From a228fd64cc6a4f92318b42d9bef4c34f32c57b3b Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sun, 7 Jan 2024 20:13:22 -0500 Subject: [PATCH] Reformat with Spotless (#8180) * Enable spotless * Run spotlessApply * Fixup trimMargin * Re-run spotlessApply --- .editorconfig | 3 +- .../testapp/PublicSuffixDatabaseTest.kt | 1 - .../okhttp/android/testapp/MainActivity.kt | 33 +- .../okhttp/android/testapp/TestApplication.kt | 3 +- .../java/okhttp/android/test/OkHttpTest.kt | 472 ++-- .../android/test/alpn/AlpnOverrideTest.kt | 50 +- .../test/letsencrypt/LetsEncryptClientTest.kt | 91 +- .../android/test/sni/SniOverrideTest.kt | 68 +- build.gradle.kts | 12 +- buildSrc/src/main/kotlin/Osgi.kt | 14 +- .../mockwebserver/DeprecationBridge.kt | 29 +- .../okhttp3/mockwebserver/MockResponse.kt | 186 +- .../okhttp3/mockwebserver/MockWebServer.kt | 85 +- .../okhttp3/mockwebserver/PushPromise.kt | 31 +- .../okhttp3/mockwebserver/RecordedRequest.kt | 26 +- .../okhttp3/mockwebserver/SocketPolicy.kt | 2 +- .../mockwebserver/KotlinSourceModernTest.kt | 66 +- .../mockwebserver/MockWebServerTest.kt | 138 +- .../junit4/MockWebServerRule.kt | 4 +- .../junit4/MockWebServerRuleTest.kt | 16 +- .../junit5/internal/MockWebServerExtension.kt | 30 +- .../junit5/internal/MockWebServerInstance.kt | 2 +- .../ExtensionMultipleInstancesTest.kt | 6 +- .../kotlin/mockwebserver3/MockResponse.kt | 221 +- .../kotlin/mockwebserver3/MockWebServer.kt | 318 ++- .../kotlin/mockwebserver3/QueueDispatcher.kt | 11 +- .../kotlin/mockwebserver3/RecordedRequest.kt | 21 +- .../kotlin/mockwebserver3/SocketPolicy.kt | 1 - .../mockwebserver3/internal/ThrottledSink.kt | 6 +- .../mockwebserver3/internal/TriggerSink.kt | 5 +- .../internal/duplex/MockStreamHandler.kt | 65 +- .../mockwebserver3/CustomDispatcherTest.kt | 29 +- .../mockwebserver3/MockResponseSniTest.kt | 122 +- .../java/mockwebserver3/MockWebServerTest.kt | 292 +- .../mockwebserver3/RecordedRequestTest.kt | 56 +- .../internal/http2/Http2Server.kt | 86 +- .../src/main/kotlin/okhttp3/DotListener.kt | 19 +- .../main/kotlin/okhttp3/GenerateClassList.kt | 46 +- .../src/main/kotlin/okhttp3/RunTests.kt | 45 +- .../src/main/kotlin/okhttp3/SampleTest.kt | 5 +- .../main/kotlin/okhttp3/TestRegistration.kt | 19 +- .../nativeImage/NativeImageTestsTest.kt | 2 +- okcurl/src/main/kotlin/okhttp3/curl/Main.kt | 62 +- .../okhttp3/curl/internal/-MainCommon.kt | 18 +- .../okhttp3/curl/logging/LoggingUtil.kt | 23 +- .../okhttp3/curl/logging/OneLineLogFormat.kt | 21 +- .../src/test/kotlin/okhttp3/curl/MainTest.kt | 37 +- .../okhttp3/android/AndroidAsyncDnsTest.kt | 59 +- .../kotlin/okhttp3/android/AndroidAsyncDns.kt | 28 +- .../android/RobolectricOkHttpClientTest.kt | 13 +- .../okhttp3/brotli/BrotliInterceptor.kt | 7 +- .../okhttp3/brotli/internal/Uncompress.kt | 15 +- .../okhttp3/brotli/BrotliInterceptorTest.kt | 68 +- .../java/okhttp3/brotli/BrotliTestMain.kt | 8 +- .../main/kotlin/okhttp3/JvmCallExtensions.kt | 35 +- .../test/kotlin/okhttp3/SuspendCallTest.kt | 6 +- .../okhttp3/dnsoverhttps/BootstrapDns.kt | 4 +- .../okhttp3/dnsoverhttps/DnsOverHttps.kt | 152 +- .../okhttp3/dnsoverhttps/DnsRecordCodec.kt | 54 +- .../okhttp3/dnsoverhttps/DnsOverHttpsTest.kt | 44 +- .../dnsoverhttps/DnsRecordCodecTest.kt | 62 +- .../java/okhttp3/dnsoverhttps/TestDohMain.kt | 75 +- .../internal/http2/HpackDecodeInteropTest.kt | 2 +- .../internal/http2/HpackDecodeTestBase.kt | 2 +- .../internal/http2/HpackRoundTripTest.kt | 2 +- .../internal/http2/hpackjson/HpackJsonUtil.kt | 44 +- .../okhttp3/internal/http2/hpackjson/Story.kt | 1 - .../idn/GenerateIdnaMappingTableCode.kt | 24 +- .../okhttp3/internal/idn/MappedRange.kt | 37 +- .../okhttp3/internal/idn/MappingTables.kt | 80 +- .../internal/idn/SimpleIdnaMappingTable.kt | 116 +- .../okhttp3/internal/idn/MappingTablesTest.kt | 98 +- .../java/net/cookiejar/JavaNetCookieJar.kt | 48 +- .../okhttp3/logging/HttpLoggingInterceptor.kt | 488 ++-- .../okhttp3/logging/LoggingEventListener.kt | 111 +- .../logging/HttpLoggingInterceptorTest.kt | 246 +- .../logging/LoggingEventListenerTest.kt | 71 +- .../main/kotlin/okhttp3/sse/EventSource.kt | 5 +- .../kotlin/okhttp3/sse/EventSourceListener.kt | 18 +- .../main/kotlin/okhttp3/sse/EventSources.kt | 5 +- .../okhttp3/sse/internal/RealEventSource.kt | 42 +- .../sse/internal/ServerSentEventReader.kt | 87 +- .../sse/internal/EventSourceHttpTest.kt | 60 +- .../sse/internal/EventSourceRecorder.kt | 13 +- .../sse/internal/EventSourcesHttpTest.kt | 22 +- .../internal/ServerSentEventIteratorTest.kt | 51 +- .../src/main/kotlin/okhttp3/CallEvent.kt | 93 +- .../kotlin/okhttp3/ClientRuleEventListener.kt | 66 +- .../main/kotlin/okhttp3/ConnectionEvent.kt | 16 +- .../kotlin/okhttp3/DelegatingSSLSession.kt | 6 +- .../kotlin/okhttp3/DelegatingSSLSocket.kt | 10 +- .../okhttp3/DelegatingSSLSocketFactory.kt | 25 +- .../okhttp3/DelegatingServerSocketFactory.kt | 11 +- .../kotlin/okhttp3/DelegatingSocketFactory.kt | 22 +- .../src/main/kotlin/okhttp3/FakeDns.kt | 11 +- .../main/kotlin/okhttp3/FakeProxySelector.kt | 2 +- .../src/main/kotlin/okhttp3/FakeSSLSession.kt | 4 +- .../kotlin/okhttp3/ForwardingRequestBody.kt | 4 +- .../kotlin/okhttp3/ForwardingResponseBody.kt | 1 + .../main/kotlin/okhttp3/JsseDebugLogging.kt | 62 +- .../kotlin/okhttp3/OkHttpClientTestRule.kt | 140 +- .../main/kotlin/okhttp3/OkHttpDebugLogging.kt | 22 +- .../okhttp3/RecordingConnectionListener.kt | 43 +- .../main/kotlin/okhttp3/RecordingCookieJar.kt | 2 +- .../kotlin/okhttp3/RecordingEventListener.kt | 92 +- .../okhttp3/RecordingHostnameVerifier.kt | 2 +- .../src/main/kotlin/okhttp3/SimpleProvider.kt | 9 +- .../okhttp3/SpecificHostSocketFactory.kt | 9 +- .../src/main/kotlin/okhttp3/TestUtilJvm.kt | 2 +- .../main/kotlin/okhttp3/TestValueFactory.kt | 46 +- .../okhttp3/UppercaseRequestInterceptor.kt | 22 +- .../okhttp3/UppercaseResponseInterceptor.kt | 6 +- .../internal/RecordingOkAuthenticator.kt | 13 +- .../okhttp3/internal/concurrent/TaskFaker.kt | 124 +- .../internal/http/RecordingProxySelector.kt | 7 +- .../Http2FlowControlConnectionListener.kt | 8 +- .../kotlin/okhttp3/okio/LoggingFilesystem.kt | 25 +- .../kotlin/okhttp3/testing/PlatformRule.kt | 677 ++--- .../okhttp3/OkHttpClientTestRuleTest.kt | 17 +- .../okhttp3/testing/PlatformRuleTest.kt | 3 +- .../main/kotlin/okhttp3/tls/Certificates.kt | 6 +- .../okhttp3/tls/HandshakeCertificates.kt | 45 +- .../kotlin/okhttp3/tls/HeldCertificate.kt | 256 +- .../internal/InsecureAndroidTrustManager.kt | 36 +- .../internal/InsecureExtendedTrustManager.kt | 23 +- .../kotlin/okhttp3/tls/internal/TlsUtil.kt | 14 +- .../okhttp3/tls/internal/der/Adapters.kt | 402 +-- .../okhttp3/tls/internal/der/AnyValue.kt | 2 +- .../tls/internal/der/BasicDerAdapter.kt | 29 +- .../okhttp3/tls/internal/der/BitString.kt | 3 +- .../okhttp3/tls/internal/der/Certificate.kt | 30 +- .../tls/internal/der/CertificateAdapters.kt | 288 +- .../okhttp3/tls/internal/der/DerAdapter.kt | 68 +- .../okhttp3/tls/internal/der/DerHeader.kt | 5 +- .../okhttp3/tls/internal/der/DerReader.kt | 79 +- .../okhttp3/tls/internal/der/DerWriter.kt | 21 +- .../test/java/okhttp3/tls/CertificatesTest.kt | 3 +- .../okhttp3/tls/HandshakeCertificatesTest.kt | 146 +- .../java/okhttp3/tls/HeldCertificateTest.kt | 220 +- .../tls/internal/der/DerCertificatesTest.kt | 1391 +++++----- .../java/okhttp3/tls/internal/der/DerTest.kt | 205 +- .../kotlin/okhttp3/JavaNetAuthenticator.kt | 6 +- .../main/kotlin/okhttp3/JavaNetCookieJar.kt | 4 +- .../src/main/kotlin/okhttp3/-JvmPlatform.kt | 1 + okhttp/src/main/kotlin/okhttp3/Address.kt | 127 +- okhttp/src/main/kotlin/okhttp3/AsyncDns.kt | 87 +- .../src/main/kotlin/okhttp3/Authenticator.kt | 11 +- okhttp/src/main/kotlin/okhttp3/Cache.kt | 135 +- .../src/main/kotlin/okhttp3/CacheControl.kt | 113 +- okhttp/src/main/kotlin/okhttp3/Callback.kt | 10 +- .../main/kotlin/okhttp3/CertificatePinner.kt | 95 +- okhttp/src/main/kotlin/okhttp3/Challenge.kt | 40 +- okhttp/src/main/kotlin/okhttp3/CipherSuite.kt | 163 +- .../main/kotlin/okhttp3/ConnectionListener.kt | 27 +- .../src/main/kotlin/okhttp3/ConnectionPool.kt | 14 +- .../src/main/kotlin/okhttp3/ConnectionSpec.kt | 213 +- okhttp/src/main/kotlin/okhttp3/Cookie.kt | 211 +- okhttp/src/main/kotlin/okhttp3/CookieJar.kt | 11 +- okhttp/src/main/kotlin/okhttp3/Credentials.kt | 5 +- okhttp/src/main/kotlin/okhttp3/Dispatcher.kt | 40 +- okhttp/src/main/kotlin/okhttp3/Dns.kt | 1 + .../src/main/kotlin/okhttp3/EventListener.kt | 89 +- .../kotlin/okhttp3/ExperimentalOkHttpApi.kt | 2 +- okhttp/src/main/kotlin/okhttp3/FormBody.kt | 99 +- okhttp/src/main/kotlin/okhttp3/Handshake.kt | 113 +- okhttp/src/main/kotlin/okhttp3/Headers.kt | 103 +- okhttp/src/main/kotlin/okhttp3/HttpUrl.kt | 309 ++- okhttp/src/main/kotlin/okhttp3/Interceptor.kt | 18 +- okhttp/src/main/kotlin/okhttp3/MediaType.kt | 32 +- .../src/main/kotlin/okhttp3/MultipartBody.kt | 151 +- .../main/kotlin/okhttp3/MultipartReader.kt | 284 +- .../src/main/kotlin/okhttp3/OkHttpClient.kt | 583 ++-- okhttp/src/main/kotlin/okhttp3/Protocol.kt | 3 +- okhttp/src/main/kotlin/okhttp3/Request.kt | 84 +- okhttp/src/main/kotlin/okhttp3/RequestBody.kt | 71 +- okhttp/src/main/kotlin/okhttp3/Response.kt | 186 +- .../src/main/kotlin/okhttp3/ResponseBody.kt | 98 +- okhttp/src/main/kotlin/okhttp3/Route.kt | 30 +- okhttp/src/main/kotlin/okhttp3/TlsVersion.kt | 14 +- okhttp/src/main/kotlin/okhttp3/WebSocket.kt | 10 +- .../main/kotlin/okhttp3/WebSocketListener.kt | 33 +- .../okhttp3/internal/-CacheControlCommon.kt | 110 +- .../okhttp3/internal/-ChallengeCommon.kt | 1 + .../kotlin/okhttp3/internal/-HeadersCommon.kt | 70 +- .../okhttp3/internal/-HostnamesCommon.kt | 34 +- .../kotlin/okhttp3/internal/-HttpUrlCommon.kt | 483 ++-- .../kotlin/okhttp3/internal/-HttpUrlJvm.kt | 26 +- .../okhttp3/internal/-MediaTypeCommon.kt | 27 +- .../kotlin/okhttp3/internal/-NormalizeJvm.kt | 4 +- .../okhttp3/internal/-RequestBodyCommon.kt | 3 +- .../kotlin/okhttp3/internal/-RequestCommon.kt | 111 +- .../okhttp3/internal/-ResponseBodyCommon.kt | 16 +- .../okhttp3/internal/-ResponseCommon.kt | 128 +- .../kotlin/okhttp3/internal/-UtilCommon.kt | 111 +- .../main/kotlin/okhttp3/internal/-UtilJvm.kt | 94 +- .../internal/NativeImageTestsAccessors.kt | 6 +- .../authenticator/JavaNetAuthenticator.kt | 43 +- .../internal/cache/CacheInterceptor.kt | 141 +- .../okhttp3/internal/cache/CacheStrategy.kt | 50 +- .../okhttp3/internal/cache/DiskLruCache.kt | 178 +- .../okhttp3/internal/cache/FaultHidingSink.kt | 7 +- .../okhttp3/internal/cache2/FileOperator.kt | 15 +- .../kotlin/okhttp3/internal/cache2/Relay.kt | 91 +- .../okhttp3/internal/concurrent/Task.kt | 2 +- .../okhttp3/internal/concurrent/TaskLogger.kt | 27 +- .../okhttp3/internal/concurrent/TaskQueue.kt | 52 +- .../okhttp3/internal/concurrent/TaskRunner.kt | 91 +- .../internal/connection/ConnectPlan.kt | 166 +- .../okhttp3/internal/connection/Exchange.kt | 26 +- .../connection/FastFallbackExchangeFinder.kt | 51 +- .../okhttp3/internal/connection/RealCall.kt | 86 +- .../internal/connection/RealConnection.kt | 85 +- .../internal/connection/RealConnectionPool.kt | 72 +- .../internal/connection/RealRoutePlanner.kt | 116 +- .../okhttp3/internal/connection/ReusePlan.kt | 1 - .../internal/connection/RouteDatabase.kt | 1 - .../internal/connection/RouteSelector.kt | 48 +- .../connection/SequentialExchangeFinder.kt | 11 +- .../okhttp3/internal/graal/OkHttpFeature.kt | 2 +- .../internal/http/BridgeInterceptor.kt | 25 +- .../internal/http/CallServerInterceptor.kt | 50 +- .../okhttp3/internal/http/DateFormatting.kt | 80 +- .../okhttp3/internal/http/ExchangeCodec.kt | 13 +- .../okhttp3/internal/http/HttpHeaders.kt | 37 +- .../okhttp3/internal/http/HttpMethod.kt | 15 +- .../internal/http/RealInterceptorChain.kt | 38 +- .../okhttp3/internal/http/RealResponseBody.kt | 3 +- .../okhttp3/internal/http/RequestLine.kt | 28 +- .../http/RetryAndFollowUpInterceptor.kt | 42 +- .../okhttp3/internal/http/StatusLine.kt | 16 +- .../internal/http1/Http1ExchangeCodec.kt | 84 +- .../okhttp3/internal/http2/ErrorCode.kt | 3 +- .../internal/http2/FlowControlListener.kt | 14 +- .../kotlin/okhttp3/internal/http2/Header.kt | 6 +- .../kotlin/okhttp3/internal/http2/Hpack.kt | 828 +++--- .../kotlin/okhttp3/internal/http2/Http2.kt | 46 +- .../okhttp3/internal/http2/Http2Connection.kt | 202 +- .../internal/http2/Http2ExchangeCodec.kt | 48 +- .../okhttp3/internal/http2/Http2Reader.kt | 160 +- .../okhttp3/internal/http2/Http2Stream.kt | 81 +- .../okhttp3/internal/http2/Http2Writer.kt | 195 +- .../kotlin/okhttp3/internal/http2/Huffman.kt | 98 +- .../okhttp3/internal/http2/PushObserver.kt | 48 +- .../kotlin/okhttp3/internal/http2/Settings.kt | 11 +- .../internal/http2/StreamResetException.kt | 4 +- .../http2/flowcontrol/WindowCounter.kt | 7 +- .../okhttp3/internal/idn/IdnaMappingTable.kt | 40 +- .../kotlin/okhttp3/internal/idn/Punycode.kt | 100 +- .../main/kotlin/okhttp3/internal/internal.kt | 48 +- .../internal/platform/Android10Platform.kt | 32 +- .../internal/platform/AndroidPlatform.kt | 87 +- .../internal/platform/BouncyCastlePlatform.kt | 48 +- .../internal/platform/ConscryptPlatform.kt | 60 +- .../platform/Jdk8WithJettyBootPlatform.kt | 31 +- .../okhttp3/internal/platform/Jdk9Platform.kt | 26 +- .../internal/platform/OpenJSSEPlatform.kt | 48 +- .../okhttp3/internal/platform/Platform.kt | 49 +- .../android/Android10SocketAdapter.kt | 7 +- .../android/AndroidCertificateChainCleaner.kt | 25 +- .../internal/platform/android/AndroidLog.kt | 57 +- .../platform/android/AndroidSocketAdapter.kt | 11 +- .../android/BouncyCastleSocketAdapter.kt | 14 +- .../android/ConscryptSocketAdapter.kt | 22 +- .../platform/android/DeferredSocketAdapter.kt | 6 +- .../platform/android/SocketAdapter.kt | 5 +- .../android/StandardAndroidSocketAdapter.kt | 34 +- .../internal/proxy/NullProxySelector.kt | 6 +- .../publicsuffix/PublicSuffixDatabase.kt | 29 +- .../tls/BasicCertificateChainCleaner.kt | 11 +- .../internal/tls/BasicTrustRootIndex.kt | 2 +- .../internal/tls/CertificateChainCleaner.kt | 6 +- .../internal/tls/OkHostnameVerifier.kt | 50 +- .../okhttp3/internal/ws/MessageDeflater.kt | 13 +- .../okhttp3/internal/ws/MessageInflater.kt | 11 +- .../okhttp3/internal/ws/RealWebSocket.kt | 173 +- .../internal/ws/WebSocketExtensions.kt | 31 +- .../okhttp3/internal/ws/WebSocketProtocol.kt | 18 +- .../okhttp3/internal/ws/WebSocketReader.kt | 40 +- .../okhttp3/internal/ws/WebSocketWriter.kt | 33 +- .../okhttp3/internal/-InternalVersion.kt | 1 + okhttp/src/test/java/okhttp3/AddressTest.kt | 9 +- .../src/test/java/okhttp3/AutobahnTester.kt | 160 +- .../src/test/java/okhttp3/BouncyCastleTest.kt | 7 +- .../test/java/okhttp3/CacheControlJvmTest.kt | 101 +- .../src/test/java/okhttp3/CacheControlTest.kt | 23 +- .../test/java/okhttp3/CacheCorruptionTest.kt | 100 +- okhttp/src/test/java/okhttp3/CacheTest.kt | 1330 +++++---- .../test/java/okhttp3/CallHandshakeTest.kt | 59 +- .../src/test/java/okhttp3/CallKotlinTest.kt | 75 +- okhttp/src/test/java/okhttp3/CallTest.kt | 2448 ++++++++++------- .../okhttp3/CertificateChainCleanerTest.kt | 315 ++- .../okhttp3/CertificatePinnerKotlinTest.kt | 67 +- .../java/okhttp3/CertificatePinnerTest.kt | 174 +- .../test/java/okhttp3/ChannelSocketFactory.kt | 17 +- .../src/test/java/okhttp3/CipherSuiteTest.kt | 50 +- .../java/okhttp3/ConnectionCoalescingTest.kt | 344 ++- .../java/okhttp3/ConnectionListenerTest.kt | 152 +- .../test/java/okhttp3/ConnectionReuseTest.kt | 124 +- .../test/java/okhttp3/ConnectionSpecTest.kt | 291 +- okhttp/src/test/java/okhttp3/ConscryptTest.kt | 7 +- okhttp/src/test/java/okhttp3/CookieTest.kt | 236 +- okhttp/src/test/java/okhttp3/CookiesTest.kt | 189 +- okhttp/src/test/java/okhttp3/CorrettoTest.kt | 7 +- .../java/okhttp3/DispatcherCleanupTest.kt | 18 +- .../src/test/java/okhttp3/DispatcherTest.kt | 85 +- okhttp/src/test/java/okhttp3/DuplexTest.kt | 519 ++-- .../test/java/okhttp3/EventListenerTest.kt | 1107 ++++---- .../src/test/java/okhttp3/FakeRoutePlanner.kt | 2 +- .../FallbackTestClientSocketFactory.kt | 5 +- .../src/test/java/okhttp3/FastFallbackTest.kt | 156 +- okhttp/src/test/java/okhttp3/FormBodyTest.kt | 56 +- okhttp/src/test/java/okhttp3/HandshakeTest.kt | 54 +- .../java/okhttp3/HeadersChallengesTest.kt | 319 ++- .../src/test/java/okhttp3/HeadersJvmTest.kt | 101 +- .../test/java/okhttp3/HeadersRequestTest.kt | 72 +- okhttp/src/test/java/okhttp3/HeadersTest.kt | 97 +- .../src/test/java/okhttp3/HttpUrlJvmTest.kt | 91 +- okhttp/src/test/java/okhttp3/HttpUrlTest.kt | 419 +-- .../test/java/okhttp3/InsecureForHostTest.kt | 31 +- .../src/test/java/okhttp3/InterceptorTest.kt | 669 +++-- okhttp/src/test/java/okhttp3/JSSETest.kt | 78 +- .../okhttp3/KotlinDeprecationErrorTest.kt | 10 +- .../java/okhttp3/KotlinSourceModernTest.kt | 428 ++- okhttp/src/test/java/okhttp3/LoomTest.kt | 12 +- .../src/test/java/okhttp3/MediaTypeGetTest.kt | 12 +- .../src/test/java/okhttp3/MediaTypeJvmTest.kt | 19 +- okhttp/src/test/java/okhttp3/MediaTypeTest.kt | 30 +- .../test/java/okhttp3/MultipartBodyTest.kt | 164 +- .../test/java/okhttp3/MultipartReaderTest.kt | 510 ++-- .../src/test/java/okhttp3/OkHttpClientTest.kt | 170 +- okhttp/src/test/java/okhttp3/OpenJSSETest.kt | 19 +- .../java/okhttp3/PublicInternalApiTest.kt | 11 +- .../src/test/java/okhttp3/RecordedResponse.kt | 159 +- .../test/java/okhttp3/RecordingCallback.kt | 10 +- .../test/java/okhttp3/RecordingExecutor.kt | 7 +- .../src/test/java/okhttp3/RequestBodyTest.kt | 14 +- .../test/java/okhttp3/RequestCommonTest.kt | 202 +- okhttp/src/test/java/okhttp3/RequestTest.kt | 213 +- .../test/java/okhttp3/ResponseBodyJvmTest.kt | 348 +-- .../src/test/java/okhttp3/ResponseBodyTest.kt | 81 +- .../test/java/okhttp3/ResponseCommonTest.kt | 57 +- .../src/test/java/okhttp3/ResponseJvmTest.kt | 51 +- .../src/test/java/okhttp3/RouteFailureTest.kt | 132 +- .../okhttp3/ServerTruncatesRequestTest.kt | 124 +- .../src/test/java/okhttp3/SessionReuseTest.kt | 68 +- .../test/java/okhttp3/SocketChannelTest.kt | 179 +- okhttp/src/test/java/okhttp3/SocksProxy.kt | 42 +- .../src/test/java/okhttp3/SocksProxyTest.kt | 47 +- .../src/test/java/okhttp3/TestLogHandler.kt | 17 +- .../src/test/java/okhttp3/TestTls13Request.kt | 87 +- .../test/java/okhttp3/URLConnectionTest.kt | 1907 +++++++------ .../okhttp3/UrlComponentEncodingTester.kt | 229 +- .../okhttp3/UrlComponentEncodingTesterJvm.kt | 151 +- .../java/okhttp3/WebPlatformToAsciiTest.kt | 68 +- .../test/java/okhttp3/WebPlatformUrlTest.kt | 81 +- .../java/okhttp3/WebPlatformUrlTestData.kt | 14 +- .../java/okhttp3/WholeOperationTimeoutTest.kt | 211 +- .../java/okhttp3/internal/HostnamesTest.kt | 61 +- .../internal/RecordingAuthenticator.kt | 16 +- .../test/java/okhttp3/internal/UtilTest.kt | 104 +- .../authenticator/JavaNetAuthenticatorTest.kt | 24 +- .../internal/cache/DiskLruCacheTest.kt | 147 +- .../internal/cache2/FileOperatorTest.kt | 81 +- .../java/okhttp3/internal/cache2/RelayTest.kt | 7 +- .../internal/concurrent/TaskLoggerTest.kt | 3 +- .../concurrent/TaskRunnerRealBackendTest.kt | 18 +- .../internal/concurrent/TaskRunnerTest.kt | 352 +-- .../internal/connection/ConnectionPoolTest.kt | 35 +- .../FastFallbackExchangeFinderTest.kt | 7 +- .../connection/InetAddressOrderTest.kt | 41 +- .../connection/RetryConnectionTest.kt | 38 +- .../internal/connection/RouteSelectorTest.kt | 184 +- .../java/okhttp3/internal/http/CancelTest.kt | 136 +- .../internal/http/ExternalHttp2Example.kt | 16 +- .../okhttp3/internal/http/HttpDateTest.kt | 16 +- .../okhttp3/internal/http/StatusLineTest.kt | 3 +- .../internal/http/ThreadInterruptTest.kt | 97 +- .../okhttp3/internal/http2/BaseTestHandler.kt | 2 +- .../okhttp3/internal/http2/FrameLogTest.kt | 2 +- .../java/okhttp3/internal/http2/HpackTest.kt | 165 +- .../internal/http2/Http2ConnectionTest.kt | 197 +- .../java/okhttp3/internal/http2/Http2Test.kt | 382 ++- .../internal/http2/HttpOverHttp2Test.kt | 1436 ++++++---- .../okhttp3/internal/http2/MockHttp2Peer.kt | 63 +- .../okhttp3/internal/http2/SettingsTest.kt | 2 +- .../okhttp3/internal/idn/IdnStringprep.kt | 2 - .../internal/idn/IdnaMappingTableTest.kt | 27 +- .../java/okhttp3/internal/idn/PunycodeTest.kt | 46 +- .../okhttp3/internal/idn/StringprepReader.kt | 118 +- .../idn/StringprepTablesReaderTest.kt | 17 +- .../okhttp3/internal/idn/StringprepTest.kt | 15 +- .../okhttp3/internal/io/FaultyFileSystem.kt | 47 +- .../internal/platform/Jdk9PlatformTest.kt | 9 +- .../android/AndroidSocketAdapterTest.kt | 11 +- .../publicsuffix/PublicSuffixDatabaseTest.kt | 102 +- .../publicsuffix/PublicSuffixListGenerator.kt | 67 +- .../CertificatePinnerChainValidationTest.kt | 733 ++--- .../okhttp3/internal/tls/ClientAuthTest.kt | 181 +- .../internal/tls/HostnameVerifierTest.kt | 800 +++--- .../okhttp3/internal/ws/RealWebSocketTest.kt | 42 +- .../internal/ws/WebSocketExtensionsTest.kt | 212 +- .../okhttp3/internal/ws/WebSocketHttpTest.kt | 468 ++-- .../internal/ws/WebSocketReaderTest.kt | 65 +- .../okhttp3/internal/ws/WebSocketRecorder.kt | 100 +- .../internal/ws/WebSocketWriterTest.kt | 94 +- okhttp/src/test/java/okhttp3/osgi/OsgiTest.kt | 47 +- .../compare/ApacheHttpClientHttp2Test.kt | 2 +- .../compare/ApacheHttpClientTest.kt | 2 +- .../okhttp3/compare/ApacheHttpClientTest.kt | 14 +- .../okhttp3/compare/JavaHttpClientTest.kt | 37 +- .../okhttp3/compare/JettyHttpClientTest.kt | 11 +- .../okhttp3/compare/OkHttpClientTest.kt | 14 +- .../java/okhttp3/recipes/kt/AccessHeaders.kt | 3 +- .../okhttp3/recipes/kt/AsynchronousGet.kt | 37 +- .../java/okhttp3/recipes/kt/Authenticate.kt | 35 +- .../java/okhttp3/recipes/kt/CacheResponse.kt | 44 +- .../java/okhttp3/recipes/kt/CancelCall.kt | 17 +- .../okhttp3/recipes/kt/CertificatePinning.kt | 13 +- .../okhttp3/recipes/kt/ConfigureTimeouts.kt | 6 +- .../java/okhttp3/recipes/kt/CustomTrust.kt | 48 +- .../main/java/okhttp3/recipes/kt/DevServer.kt | 21 +- .../recipes/kt/ParseResponseWithMoshi.kt | 3 +- .../okhttp3/recipes/kt/PerCallSettings.kt | 9 +- .../main/java/okhttp3/recipes/kt/PostFile.kt | 9 +- .../main/java/okhttp3/recipes/kt/PostForm.kt | 12 +- .../java/okhttp3/recipes/kt/PostMultipart.kt | 13 +- .../main/java/okhttp3/recipes/kt/PostPath.kt | 3 +- .../java/okhttp3/recipes/kt/PostStreaming.kt | 38 +- .../java/okhttp3/recipes/kt/PostString.kt | 29 +- .../java/okhttp3/recipes/kt/SynchronousGet.kt | 3 +- .../okhttp3/recipes/kt/WiresharkExample.kt | 179 +- .../okhttp3/recipes/kt/YubikeyClientAuth.kt | 19 +- .../src/test/kotlin/okhttp3/AllMainsTest.kt | 20 +- .../okhttp3/survey/CipherSuiteSurvey.kt | 12 +- .../src/main/kotlin/okhttp3/survey/Clients.kt | 51 +- .../src/main/kotlin/okhttp3/survey/Iana.kt | 16 +- .../main/kotlin/okhttp3/survey/RunSurvey.kt | 65 +- .../okhttp3/survey/ssllabs/SslLabsScrape.kt | 12 +- .../okhttp3/survey/ssllabs/SslLabsService.kt | 10 +- .../survey/ssllabs/UserAgentCapabilities.kt | 59 +- .../kotlin/okhttp3/survey/types/Client.kt | 2 +- .../kotlin/okhttp3/survey/types/Record.kt | 1 - 442 files changed, 24924 insertions(+), 18474 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6531d6787d2f..d42d6bc773e2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,9 +2,10 @@ root = true [*] indent_size = 2 +ij_continuation_indent_size = 2 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.{kt, kts}] -kotlin_imports_layout = ascii +ij_kotlin_imports_layout = * diff --git a/android-test-app/src/androidTest/kotlin/okhttp/android/testapp/PublicSuffixDatabaseTest.kt b/android-test-app/src/androidTest/kotlin/okhttp/android/testapp/PublicSuffixDatabaseTest.kt index f7debc9d345e..5580f5dd332a 100644 --- a/android-test-app/src/androidTest/kotlin/okhttp/android/testapp/PublicSuffixDatabaseTest.kt +++ b/android-test-app/src/androidTest/kotlin/okhttp/android/testapp/PublicSuffixDatabaseTest.kt @@ -24,7 +24,6 @@ import org.junit.Test * Run with "./gradlew :android-test-app:connectedCheck -PandroidBuild=true" and make sure ANDROID_SDK_ROOT is set. */ class PublicSuffixDatabaseTest { - @Test fun testTopLevelDomain() { assertThat("https://www.google.com/robots.txt".toHttpUrl().topPrivateDomain()).isEqualTo("google.com") diff --git a/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt b/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt index 7517b0ab05f2..d9ed518156ff 100644 --- a/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt +++ b/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt @@ -19,20 +19,13 @@ import android.os.Bundle import androidx.activity.ComponentActivity import okhttp3.Call import okhttp3.Callback -import okhttp3.CookieJar import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response -import okhttp3.internal.publicsuffix.PublicSuffixDatabase -import okio.FileSystem import okio.IOException -import okio.Path.Companion.toPath -import java.net.CookieHandler -import java.net.URI class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -41,15 +34,23 @@ class MainActivity : ComponentActivity() { val url = "https://github.com/square/okhttp".toHttpUrl() println(url.topPrivateDomain()) - client.newCall(Request(url)).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - println("failed: $e") - } + client.newCall(Request(url)).enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + println("failed: $e") + } - override fun onResponse(call: Call, response: Response) { - println("response: ${response.code}") - response.close() - } - }) + override fun onResponse( + call: Call, + response: Response, + ) { + println("response: ${response.code}") + response.close() + } + }, + ) } } diff --git a/android-test-app/src/main/kotlin/okhttp/android/testapp/TestApplication.kt b/android-test-app/src/main/kotlin/okhttp/android/testapp/TestApplication.kt index bd6bef4f68c1..481aa6f08488 100644 --- a/android-test-app/src/main/kotlin/okhttp/android/testapp/TestApplication.kt +++ b/android-test-app/src/main/kotlin/okhttp/android/testapp/TestApplication.kt @@ -17,5 +17,4 @@ package okhttp.android.testapp import android.app.Application -class TestApplication: Application() { -} +class TestApplication : Application() diff --git a/android-test/src/androidTest/java/okhttp/android/test/OkHttpTest.kt b/android-test/src/androidTest/java/okhttp/android/test/OkHttpTest.kt index 789c624aff3a..eaf37eb90864 100644 --- a/android-test/src/androidTest/java/okhttp/android/test/OkHttpTest.kt +++ b/android-test/src/androidTest/java/okhttp/android/test/OkHttpTest.kt @@ -21,6 +21,25 @@ import com.google.android.gms.common.GooglePlayServicesNotAvailableException import com.google.android.gms.security.ProviderInstaller import com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import java.io.IOException +import java.net.InetAddress +import java.net.UnknownHostException +import java.security.KeyStore +import java.security.SecureRandom +import java.security.Security +import java.security.cert.Certificate +import java.security.cert.CertificateException +import java.security.cert.X509Certificate +import java.util.concurrent.atomic.AtomicInteger +import java.util.logging.Handler +import java.util.logging.Level +import java.util.logging.LogRecord +import java.util.logging.Logger +import javax.net.ssl.HostnameVerifier +import javax.net.ssl.SSLPeerUnverifiedException +import javax.net.ssl.SSLSocket +import javax.net.ssl.TrustManagerFactory +import javax.net.ssl.X509TrustManager import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import mockwebserver3.junit5.internal.MockWebServerExtension @@ -31,6 +50,7 @@ import okhttp3.Connection import okhttp3.DelegatingSSLSocket import okhttp3.DelegatingSSLSocketFactory import okhttp3.EventListener +import okhttp3.Headers import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.OkHttpClientTestRule @@ -59,33 +79,13 @@ import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Assertions.fail import org.junit.jupiter.api.Assumptions.assumeTrue +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.RegisterExtension import org.opentest4j.TestAbortedException -import java.io.IOException -import java.net.InetAddress -import java.net.UnknownHostException -import java.security.KeyStore -import java.security.SecureRandom -import java.security.Security -import java.security.cert.Certificate -import java.security.cert.CertificateException -import java.security.cert.X509Certificate -import java.util.concurrent.atomic.AtomicInteger -import java.util.logging.Handler -import java.util.logging.Level -import java.util.logging.LogRecord -import java.util.logging.Logger -import javax.net.ssl.HostnameVerifier -import javax.net.ssl.SSLPeerUnverifiedException -import javax.net.ssl.SSLSocket -import javax.net.ssl.TrustManagerFactory -import javax.net.ssl.X509TrustManager -import okhttp3.Headers -import org.junit.jupiter.api.BeforeEach /** * Run with "./gradlew :android-test:connectedCheck -PandroidBuild=true" and make sure ANDROID_SDK_ROOT is set. @@ -93,22 +93,25 @@ import org.junit.jupiter.api.BeforeEach @ExtendWith(MockWebServerExtension::class) @Tag("Slow") class OkHttpTest { - @Suppress("RedundantVisibilityModifier") @JvmField - @RegisterExtension public val platform = PlatformRule() + @RegisterExtension + public val platform = PlatformRule() @Suppress("RedundantVisibilityModifier") @JvmField - @RegisterExtension public val clientTestRule = OkHttpClientTestRule().apply { - logger = Logger.getLogger(OkHttpTest::class.java.name) - } + @RegisterExtension + public val clientTestRule = + OkHttpClientTestRule().apply { + logger = Logger.getLogger(OkHttpTest::class.java.name) + } private var client: OkHttpClient = clientTestRule.newClient() - private val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + private val moshi = + Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() private val handshakeCertificates = localhost() @@ -136,18 +139,20 @@ class OkHttpTest { val request = Request.Builder().url("https://api.twitter.com/robots.txt").build() - val clientCertificates = HandshakeCertificates.Builder() - .addPlatformTrustedCertificates() - .apply { - if (Build.VERSION.SDK_INT >= 24) { - addInsecureHost(server.hostName) + val clientCertificates = + HandshakeCertificates.Builder() + .addPlatformTrustedCertificates() + .apply { + if (Build.VERSION.SDK_INT >= 24) { + addInsecureHost(server.hostName) + } } - } - .build() + .build() - client = client.newBuilder() - .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) - .build() + client = + client.newBuilder() + .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) + .build() val response = client.newCall(request).execute() @@ -184,22 +189,29 @@ class OkHttpTest { var socketClass: String? = null - val clientCertificates = HandshakeCertificates.Builder() - .addPlatformTrustedCertificates() - .addInsecureHost(server.hostName) - .build() + val clientCertificates = + HandshakeCertificates.Builder() + .addPlatformTrustedCertificates() + .addInsecureHost(server.hostName) + .build() // Need fresh client to reset sslSocketFactoryOrNull - client = OkHttpClient.Builder() - .eventListenerFactory( - clientTestRule.wrap(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - socketClass = connection.socket().javaClass.name - } - }) - ) - .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) - .build() + client = + OkHttpClient.Builder() + .eventListenerFactory( + clientTestRule.wrap( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + socketClass = connection.socket().javaClass.name + } + }, + ), + ) + .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) + .build() val response = client.newCall(request).execute() @@ -240,26 +252,33 @@ class OkHttpTest { throw TestAbortedException("Google Play Services not available", gpsnae) } - val clientCertificates = HandshakeCertificates.Builder() - .addPlatformTrustedCertificates() - .addInsecureHost(server.hostName) - .build() + val clientCertificates = + HandshakeCertificates.Builder() + .addPlatformTrustedCertificates() + .addInsecureHost(server.hostName) + .build() val request = Request.Builder().url("https://facebook.com/robots.txt").build() var socketClass: String? = null // Need fresh client to reset sslSocketFactoryOrNull - client = OkHttpClient.Builder() - .eventListenerFactory( - clientTestRule.wrap(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - socketClass = connection.socket().javaClass.name - } - }) - ) - .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) - .build() + client = + OkHttpClient.Builder() + .eventListenerFactory( + clientTestRule.wrap( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + socketClass = connection.socket().javaClass.name + } + }, + ), + ) + .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) + .build() val response = client.newCall(request).execute() @@ -298,24 +317,31 @@ class OkHttpTest { var socketClass: String? = null - val clientCertificates = HandshakeCertificates.Builder() - .addPlatformTrustedCertificates().apply { - if (Build.VERSION.SDK_INT >= 24) { - addInsecureHost(server.hostName) + val clientCertificates = + HandshakeCertificates.Builder() + .addPlatformTrustedCertificates().apply { + if (Build.VERSION.SDK_INT >= 24) { + addInsecureHost(server.hostName) + } } - } - .build() + .build() - client = client.newBuilder() - .eventListenerFactory( - clientTestRule.wrap(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - socketClass = connection.socket().javaClass.name - } - }) - ) - .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) - .build() + client = + client.newBuilder() + .eventListenerFactory( + clientTestRule.wrap( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + socketClass = connection.socket().javaClass.name + } + }, + ), + ) + .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) + .build() val response = client.newCall(request).execute() @@ -372,7 +398,7 @@ class OkHttpTest { val tls_version: String, val able_to_detect_n_minus_one_splitting: Boolean, val insecure_cipher_suites: Map>, - val given_cipher_suites: List? + val given_cipher_suites: List?, ) @Test @@ -384,9 +410,10 @@ class OkHttpTest { val response = client.newCall(request).execute() - val results = response.use { - moshi.adapter(HowsMySslResults::class.java).fromJson(response.body.string())!! - } + val results = + response.use { + moshi.adapter(HowsMySslResults::class.java).fromJson(response.body.string())!! + } Platform.get().log("results $results", Platform.WARN) @@ -417,7 +444,7 @@ class OkHttpTest { assertTrue(tlsVersion == TlsVersion.TLS_1_2 || tlsVersion == TlsVersion.TLS_1_3) assertEquals( "CN=localhost", - (response.handshake!!.peerCertificates.first() as X509Certificate).subjectDN.name + (response.handshake!!.peerCertificates.first() as X509Certificate).subjectDN.name, ) } } @@ -426,9 +453,10 @@ class OkHttpTest { fun testCertificatePinningFailure() { enableTls() - val certificatePinner = CertificatePinner.Builder() - .add(server.hostName, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") - .build() + val certificatePinner = + CertificatePinner.Builder() + .add(server.hostName, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") + .build() client = client.newBuilder().certificatePinner(certificatePinner).build() server.enqueue(MockResponse(body = "abc")) @@ -446,12 +474,13 @@ class OkHttpTest { fun testCertificatePinningSuccess() { enableTls() - val certificatePinner = CertificatePinner.Builder() - .add( - server.hostName, - CertificatePinner.pin(handshakeCertificates.trustManager.acceptedIssuers[0]) - ) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add( + server.hostName, + CertificatePinner.pin(handshakeCertificates.trustManager.acceptedIssuers[0]), + ) + .build() client = client.newBuilder().certificatePinner(certificatePinner).build() server.enqueue(MockResponse(body = "abc")) @@ -488,9 +517,9 @@ class OkHttpTest { "ConnectStart", "SecureConnectStart", "SecureConnectEnd", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", - "CallEnd" + "CallEnd", ), - eventListener.recordedEventTypes() + eventListener.recordedEventTypes(), ) eventListener.clearAllEvents() @@ -504,9 +533,9 @@ class OkHttpTest { "CallStart", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", - "CallEnd" + "CallEnd", ), - eventListener.recordedEventTypes() + eventListener.recordedEventTypes(), ) } @@ -516,15 +545,21 @@ class OkHttpTest { enableTls() - client = client.newBuilder().eventListenerFactory( - clientTestRule.wrap(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - val sslSocket = connection.socket() as SSLSocket - - sessionIds.add(sslSocket.session.id.toByteString().hex()) - } - }) - ).build() + client = + client.newBuilder().eventListenerFactory( + clientTestRule.wrap( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + val sslSocket = connection.socket() as SSLSocket + + sessionIds.add(sslSocket.session.id.toByteString().hex()) + } + }, + ), + ).build() server.enqueue(MockResponse(body = "abc1")) server.enqueue(MockResponse(body = "abc2")) @@ -550,9 +585,10 @@ class OkHttpTest { fun testDnsOverHttps() { assumeNetwork() - client = client.newBuilder() - .eventListenerFactory(clientTestRule.wrap(LoggingEventListener.Factory())) - .build() + client = + client.newBuilder() + .eventListenerFactory(clientTestRule.wrap(LoggingEventListener.Factory())) + .build() val dohDns = buildCloudflareIp(client) val dohEnabledClient = @@ -566,25 +602,34 @@ class OkHttpTest { fun testCustomTrustManager() { assumeNetwork() - val trustManager = object : X509TrustManager { - override fun checkClientTrusted(chain: Array?, authType: String?) {} + val trustManager = + object : X509TrustManager { + override fun checkClientTrusted( + chain: Array?, + authType: String?, + ) {} - override fun checkServerTrusted(chain: Array?, authType: String?) {} + override fun checkServerTrusted( + chain: Array?, + authType: String?, + ) {} - override fun getAcceptedIssuers(): Array = arrayOf() - } + override fun getAcceptedIssuers(): Array = arrayOf() + } - val sslContext = Platform.get().newSSLContext().apply { - init(null, arrayOf(trustManager), null) - } + val sslContext = + Platform.get().newSSLContext().apply { + init(null, arrayOf(trustManager), null) + } val sslSocketFactory = sslContext.socketFactory val hostnameVerifier = HostnameVerifier { _, _ -> true } - client = client.newBuilder() - .sslSocketFactory(sslSocketFactory, trustManager) - .hostnameVerifier(hostnameVerifier) - .build() + client = + client.newBuilder() + .sslSocketFactory(sslSocketFactory, trustManager) + .hostnameVerifier(hostnameVerifier) + .build() client.get("https://www.facebook.com/robots.txt") } @@ -598,19 +643,21 @@ class OkHttpTest { val sslSocketFactory = client.sslSocketFactory val trustManager = client.x509TrustManager!! - val delegatingSocketFactory = object : DelegatingSSLSocketFactory(sslSocketFactory) { - override fun configureSocket(sslSocket: SSLSocket): SSLSocket { - return object : DelegatingSSLSocket(sslSocket) { - override fun getApplicationProtocol(): String { - throw UnsupportedOperationException() + val delegatingSocketFactory = + object : DelegatingSSLSocketFactory(sslSocketFactory) { + override fun configureSocket(sslSocket: SSLSocket): SSLSocket { + return object : DelegatingSSLSocket(sslSocket) { + override fun getApplicationProtocol(): String { + throw UnsupportedOperationException() + } } } } - } - client = client.newBuilder() - .sslSocketFactory(delegatingSocketFactory, trustManager) - .build() + client = + client.newBuilder() + .sslSocketFactory(delegatingSocketFactory, trustManager) + .build() val request = Request.Builder().url(server.url("/").toString()).build() val response = client.newCall(request).execute() @@ -626,34 +673,47 @@ class OkHttpTest { var withHostCalled = false var withoutHostCalled = false - val trustManager = object : X509TrustManager { - override fun checkClientTrusted(chain: Array?, authType: String?) {} + val trustManager = + object : X509TrustManager { + override fun checkClientTrusted( + chain: Array?, + authType: String?, + ) {} + + override fun checkServerTrusted( + chain: Array?, + authType: String?, + ) { + withoutHostCalled = true + } - override fun checkServerTrusted(chain: Array?, authType: String?) { - withoutHostCalled = true - } + // called by Android via reflection in X509TrustManagerExtensions + @Suppress("unused", "UNUSED_PARAMETER") + fun checkServerTrusted( + chain: Array, + authType: String, + hostname: String, + ): List { + withHostCalled = true + return chain.toList() + } - @Suppress("unused", "UNUSED_PARAMETER") - // called by Android via reflection in X509TrustManagerExtensions - fun checkServerTrusted(chain: Array, authType: String, hostname: String): List { - withHostCalled = true - return chain.toList() + override fun getAcceptedIssuers(): Array = arrayOf() } - override fun getAcceptedIssuers(): Array = arrayOf() - } - - val sslContext = Platform.get().newSSLContext().apply { - init(null, arrayOf(trustManager), null) - } + val sslContext = + Platform.get().newSSLContext().apply { + init(null, arrayOf(trustManager), null) + } val sslSocketFactory = sslContext.socketFactory val hostnameVerifier = HostnameVerifier { _, _ -> true } - client = client.newBuilder() - .sslSocketFactory(sslSocketFactory, trustManager) - .hostnameVerifier(hostnameVerifier) - .build() + client = + client.newBuilder() + .sslSocketFactory(sslSocketFactory, trustManager) + .hostnameVerifier(hostnameVerifier) + .build() client.get("https://www.facebook.com/robots.txt") @@ -702,25 +762,33 @@ class OkHttpTest { var socketClass: String? = null - val trustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply { - init(null as KeyStore?) - }.trustManagers.first() as X509TrustManager + val trustManager = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply { + init(null as KeyStore?) + }.trustManagers.first() as X509TrustManager - val sslContext = Platform.get().newSSLContext().apply { - // TODO remove most of this code after https://github.com/bcgit/bc-java/issues/686 - init(null, arrayOf(trustManager), SecureRandom()) - } + val sslContext = + Platform.get().newSSLContext().apply { + // TODO remove most of this code after https://github.com/bcgit/bc-java/issues/686 + init(null, arrayOf(trustManager), SecureRandom()) + } - client = client.newBuilder() - .sslSocketFactory(sslContext.socketFactory, trustManager) - .eventListenerFactory( - clientTestRule.wrap(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - socketClass = connection.socket().javaClass.name - } - }) - ) - .build() + client = + client.newBuilder() + .sslSocketFactory(sslContext.socketFactory, trustManager) + .eventListenerFactory( + clientTestRule.wrap( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + socketClass = connection.socket().javaClass.name + } + }, + ), + ) + .build() val request = Request.Builder().url("https://facebook.com/robots.txt").build() @@ -743,22 +811,23 @@ class OkHttpTest { fun testLoggingLevels() { enableTls() - val testHandler = object : Handler() { - val calls = mutableMapOf() + val testHandler = + object : Handler() { + val calls = mutableMapOf() - override fun publish(record: LogRecord) { - calls.getOrPut(record.loggerName) { AtomicInteger(0) } - .incrementAndGet() - } + override fun publish(record: LogRecord) { + calls.getOrPut(record.loggerName) { AtomicInteger(0) } + .incrementAndGet() + } - override fun flush() { - } + override fun flush() { + } - override fun close() { + override fun close() { + } + }.apply { + level = Level.FINEST } - }.apply { - level = Level.FINEST - } Logger.getLogger("") .addHandler(testHandler) @@ -773,12 +842,14 @@ class OkHttpTest { server.enqueue(MockResponse(body = "abc")) - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() - val response = client.newCall(request) - .execute() + val response = + client.newCall(request) + .execute() response.use { assertEquals(200, response.code) @@ -802,13 +873,15 @@ class OkHttpTest { val cache = Cache(ctxt.cacheDir.resolve("testCache"), cacheSize) try { - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() client.newCall(request) .execute() @@ -853,11 +926,12 @@ class OkHttpTest { } private fun enableTls() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } diff --git a/android-test/src/androidTest/java/okhttp/android/test/alpn/AlpnOverrideTest.kt b/android-test/src/androidTest/java/okhttp/android/test/alpn/AlpnOverrideTest.kt index 8bb47256b00b..accc65679684 100644 --- a/android-test/src/androidTest/java/okhttp/android/test/alpn/AlpnOverrideTest.kt +++ b/android-test/src/androidTest/java/okhttp/android/test/alpn/AlpnOverrideTest.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp.android.test.alpn; +package okhttp.android.test.alpn import android.os.Build import android.util.Log @@ -36,9 +36,8 @@ import org.junit.jupiter.api.Test */ @Tag("Remote") class AlpnOverrideTest { - class CustomSSLSocketFactory( - delegate: SSLSocketFactory + delegate: SSLSocketFactory, ) : DelegatingSSLSocketFactory(delegate) { override fun configureSocket(sslSocket: SSLSocket): SSLSocket { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { @@ -56,25 +55,34 @@ class AlpnOverrideTest { @Test fun getWithCustomSocketFactory() { - client = client.newBuilder() - .sslSocketFactory(CustomSSLSocketFactory(client.sslSocketFactory), client.x509TrustManager!!) - .connectionSpecs(listOf( - ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .supportsTlsExtensions(false) - .build() - )) - .eventListener(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - val sslSocket = connection.socket() as SSLSocket - println("Requested " + sslSocket.sslParameters.applicationProtocols.joinToString()) - println("Negotiated " + sslSocket.applicationProtocol) - } - }) - .build() + client = + client.newBuilder() + .sslSocketFactory(CustomSSLSocketFactory(client.sslSocketFactory), client.x509TrustManager!!) + .connectionSpecs( + listOf( + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .supportsTlsExtensions(false) + .build(), + ), + ) + .eventListener( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + val sslSocket = connection.socket() as SSLSocket + println("Requested " + sslSocket.sslParameters.applicationProtocols.joinToString()) + println("Negotiated " + sslSocket.applicationProtocol) + } + }, + ) + .build() - val request = Request.Builder() - .url("https://www.google.com") - .build() + val request = + Request.Builder() + .url("https://www.google.com") + .build() client.newCall(request).execute().use { response -> assertThat(response.code).isEqualTo(200) } diff --git a/android-test/src/androidTest/java/okhttp/android/test/letsencrypt/LetsEncryptClientTest.kt b/android-test/src/androidTest/java/okhttp/android/test/letsencrypt/LetsEncryptClientTest.kt index 5bf749abb89d..99a856edc41b 100644 --- a/android-test/src/androidTest/java/okhttp/android/test/letsencrypt/LetsEncryptClientTest.kt +++ b/android-test/src/androidTest/java/okhttp/android/test/letsencrypt/LetsEncryptClientTest.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp.android.test.letsencrypt; +package okhttp.android.test.letsencrypt import android.os.Build import assertk.assertThat @@ -41,56 +41,61 @@ class LetsEncryptClientTest { val clientBuilder = OkHttpClient.Builder() if (androidMorEarlier) { - val cert: X509Certificate = """ - -----BEGIN CERTIFICATE----- - MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw - TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh - cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 - WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu - ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY - MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc - h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ - 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U - A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW - T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH - B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC - B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv - KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn - OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn - jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw - qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI - rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV - HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq - hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL - ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ - 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK - NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 - ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur - TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC - jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc - oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq - 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA - mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d - emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= - -----END CERTIFICATE----- - """.trimIndent().decodeCertificatePem() + val cert: X509Certificate = + """ + -----BEGIN CERTIFICATE----- + MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw + TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh + cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 + WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu + ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY + MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc + h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ + 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U + A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW + T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH + B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC + B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv + KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn + OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn + jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw + qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI + rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV + HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq + hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL + ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ + 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK + NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 + ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur + TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC + jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc + oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq + 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA + mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d + emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= + -----END CERTIFICATE----- + """.trimIndent().decodeCertificatePem() - val handshakeCertificates = HandshakeCertificates.Builder() - // TODO reenable in official answers + val handshakeCertificates = + HandshakeCertificates.Builder() + // TODO reenable in official answers // .addPlatformTrustedCertificates() - .addTrustedCertificate(cert) - .build() + .addTrustedCertificate(cert) + .build() clientBuilder - .sslSocketFactory(handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) } val client = clientBuilder.build() - val request = Request.Builder() - .url("https://valid-isrgrootx1.letsencrypt.org/robots.txt") - .build() + val request = + Request.Builder() + .url("https://valid-isrgrootx1.letsencrypt.org/robots.txt") + .build() client.newCall(request).execute().use { response -> assertThat(response.code).isEqualTo(404) assertThat(response.protocol).isEqualTo(Protocol.HTTP_2) diff --git a/android-test/src/androidTest/java/okhttp/android/test/sni/SniOverrideTest.kt b/android-test/src/androidTest/java/okhttp/android/test/sni/SniOverrideTest.kt index 6b3e3f79e4cd..7e606d4580a5 100644 --- a/android-test/src/androidTest/java/okhttp/android/test/sni/SniOverrideTest.kt +++ b/android-test/src/androidTest/java/okhttp/android/test/sni/SniOverrideTest.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp.android.test.sni; +package okhttp.android.test.sni import android.os.Build import android.util.Log @@ -39,15 +39,16 @@ import org.junit.jupiter.api.Test */ @Tag("Remote") class SniOverrideTest { - var client = OkHttpClient.Builder() - .build() + var client = + OkHttpClient.Builder() + .build() @Test fun getWithCustomSocketFactory() { assumeTrue(Build.VERSION.SDK_INT >= 24) class CustomSSLSocketFactory( - delegate: SSLSocketFactory + delegate: SSLSocketFactory, ) : DelegatingSSLSocketFactory(delegate) { override fun configureSocket(sslSocket: SSLSocket): SSLSocket { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { @@ -62,49 +63,52 @@ class SniOverrideTest { } } - client = client.newBuilder() - .sslSocketFactory(CustomSSLSocketFactory(client.sslSocketFactory), client.x509TrustManager!!) - .hostnameVerifier { hostname, session -> - val s = "hostname: $hostname peerHost:${session.peerHost}" - Log.d("SniOverrideTest", s) - try { - val cert = session.peerCertificates[0] as X509Certificate - for (name in cert.subjectAlternativeNames) { - if (name[0] as Int == 2) { - Log.d("SniOverrideTest", "cert: " + name[1]) + client = + client.newBuilder() + .sslSocketFactory(CustomSSLSocketFactory(client.sslSocketFactory), client.x509TrustManager!!) + .hostnameVerifier { hostname, session -> + val s = "hostname: $hostname peerHost:${session.peerHost}" + Log.d("SniOverrideTest", s) + try { + val cert = session.peerCertificates[0] as X509Certificate + for (name in cert.subjectAlternativeNames) { + if (name[0] as Int == 2) { + Log.d("SniOverrideTest", "cert: " + name[1]) + } } + true + } catch (e: Exception) { + false } - true - } catch (e: Exception) { - false } - } - .build() + .build() - val request = Request.Builder() - .url("https://sni.cloudflaressl.com/cdn-cgi/trace") - .header("Host", "cloudflare-dns.com") - .build() + val request = + Request.Builder() + .url("https://sni.cloudflaressl.com/cdn-cgi/trace") + .header("Host", "cloudflare-dns.com") + .build() client.newCall(request).execute().use { response -> assertThat(response.code).isEqualTo(200) assertThat(response.protocol).isEqualTo(Protocol.HTTP_2) - assertThat(response.body.string()).contains("h=cloudflare-dns.com") } } @Test fun getWithDns() { - client = client.newBuilder() - .dns { - Dns.SYSTEM.lookup("sni.cloudflaressl.com") - } - .build() + client = + client.newBuilder() + .dns { + Dns.SYSTEM.lookup("sni.cloudflaressl.com") + } + .build() - val request = Request.Builder() - .url("https://cloudflare-dns.com/cdn-cgi/trace") - .build() + val request = + Request.Builder() + .url("https://cloudflare-dns.com/cdn-cgi/trace") + .build() client.newCall(request).execute().use { response -> assertThat(response.code).isEqualTo(200) assertThat(response.protocol).isEqualTo(Protocol.HTTP_2) diff --git a/build.gradle.kts b/build.gradle.kts index 781eea7553d9..fca62fe13057 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,14 @@ @file:Suppress("UnstableApiUsage") +import com.diffplug.gradle.spotless.SpotlessExtension import com.vanniktech.maven.publish.MavenPublishBaseExtension import com.vanniktech.maven.publish.SonatypeHost -import java.net.URL +import java.net.URI import kotlinx.validation.ApiValidationExtension import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.jetbrains.dokka.gradle.DokkaTaskPartial import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension -import java.net.URI buildscript { dependencies { @@ -35,6 +35,14 @@ buildscript { } apply(plugin = "org.jetbrains.dokka") +apply(plugin = "com.diffplug.spotless") + +configure { + kotlin { + target("**/*.kt") + ktlint() + } +} allprojects { group = "com.squareup.okhttp3" diff --git a/buildSrc/src/main/kotlin/Osgi.kt b/buildSrc/src/main/kotlin/Osgi.kt index 7a33138b8e24..a23228fb9dcf 100644 --- a/buildSrc/src/main/kotlin/Osgi.kt +++ b/buildSrc/src/main/kotlin/Osgi.kt @@ -34,21 +34,23 @@ fun Project.applyOsgi(vararg bndProperties: String) { private fun Project.applyOsgi( jarTaskName: String, osgiApiConfigurationName: String, - bndProperties: Array + bndProperties: Array, ) { val osgi = project.sourceSets.create("osgi") val osgiApi = project.configurations.getByName(osgiApiConfigurationName) - val kotlinOsgi = extensions.getByType(VersionCatalogsExtension::class.java).named("libs") - .findLibrary("kotlin.stdlib.osgi").get().get() + val kotlinOsgi = + extensions.getByType(VersionCatalogsExtension::class.java).named("libs") + .findLibrary("kotlin.stdlib.osgi").get().get() project.dependencies { osgiApi(kotlinOsgi) } val jarTask = tasks.getByName(jarTaskName) - val bundleExtension = jarTask.extensions.findByType() ?: jarTask.extensions.create( - BundleTaskExtension.NAME, BundleTaskExtension::class.java, jarTask - ) + val bundleExtension = + jarTask.extensions.findByType() ?: jarTask.extensions.create( + BundleTaskExtension.NAME, BundleTaskExtension::class.java, jarTask, + ) bundleExtension.run { setClasspath(osgi.compileClasspath + sourceSets["main"].compileClasspath) bnd(*bndProperties) diff --git a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/DeprecationBridge.kt b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/DeprecationBridge.kt index edc69af61c50..7f7d416b6d4c 100644 --- a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/DeprecationBridge.kt +++ b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/DeprecationBridge.kt @@ -36,9 +36,7 @@ internal fun Dispatcher.wrap(): mockwebserver3.Dispatcher { val delegate = this return object : mockwebserver3.Dispatcher() { - override fun dispatch( - request: mockwebserver3.RecordedRequest - ): mockwebserver3.MockResponse { + override fun dispatch(request: mockwebserver3.RecordedRequest): mockwebserver3.MockResponse { return delegate.dispatch(request.unwrap()).wrap() } @@ -70,17 +68,18 @@ internal fun MockResponse.wrap(): mockwebserver3.MockResponse { result.status = status result.headers(headers) result.trailers(trailers) - result.socketPolicy = when (socketPolicy) { - SocketPolicy.EXPECT_CONTINUE, SocketPolicy.CONTINUE_ALWAYS -> { - result.add100Continue() - KeepOpen + result.socketPolicy = + when (socketPolicy) { + SocketPolicy.EXPECT_CONTINUE, SocketPolicy.CONTINUE_ALWAYS -> { + result.add100Continue() + KeepOpen + } + SocketPolicy.UPGRADE_TO_SSL_AT_END -> { + result.inTunnel() + KeepOpen + } + else -> wrapSocketPolicy() } - SocketPolicy.UPGRADE_TO_SSL_AT_END -> { - result.inTunnel() - KeepOpen - } - else -> wrapSocketPolicy() - } result.throttleBody(throttleBytesPerPeriod, getThrottlePeriod(MILLISECONDS), MILLISECONDS) result.bodyDelay(getBodyDelay(MILLISECONDS), MILLISECONDS) result.headersDelay(getHeadersDelay(MILLISECONDS), MILLISECONDS) @@ -92,7 +91,7 @@ private fun PushPromise.wrap(): mockwebserver3.PushPromise { method = method, path = path, headers = headers, - response = response.wrap() + response = response.wrap(), ) } @@ -108,7 +107,7 @@ internal fun mockwebserver3.RecordedRequest.unwrap(): RecordedRequest { method = method, path = path, handshake = handshake, - requestUrl = requestUrl + requestUrl = requestUrl, ) } diff --git a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/MockResponse.kt b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/MockResponse.kt index cfe8d086650e..9c8d33ef7ebb 100644 --- a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/MockResponse.kt +++ b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/MockResponse.kt @@ -14,14 +14,15 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3.mockwebserver +import java.util.concurrent.TimeUnit import okhttp3.Headers import okhttp3.WebSocketListener import okhttp3.internal.addHeaderLenient import okhttp3.internal.http2.Settings import okio.Buffer -import java.util.concurrent.TimeUnit class MockResponse : Cloneable { @set:JvmName("status") @@ -86,62 +87,81 @@ class MockResponse : Cloneable { @JvmName("-deprecated_getStatus") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith(expression = "status"), - level = DeprecationLevel.ERROR) + message = "moved to var", + replaceWith = ReplaceWith(expression = "status"), + level = DeprecationLevel.ERROR, + ) fun getStatus(): String = status - fun setStatus(status: String) = apply { - this.status = status - } + fun setStatus(status: String) = + apply { + this.status = status + } fun setResponseCode(code: Int): MockResponse { - val reason = when (code) { - in 100..199 -> "Informational" - in 200..299 -> "OK" - in 300..399 -> "Redirection" - in 400..499 -> "Client Error" - in 500..599 -> "Server Error" - else -> "Mock Response" - } + val reason = + when (code) { + in 100..199 -> "Informational" + in 200..299 -> "OK" + in 300..399 -> "Redirection" + in 400..499 -> "Client Error" + in 500..599 -> "Server Error" + else -> "Mock Response" + } return apply { status = "HTTP/1.1 $code $reason" } } - fun clearHeaders() = apply { - headersBuilder = Headers.Builder() - } + fun clearHeaders() = + apply { + headersBuilder = Headers.Builder() + } - fun addHeader(header: String) = apply { - headersBuilder.add(header) - } + fun addHeader(header: String) = + apply { + headersBuilder.add(header) + } - fun addHeader(name: String, value: Any) = apply { + fun addHeader( + name: String, + value: Any, + ) = apply { headersBuilder.add(name, value.toString()) } - fun addHeaderLenient(name: String, value: Any) = apply { + fun addHeaderLenient( + name: String, + value: Any, + ) = apply { addHeaderLenient(headersBuilder, name, value.toString()) } - fun setHeader(name: String, value: Any) = apply { + fun setHeader( + name: String, + value: Any, + ) = apply { removeHeader(name) addHeader(name, value) } - fun removeHeader(name: String) = apply { - headersBuilder.removeAll(name) - } + fun removeHeader(name: String) = + apply { + headersBuilder.removeAll(name) + } fun getBody(): Buffer? = body?.clone() - fun setBody(body: Buffer) = apply { - setHeader("Content-Length", body.size) - this.body = body.clone() // Defensive copy. - } + fun setBody(body: Buffer) = + apply { + setHeader("Content-Length", body.size) + this.body = body.clone() // Defensive copy. + } fun setBody(body: String): MockResponse = setBody(Buffer().writeUtf8(body)) - fun setChunkedBody(body: Buffer, maxChunkSize: Int) = apply { + fun setChunkedBody( + body: Buffer, + maxChunkSize: Int, + ) = apply { removeHeader("Content-Length") headersBuilder.add(CHUNKED_BODY_HEADER) @@ -157,89 +177,107 @@ class MockResponse : Cloneable { this.body = bytesOut } - fun setChunkedBody(body: String, maxChunkSize: Int): MockResponse = - setChunkedBody(Buffer().writeUtf8(body), maxChunkSize) + fun setChunkedBody( + body: String, + maxChunkSize: Int, + ): MockResponse = setChunkedBody(Buffer().writeUtf8(body), maxChunkSize) @JvmName("-deprecated_getHeaders") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith(expression = "headers"), - level = DeprecationLevel.ERROR) + message = "moved to var", + replaceWith = ReplaceWith(expression = "headers"), + level = DeprecationLevel.ERROR, + ) fun getHeaders(): Headers = headers fun setHeaders(headers: Headers) = apply { this.headers = headers } @JvmName("-deprecated_getTrailers") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith(expression = "trailers"), - level = DeprecationLevel.ERROR) + message = "moved to var", + replaceWith = ReplaceWith(expression = "trailers"), + level = DeprecationLevel.ERROR, + ) fun getTrailers(): Headers = trailers fun setTrailers(trailers: Headers) = apply { this.trailers = trailers } @JvmName("-deprecated_getSocketPolicy") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith(expression = "socketPolicy"), - level = DeprecationLevel.ERROR) + message = "moved to var", + replaceWith = ReplaceWith(expression = "socketPolicy"), + level = DeprecationLevel.ERROR, + ) fun getSocketPolicy(): SocketPolicy = socketPolicy - fun setSocketPolicy(socketPolicy: SocketPolicy) = apply { - this.socketPolicy = socketPolicy - } + fun setSocketPolicy(socketPolicy: SocketPolicy) = + apply { + this.socketPolicy = socketPolicy + } @JvmName("-deprecated_getHttp2ErrorCode") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith(expression = "http2ErrorCode"), - level = DeprecationLevel.ERROR) + message = "moved to var", + replaceWith = ReplaceWith(expression = "http2ErrorCode"), + level = DeprecationLevel.ERROR, + ) fun getHttp2ErrorCode(): Int = http2ErrorCode - fun setHttp2ErrorCode(http2ErrorCode: Int) = apply { - this.http2ErrorCode = http2ErrorCode - } + fun setHttp2ErrorCode(http2ErrorCode: Int) = + apply { + this.http2ErrorCode = http2ErrorCode + } - fun throttleBody(bytesPerPeriod: Long, period: Long, unit: TimeUnit) = apply { + fun throttleBody( + bytesPerPeriod: Long, + period: Long, + unit: TimeUnit, + ) = apply { throttleBytesPerPeriod = bytesPerPeriod throttlePeriodAmount = period throttlePeriodUnit = unit } - fun getThrottlePeriod(unit: TimeUnit): Long = - unit.convert(throttlePeriodAmount, throttlePeriodUnit) + fun getThrottlePeriod(unit: TimeUnit): Long = unit.convert(throttlePeriodAmount, throttlePeriodUnit) - fun setBodyDelay(delay: Long, unit: TimeUnit) = apply { + fun setBodyDelay( + delay: Long, + unit: TimeUnit, + ) = apply { bodyDelayAmount = delay bodyDelayUnit = unit } - fun getBodyDelay(unit: TimeUnit): Long = - unit.convert(bodyDelayAmount, bodyDelayUnit) + fun getBodyDelay(unit: TimeUnit): Long = unit.convert(bodyDelayAmount, bodyDelayUnit) - fun setHeadersDelay(delay: Long, unit: TimeUnit) = apply { + fun setHeadersDelay( + delay: Long, + unit: TimeUnit, + ) = apply { headersDelayAmount = delay headersDelayUnit = unit } - fun getHeadersDelay(unit: TimeUnit): Long = - unit.convert(headersDelayAmount, headersDelayUnit) + fun getHeadersDelay(unit: TimeUnit): Long = unit.convert(headersDelayAmount, headersDelayUnit) - fun withPush(promise: PushPromise) = apply { - promises.add(promise) - } + fun withPush(promise: PushPromise) = + apply { + promises.add(promise) + } - fun withSettings(settings: Settings) = apply { - this.settings = settings - } + fun withSettings(settings: Settings) = + apply { + this.settings = settings + } - fun withWebSocketUpgrade(listener: WebSocketListener) = apply { - status = "HTTP/1.1 101 Switching Protocols" - setHeader("Connection", "Upgrade") - setHeader("Upgrade", "websocket") - body = null - webSocketListener = listener - } + fun withWebSocketUpgrade(listener: WebSocketListener) = + apply { + status = "HTTP/1.1 101 Switching Protocols" + setHeader("Connection", "Upgrade") + setHeader("Upgrade", "websocket") + body = null + webSocketListener = listener + } override fun toString(): String = status diff --git a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/MockWebServer.kt b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/MockWebServer.kt index a853aaae338c..2b7bfc87cab6 100644 --- a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/MockWebServer.kt +++ b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/MockWebServer.kt @@ -15,9 +15,6 @@ */ package okhttp3.mockwebserver -import okhttp3.HttpUrl -import okhttp3.Protocol -import org.junit.rules.ExternalResource import java.io.Closeable import java.io.IOException import java.net.InetAddress @@ -27,6 +24,9 @@ import java.util.logging.Level import java.util.logging.Logger import javax.net.ServerSocketFactory import javax.net.ssl.SSLSocketFactory +import okhttp3.HttpUrl +import okhttp3.Protocol +import org.junit.rules.ExternalResource class MockWebServer : ExternalResource(), Closeable { val delegate = mockwebserver3.MockWebServer() @@ -57,7 +57,8 @@ class MockWebServer : ExternalResource(), Closeable { var protocolNegotiationEnabled: Boolean by delegate::protocolNegotiationEnabled - @get:JvmName("protocols") var protocols: List + @get:JvmName("protocols") + var protocols: List get() = delegate.protocols set(value) { delegate.protocols = value @@ -80,9 +81,10 @@ class MockWebServer : ExternalResource(), Closeable { @JvmName("-deprecated_port") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "port"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "port"), + level = DeprecationLevel.ERROR, + ) fun getPort(): Int = port fun toProxyAddress(): Proxy { @@ -92,11 +94,13 @@ class MockWebServer : ExternalResource(), Closeable { @JvmName("-deprecated_serverSocketFactory") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith( - expression = "run { this.serverSocketFactory = serverSocketFactory }" + message = "moved to var", + replaceWith = + ReplaceWith( + expression = "run { this.serverSocketFactory = serverSocketFactory }", ), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun setServerSocketFactory(serverSocketFactory: ServerSocketFactory) { delegate.serverSocketFactory = serverSocketFactory } @@ -108,43 +112,52 @@ class MockWebServer : ExternalResource(), Closeable { @JvmName("-deprecated_bodyLimit") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith( - expression = "run { this.bodyLimit = bodyLimit }" + message = "moved to var", + replaceWith = + ReplaceWith( + expression = "run { this.bodyLimit = bodyLimit }", ), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun setBodyLimit(bodyLimit: Long) { delegate.bodyLimit = bodyLimit } @JvmName("-deprecated_protocolNegotiationEnabled") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith( - expression = "run { this.protocolNegotiationEnabled = protocolNegotiationEnabled }" + message = "moved to var", + replaceWith = + ReplaceWith( + expression = "run { this.protocolNegotiationEnabled = protocolNegotiationEnabled }", ), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun setProtocolNegotiationEnabled(protocolNegotiationEnabled: Boolean) { delegate.protocolNegotiationEnabled = protocolNegotiationEnabled } @JvmName("-deprecated_protocols") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith(expression = "run { this.protocols = protocols }"), - level = DeprecationLevel.ERROR) + message = "moved to var", + replaceWith = ReplaceWith(expression = "run { this.protocols = protocols }"), + level = DeprecationLevel.ERROR, + ) fun setProtocols(protocols: List) { delegate.protocols = protocols } @JvmName("-deprecated_protocols") @Deprecated( - message = "moved to var", - replaceWith = ReplaceWith(expression = "protocols"), - level = DeprecationLevel.ERROR) + message = "moved to var", + replaceWith = ReplaceWith(expression = "protocols"), + level = DeprecationLevel.ERROR, + ) fun protocols(): List = delegate.protocols - fun useHttps(sslSocketFactory: SSLSocketFactory, tunnelProxy: Boolean) { + fun useHttps( + sslSocketFactory: SSLSocketFactory, + tunnelProxy: Boolean, + ) { delegate.useHttps(sslSocketFactory) } @@ -166,15 +179,19 @@ class MockWebServer : ExternalResource(), Closeable { } @Throws(InterruptedException::class) - fun takeRequest(timeout: Long, unit: TimeUnit): RecordedRequest? { + fun takeRequest( + timeout: Long, + unit: TimeUnit, + ): RecordedRequest? { return delegate.takeRequest(timeout, unit)?.unwrap() } @JvmName("-deprecated_requestCount") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "requestCount"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "requestCount"), + level = DeprecationLevel.ERROR, + ) fun getRequestCount(): Int = delegate.requestCount fun enqueue(response: MockResponse) { @@ -182,13 +199,17 @@ class MockWebServer : ExternalResource(), Closeable { } @Throws(IOException::class) - @JvmOverloads fun start(port: Int = 0) { + @JvmOverloads + fun start(port: Int = 0) { started = true delegate.start(port) } @Throws(IOException::class) - fun start(inetAddress: InetAddress, port: Int) { + fun start( + inetAddress: InetAddress, + port: Int, + ) { started = true delegate.start(inetAddress, port) } diff --git a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/PushPromise.kt b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/PushPromise.kt index aed6292654f4..c23fd82f9fb6 100644 --- a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/PushPromise.kt +++ b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/PushPromise.kt @@ -21,34 +21,37 @@ class PushPromise( @get:JvmName("method") val method: String, @get:JvmName("path") val path: String, @get:JvmName("headers") val headers: Headers, - @get:JvmName("response") val response: MockResponse + @get:JvmName("response") val response: MockResponse, ) { - @JvmName("-deprecated_method") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "method"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "method"), + level = DeprecationLevel.ERROR, + ) fun method(): String = method @JvmName("-deprecated_path") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "path"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "path"), + level = DeprecationLevel.ERROR, + ) fun path(): String = path @JvmName("-deprecated_headers") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "headers"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "headers"), + level = DeprecationLevel.ERROR, + ) fun headers(): Headers = headers @JvmName("-deprecated_response") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "response"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "response"), + level = DeprecationLevel.ERROR, + ) fun response(): MockResponse = response } diff --git a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/RecordedRequest.kt b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/RecordedRequest.kt index ff2e76fa0523..2e48315c5784 100644 --- a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/RecordedRequest.kt +++ b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/RecordedRequest.kt @@ -15,6 +15,10 @@ */ package okhttp3.mockwebserver +import java.io.IOException +import java.net.Inet6Address +import java.net.Socket +import javax.net.ssl.SSLSocket import okhttp3.Handshake import okhttp3.Handshake.Companion.handshake import okhttp3.Headers @@ -22,10 +26,6 @@ import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.TlsVersion import okio.Buffer -import java.io.IOException -import java.net.Inet6Address -import java.net.Socket -import javax.net.ssl.SSLSocket class RecordedRequest { val requestLine: String @@ -42,9 +42,10 @@ class RecordedRequest { @get:JvmName("-deprecated_utf8Body") @Deprecated( - message = "Use body.readUtf8()", - replaceWith = ReplaceWith("body.readUtf8()"), - level = DeprecationLevel.ERROR) + message = "Use body.readUtf8()", + replaceWith = ReplaceWith("body.readUtf8()"), + level = DeprecationLevel.ERROR, + ) val utf8Body: String get() = body.readUtf8() @@ -62,7 +63,7 @@ class RecordedRequest { method: String?, path: String?, handshake: Handshake?, - requestUrl: HttpUrl? + requestUrl: HttpUrl?, ) { this.requestLine = requestLine this.headers = headers @@ -86,7 +87,7 @@ class RecordedRequest { body: Buffer, sequenceNumber: Int, socket: Socket, - failure: IOException? = null + failure: IOException? = null, ) { this.requestLine = requestLine this.headers = headers @@ -139,9 +140,10 @@ class RecordedRequest { } @Deprecated( - message = "Use body.readUtf8()", - replaceWith = ReplaceWith("body.readUtf8()"), - level = DeprecationLevel.WARNING) + message = "Use body.readUtf8()", + replaceWith = ReplaceWith("body.readUtf8()"), + level = DeprecationLevel.WARNING, + ) fun getUtf8Body(): String = body.readUtf8() fun getHeader(name: String): String? = headers.values(name).firstOrNull() diff --git a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/SocketPolicy.kt b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/SocketPolicy.kt index 28df1eddbd6a..d82e66e3648e 100644 --- a/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/SocketPolicy.kt +++ b/mockwebserver-deprecated/src/main/kotlin/okhttp3/mockwebserver/SocketPolicy.kt @@ -32,5 +32,5 @@ enum class SocketPolicy { NO_RESPONSE, RESET_STREAM_AT_START, EXPECT_CONTINUE, - CONTINUE_ALWAYS + CONTINUE_ALWAYS, } diff --git a/mockwebserver-deprecated/src/test/java/okhttp3/mockwebserver/KotlinSourceModernTest.kt b/mockwebserver-deprecated/src/test/java/okhttp3/mockwebserver/KotlinSourceModernTest.kt index ae0346d45aa4..97cda69f0c3c 100644 --- a/mockwebserver-deprecated/src/test/java/okhttp3/mockwebserver/KotlinSourceModernTest.kt +++ b/mockwebserver-deprecated/src/test/java/okhttp3/mockwebserver/KotlinSourceModernTest.kt @@ -15,6 +15,12 @@ */ package okhttp3.mockwebserver +import java.net.InetAddress +import java.net.Proxy +import java.net.Socket +import java.util.concurrent.TimeUnit +import javax.net.ServerSocketFactory +import javax.net.ssl.SSLSocketFactory import okhttp3.Handshake import okhttp3.Headers import okhttp3.Headers.Companion.headersOf @@ -26,35 +32,32 @@ import okhttp3.internal.http2.Settings import okio.Buffer import org.junit.Ignore import org.junit.Test -import java.net.InetAddress -import java.net.Proxy -import java.net.Socket -import java.util.concurrent.TimeUnit -import javax.net.ServerSocketFactory -import javax.net.ssl.SSLSocketFactory /** * Access every type, function, and property from Kotlin to defend against unexpected regressions in * modern 4.0.x kotlin source-compatibility. */ @Suppress( - "ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", - "UNUSED_ANONYMOUS_PARAMETER", - "UNUSED_VALUE", - "UNUSED_VARIABLE", - "VARIABLE_WITH_REDUNDANT_INITIALIZER", - "RedundantLambdaArrow", - "RedundantExplicitType", - "IMPLICIT_NOTHING_AS_TYPE_PARAMETER" + "ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", + "UNUSED_ANONYMOUS_PARAMETER", + "UNUSED_VALUE", + "UNUSED_VARIABLE", + "VARIABLE_WITH_REDUNDANT_INITIALIZER", + "RedundantLambdaArrow", + "RedundantExplicitType", + "IMPLICIT_NOTHING_AS_TYPE_PARAMETER", ) class KotlinSourceModernTest { @Test @Ignore fun dispatcherFromMockWebServer() { - val dispatcher = object : Dispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse = TODO() - override fun peek(): MockResponse = TODO() - override fun shutdown() = TODO() - } + val dispatcher = + object : Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse = TODO() + + override fun peek(): MockResponse = TODO() + + override fun shutdown() = TODO() + } } @Test @Ignore @@ -96,8 +99,11 @@ class KotlinSourceModernTest { mockResponse = mockResponse.withSettings(Settings()) var settings: Settings = mockResponse.settings settings = mockResponse.settings - mockResponse = mockResponse.withWebSocketUpgrade(object : WebSocketListener() { - }) + mockResponse = + mockResponse.withWebSocketUpgrade( + object : WebSocketListener() { + }, + ) var webSocketListener: WebSocketListener? = mockResponse.webSocketListener webSocketListener = mockResponse.webSocketListener } @@ -146,8 +152,10 @@ class KotlinSourceModernTest { @Test @Ignore fun queueDispatcher() { val queueDispatcher: QueueDispatcher = QueueDispatcher() - var mockResponse: MockResponse = queueDispatcher.dispatch( - RecordedRequest("", headersOf(), listOf(), 0L, Buffer(), 0, Socket())) + var mockResponse: MockResponse = + queueDispatcher.dispatch( + RecordedRequest("", headersOf(), listOf(), 0L, Buffer(), 0, Socket()), + ) mockResponse = queueDispatcher.peek() queueDispatcher.enqueueResponse(MockResponse()) queueDispatcher.shutdown() @@ -157,8 +165,16 @@ class KotlinSourceModernTest { @Test @Ignore fun recordedRequest() { - var recordedRequest: RecordedRequest = RecordedRequest( - "", headersOf(), listOf(), 0L, Buffer(), 0, Socket()) + var recordedRequest: RecordedRequest = + RecordedRequest( + "", + headersOf(), + listOf(), + 0L, + Buffer(), + 0, + Socket(), + ) recordedRequest = RecordedRequest("", headersOf(), listOf(), 0L, Buffer(), 0, Socket()) var requestUrl: HttpUrl? = recordedRequest.requestUrl var requestLine: String = recordedRequest.requestLine diff --git a/mockwebserver-deprecated/src/test/java/okhttp3/mockwebserver/MockWebServerTest.kt b/mockwebserver-deprecated/src/test/java/okhttp3/mockwebserver/MockWebServerTest.kt index e81e2411f8e7..4b3033328e18 100644 --- a/mockwebserver-deprecated/src/test/java/okhttp3/mockwebserver/MockWebServerTest.kt +++ b/mockwebserver-deprecated/src/test/java/okhttp3/mockwebserver/MockWebServerTest.kt @@ -86,15 +86,16 @@ class MockWebServerTest { @Test fun setResponseMockReason() { - val reasons = arrayOf( - "Mock Response", - "Informational", - "OK", - "Redirection", - "Client Error", - "Server Error", - "Mock Response" - ) + val reasons = + arrayOf( + "Mock Response", + "Informational", + "OK", + "Redirection", + "Client Error", + "Server Error", + "Mock Response", + ) for (i in 0..599) { val response = MockResponse().setResponseCode(i) val expectedReason = reasons[i / 100] @@ -119,21 +120,23 @@ class MockWebServerTest { @Test fun mockResponseAddHeader() { - val response = MockResponse() - .clearHeaders() - .addHeader("Cookie: s=square") - .addHeader("Cookie", "a=android") + val response = + MockResponse() + .clearHeaders() + .addHeader("Cookie: s=square") + .addHeader("Cookie", "a=android") assertThat(headersToList(response)) .containsExactly("Cookie: s=square", "Cookie: a=android") } @Test fun mockResponseSetHeader() { - val response = MockResponse() - .clearHeaders() - .addHeader("Cookie: s=square") - .addHeader("Cookie: a=android") - .addHeader("Cookies: delicious") + val response = + MockResponse() + .clearHeaders() + .addHeader("Cookie: s=square") + .addHeader("Cookie: a=android") + .addHeader("Cookies: delicious") response.setHeader("cookie", "r=robot") assertThat(headersToList(response)) .containsExactly("Cookies: delicious", "cookie: r=robot") @@ -141,10 +144,11 @@ class MockWebServerTest { @Test fun mockResponseSetHeaders() { - val response = MockResponse() - .clearHeaders() - .addHeader("Cookie: s=square") - .addHeader("Cookies: delicious") + val response = + MockResponse() + .clearHeaders() + .addHeader("Cookie: s=square") + .addHeader("Cookies: delicious") response.setHeaders(Headers.Builder().add("Cookie", "a=android").build()) assertThat(headersToList(response)).containsExactly("Cookie: a=android") } @@ -173,7 +177,7 @@ class MockWebServerTest { MockResponse() .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) .addHeader("Location: " + server.url("/new-path")) - .setBody("This page has moved!") + .setBody("This page has moved!"), ) server.enqueue(MockResponse().setBody("This is the new location!")) val connection = server.url("/").toUrl().openConnection() @@ -211,7 +215,7 @@ class MockWebServerTest { MockResponse() .setBody("G\r\nxxxxxxxxxxxxxxxx\r\n0\r\n\r\n") .clearHeaders() - .addHeader("Transfer-encoding: chunked") + .addHeader("Transfer-encoding: chunked"), ) val connection = server.url("/").toUrl().openConnection() val inputStream = connection.getInputStream() @@ -228,7 +232,7 @@ class MockWebServerTest { MockResponse() .setBody("ABC") .clearHeaders() - .addHeader("Content-Length: 4") + .addHeader("Content-Length: 4"), ) server.enqueue(MockResponse().setBody("DEF")) val urlConnection = server.url("/").toUrl().openConnection() @@ -257,7 +261,7 @@ class MockWebServerTest { fun disconnectAtStart() { server.enqueue( MockResponse() - .setSocketPolicy(SocketPolicy.DISCONNECT_AT_START) + .setSocketPolicy(SocketPolicy.DISCONNECT_AT_START), ) server.enqueue(MockResponse()) // The jdk's HttpUrlConnection is a bastard. server.enqueue(MockResponse()) @@ -278,7 +282,7 @@ class MockWebServerTest { assumeNotWindows() server.enqueue( MockResponse() - .throttleBody(3, 500, TimeUnit.MILLISECONDS) + .throttleBody(3, 500, TimeUnit.MILLISECONDS), ) val startNanos = System.nanoTime() val connection = server.url("/").toUrl().openConnection() @@ -301,7 +305,7 @@ class MockWebServerTest { server.enqueue( MockResponse() .setBody("ABCDEF") - .throttleBody(3, 500, TimeUnit.MILLISECONDS) + .throttleBody(3, 500, TimeUnit.MILLISECONDS), ) val startNanos = System.nanoTime() val connection = server.url("/").toUrl().openConnection() @@ -325,7 +329,7 @@ class MockWebServerTest { server.enqueue( MockResponse() .setBody("ABCDEF") - .setBodyDelay(1, TimeUnit.SECONDS) + .setBodyDelay(1, TimeUnit.SECONDS), ) val startNanos = System.nanoTime() val connection = server.url("/").toUrl().openConnection() @@ -373,7 +377,7 @@ class MockWebServerTest { server.enqueue( MockResponse() .setBody("ab") - .setSocketPolicy(SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY) + .setSocketPolicy(SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY), ) val connection = server.url("/").toUrl().openConnection() assertThat(connection.getContentLength()).isEqualTo(2) @@ -443,12 +447,16 @@ class MockWebServerTest { @Test fun statementStartsAndStops() { val called = AtomicBoolean() - val statement = server.apply(object : Statement() { - override fun evaluate() { - called.set(true) - server.url("/").toUrl().openConnection().connect() - } - }, Description.EMPTY) + val statement = + server.apply( + object : Statement() { + override fun evaluate() { + called.set(true) + server.url("/").toUrl().openConnection().connect() + } + }, + Description.EMPTY, + ) statement.evaluate() assertThat(called.get()).isTrue() try { @@ -484,7 +492,7 @@ class MockWebServerTest { assertThat(reader.readLine()).isEqualTo("hello world") val request = server.takeRequest() 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 assertThat(requestUrl!!.scheme).isEqualTo("http") @@ -530,8 +538,8 @@ class MockWebServerTest { fail() } catch (expected: IllegalArgumentException) { assertThat(expected.message).isEqualTo( - "protocols containing h2_prior_knowledge cannot use other protocols: " - + "[h2_prior_knowledge, http/1.1]" + "protocols containing h2_prior_knowledge cannot use other protocols: " + + "[h2_prior_knowledge, http/1.1]", ) } } @@ -544,8 +552,8 @@ class MockWebServerTest { fail() } catch (expected: IllegalArgumentException) { assertThat(expected.message).isEqualTo( - "protocols containing h2_prior_knowledge cannot use other protocols: " - + "[h2_prior_knowledge, h2_prior_knowledge]" + "protocols containing h2_prior_knowledge cannot use other protocols: " + + "[h2_prior_knowledge, h2_prior_knowledge]", ) } } @@ -584,30 +592,36 @@ class MockWebServerTest { fun httpsWithClientAuth() { platform.assumeNotBouncyCastle() platform.assumeNotConscrypt() - val clientCa = HeldCertificate.Builder() - .certificateAuthority(0) - .build() - val serverCa = HeldCertificate.Builder() - .certificateAuthority(0) - .build() - val serverCertificate = HeldCertificate.Builder() - .signedBy(serverCa) - .addSubjectAlternativeName(server.hostName) - .build() - val serverHandshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(clientCa.certificate) - .heldCertificate(serverCertificate) - .build() + val clientCa = + HeldCertificate.Builder() + .certificateAuthority(0) + .build() + val serverCa = + HeldCertificate.Builder() + .certificateAuthority(0) + .build() + val serverCertificate = + HeldCertificate.Builder() + .signedBy(serverCa) + .addSubjectAlternativeName(server.hostName) + .build() + val serverHandshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(clientCa.certificate) + .heldCertificate(serverCertificate) + .build() server.useHttps(serverHandshakeCertificates.sslSocketFactory(), false) server.enqueue(MockResponse().setBody("abc")) server.requestClientAuth() - val clientCertificate = HeldCertificate.Builder() - .signedBy(clientCa) - .build() - val clientHandshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(serverCa.certificate) - .heldCertificate(clientCertificate) - .build() + val clientCertificate = + HeldCertificate.Builder() + .signedBy(clientCa) + .build() + val clientHandshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(serverCa.certificate) + .heldCertificate(clientCertificate) + .build() val url = server.url("/") val connection = url.toUrl().openConnection() as HttpsURLConnection connection.setSSLSocketFactory(clientHandshakeCertificates.sslSocketFactory()) diff --git a/mockwebserver-junit4/src/main/kotlin/mockwebserver3/junit4/MockWebServerRule.kt b/mockwebserver-junit4/src/main/kotlin/mockwebserver3/junit4/MockWebServerRule.kt index acdba2539031..7483bd171f31 100644 --- a/mockwebserver-junit4/src/main/kotlin/mockwebserver3/junit4/MockWebServerRule.kt +++ b/mockwebserver-junit4/src/main/kotlin/mockwebserver3/junit4/MockWebServerRule.kt @@ -15,11 +15,11 @@ */ package mockwebserver3.junit4 -import mockwebserver3.MockWebServer -import org.junit.rules.ExternalResource import java.io.IOException import java.util.logging.Level import java.util.logging.Logger +import mockwebserver3.MockWebServer +import org.junit.rules.ExternalResource /** * Runs MockWebServer for the duration of a single test method. diff --git a/mockwebserver-junit4/src/test/java/mockwebserver3/junit4/MockWebServerRuleTest.kt b/mockwebserver-junit4/src/test/java/mockwebserver3/junit4/MockWebServerRuleTest.kt index a72065774771..e0be5ade2263 100644 --- a/mockwebserver-junit4/src/test/java/mockwebserver3/junit4/MockWebServerRuleTest.kt +++ b/mockwebserver-junit4/src/test/java/mockwebserver3/junit4/MockWebServerRuleTest.kt @@ -28,12 +28,16 @@ class MockWebServerRuleTest { @Test fun statementStartsAndStops() { val rule = MockWebServerRule() val called = AtomicBoolean() - val statement: Statement = rule.apply(object : Statement() { - override fun evaluate() { - called.set(true) - rule.server.url("/").toUrl().openConnection().connect() - } - }, Description.EMPTY) + val statement: Statement = + rule.apply( + object : Statement() { + override fun evaluate() { + called.set(true) + rule.server.url("/").toUrl().openConnection().connect() + } + }, + Description.EMPTY, + ) statement.evaluate() assertThat(called.get()).isTrue() try { diff --git a/mockwebserver-junit5/src/main/kotlin/mockwebserver3/junit5/internal/MockWebServerExtension.kt b/mockwebserver-junit5/src/main/kotlin/mockwebserver3/junit5/internal/MockWebServerExtension.kt index 726d5932416d..1c9a79caf619 100644 --- a/mockwebserver-junit5/src/main/kotlin/mockwebserver3/junit5/internal/MockWebServerExtension.kt +++ b/mockwebserver-junit5/src/main/kotlin/mockwebserver3/junit5/internal/MockWebServerExtension.kt @@ -38,12 +38,13 @@ import org.junit.jupiter.api.extension.ParameterResolver * - The test lifecycle default (passed into test method, plus @BeforeEach, @AfterEach) * - named instances with @MockWebServerInstance. */ -class MockWebServerExtension - : BeforeEachCallback, AfterEachCallback, ParameterResolver { +class MockWebServerExtension : + BeforeEachCallback, AfterEachCallback, ParameterResolver { private val ExtensionContext.resource: ServersForTest - get() = getStore(namespace).getOrComputeIfAbsent(this.uniqueId) { - ServersForTest() - } as ServersForTest + get() = + getStore(namespace).getOrComputeIfAbsent(this.uniqueId) { + ServersForTest() + } as ServersForTest private class ServersForTest { private val servers = mutableMapOf() @@ -80,24 +81,25 @@ class MockWebServerExtension @IgnoreJRERequirement override fun supportsParameter( parameterContext: ParameterContext, - extensionContext: ExtensionContext + extensionContext: ExtensionContext, ): Boolean { // Not supported on constructors, or static contexts - return parameterContext.parameter.type === MockWebServer::class.java - && extensionContext.testMethod.isPresent + return parameterContext.parameter.type === MockWebServer::class.java && + extensionContext.testMethod.isPresent } @Suppress("NewApi") override fun resolveParameter( parameterContext: ParameterContext, - extensionContext: ExtensionContext + extensionContext: ExtensionContext, ): Any { val nameAnnotation = parameterContext.findAnnotation(MockWebServerInstance::class.java) - val name = if (nameAnnotation.isPresent) { - nameAnnotation.get().name - } else { - defaultName - } + val name = + if (nameAnnotation.isPresent) { + nameAnnotation.get().name + } else { + defaultName + } return extensionContext.resource.server(name) } diff --git a/mockwebserver-junit5/src/main/kotlin/mockwebserver3/junit5/internal/MockWebServerInstance.kt b/mockwebserver-junit5/src/main/kotlin/mockwebserver3/junit5/internal/MockWebServerInstance.kt index 6bee48c54b28..76a775b55386 100644 --- a/mockwebserver-junit5/src/main/kotlin/mockwebserver3/junit5/internal/MockWebServerInstance.kt +++ b/mockwebserver-junit5/src/main/kotlin/mockwebserver3/junit5/internal/MockWebServerInstance.kt @@ -16,5 +16,5 @@ package mockwebserver3.junit5.internal annotation class MockWebServerInstance( - val name: String + val name: String, ) diff --git a/mockwebserver-junit5/src/test/java/mockwebserver3/junit5/internal/ExtensionMultipleInstancesTest.kt b/mockwebserver-junit5/src/test/java/mockwebserver3/junit5/internal/ExtensionMultipleInstancesTest.kt index e9fb71a83b79..29ac65435bb5 100644 --- a/mockwebserver-junit5/src/test/java/mockwebserver3/junit5/internal/ExtensionMultipleInstancesTest.kt +++ b/mockwebserver-junit5/src/test/java/mockwebserver3/junit5/internal/ExtensionMultipleInstancesTest.kt @@ -35,7 +35,7 @@ class ExtensionMultipleInstancesTest { fun setup( defaultInstance: MockWebServer, @MockWebServerInstance("A") instanceA: MockWebServer, - @MockWebServerInstance("B") instanceB: MockWebServer + @MockWebServerInstance("B") instanceB: MockWebServer, ) { defaultInstancePort = defaultInstance.port instanceAPort = instanceA.port @@ -51,7 +51,7 @@ class ExtensionMultipleInstancesTest { fun tearDown( defaultInstance: MockWebServer, @MockWebServerInstance("A") instanceA: MockWebServer, - @MockWebServerInstance("B") instanceB: MockWebServer + @MockWebServerInstance("B") instanceB: MockWebServer, ) { assertThat(defaultInstance.port).isEqualTo(defaultInstancePort) assertThat(instanceA.port).isEqualTo(instanceAPort) @@ -62,7 +62,7 @@ class ExtensionMultipleInstancesTest { fun testClient( defaultInstance: MockWebServer, @MockWebServerInstance("A") instanceA: MockWebServer, - @MockWebServerInstance("B") instanceB: MockWebServer + @MockWebServerInstance("B") instanceB: MockWebServer, ) { assertThat(defaultInstance.port).isEqualTo(defaultInstancePort) assertThat(instanceA.port).isEqualTo(instanceAPort) diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/MockResponse.kt b/mockwebserver/src/main/kotlin/mockwebserver3/MockResponse.kt index 0c6aac9423b1..62f6c9753d0c 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/MockResponse.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/MockResponse.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package mockwebserver3 import java.util.concurrent.TimeUnit @@ -28,7 +29,6 @@ import okio.Buffer /** A scripted response to be replayed by the mock web server. */ class MockResponse { - /** Returns the HTTP response line, such as "HTTP/1.1 200 OK". */ val status: String @@ -76,14 +76,15 @@ class MockResponse { body: String = "", inTunnel: Boolean = false, socketPolicy: SocketPolicy = KeepOpen, - ) : this(Builder() - .apply { - this.code = code - this.headers.addAll(headers) - if (inTunnel) inTunnel() - this.body(body) - this.socketPolicy = socketPolicy - } + ) : this( + Builder() + .apply { + this.code = code + this.headers.addAll(headers) + if (inTunnel) inTunnel() + this.body(body) + this.socketPolicy = socketPolicy + }, ) private constructor(builder: Builder) { @@ -101,9 +102,10 @@ class MockResponse { this.bodyDelayNanos = builder.bodyDelayNanos this.headersDelayNanos = builder.headersDelayNanos this.pushPromises = builder.pushPromises.toList() - this.settings = Settings().apply { - merge(builder.settings) - } + this.settings = + Settings().apply { + merge(builder.settings) + } } fun newBuilder(): Builder = Builder(this) @@ -125,14 +127,15 @@ class MockResponse { return statusParts[1].toInt() } set(value) { - val reason = when (value) { - in 100..199 -> "Informational" - in 200..299 -> "OK" - in 300..399 -> "Redirection" - in 400..499 -> "Client Error" - in 500..599 -> "Server Error" - else -> "Mock Response" - } + val reason = + when (value) { + in 100..199 -> "Informational" + in 200..299 -> "OK" + in 300..399 -> "Redirection" + in 400..499 -> "Client Error" + in 500..599 -> "Server Error" + else -> "Mock Response" + } status = "HTTP/1.1 $value $reason" } @@ -189,8 +192,9 @@ class MockResponse { this.bodyVar = null this.streamHandlerVar = null this.webSocketListenerVar = null - this.headers = Headers.Builder() - .add("Content-Length", "0") + this.headers = + Headers.Builder() + .add("Content-Length", "0") this.trailers = Headers.Builder() this.throttleBytesPerPeriod = Long.MAX_VALUE this.throttlePeriodNanos = 0L @@ -216,41 +220,49 @@ class MockResponse { this.bodyDelayNanos = mockResponse.bodyDelayNanos this.headersDelayNanos = mockResponse.headersDelayNanos this.pushPromises = mockResponse.pushPromises.toMutableList() - this.settings = Settings().apply { - merge(mockResponse.settings) - } + this.settings = + Settings().apply { + merge(mockResponse.settings) + } } - fun code(code: Int) = apply { - this.code = code - } + fun code(code: Int) = + apply { + this.code = code + } /** Sets the status and returns this. */ - fun status(status: String) = apply { - this.status = status - } + fun status(status: String) = + apply { + this.status = status + } /** * Removes all HTTP headers including any "Content-Length" and "Transfer-encoding" headers that * were added by default. */ - fun clearHeaders() = apply { - headers = Headers.Builder() - } + fun clearHeaders() = + apply { + headers = Headers.Builder() + } /** * Adds [header] as an HTTP header. For well-formed HTTP [header] should contain a name followed * by a colon and a value. */ - fun addHeader(header: String) = apply { - headers.add(header) - } + fun addHeader(header: String) = + apply { + headers.add(header) + } /** * Adds a new header with the name and value. This may be used to add multiple headers with the * same name. */ - fun addHeader(name: String, value: Any) = apply { + fun addHeader( + name: String, + value: Any, + ) = apply { headers.add(name, value.toString()) } @@ -259,39 +271,51 @@ class MockResponse { * same name. Unlike [addHeader] this does not validate the name and * value. */ - fun addHeaderLenient(name: String, value: Any) = apply { + fun addHeaderLenient( + name: String, + value: Any, + ) = apply { addHeaderLenient(headers, name, value.toString()) } /** Removes all headers named [name], then adds a new header with the name and value. */ - fun setHeader(name: String, value: Any) = apply { + fun setHeader( + name: String, + value: Any, + ) = apply { removeHeader(name) addHeader(name, value) } /** Removes all headers named [name]. */ - fun removeHeader(name: String) = apply { - headers.removeAll(name) - } + fun removeHeader(name: String) = + apply { + headers.removeAll(name) + } fun body(body: Buffer) = body(body.toMockResponseBody()) - fun body(body: MockResponseBody) = apply { - setHeader("Content-Length", body.contentLength) - this.body = body - } + fun body(body: MockResponseBody) = + apply { + setHeader("Content-Length", body.contentLength) + this.body = body + } /** Sets the response body to the UTF-8 encoded bytes of [body]. */ fun body(body: String): Builder = body(Buffer().writeUtf8(body)) - fun streamHandler(streamHandler: StreamHandler) = apply { - this.streamHandler = streamHandler - } + fun streamHandler(streamHandler: StreamHandler) = + apply { + this.streamHandler = streamHandler + } /** * Sets the response body to [body], chunked every [maxChunkSize] bytes. */ - fun chunkedBody(body: Buffer, maxChunkSize: Int) = apply { + fun chunkedBody( + body: Buffer, + maxChunkSize: Int, + ) = apply { removeHeader("Content-Length") headers.add(CHUNKED_BODY_HEADER) @@ -311,29 +335,38 @@ class MockResponse { * Sets the response body to the UTF-8 encoded bytes of [body], * chunked every [maxChunkSize] bytes. */ - fun chunkedBody(body: String, maxChunkSize: Int): Builder = - chunkedBody(Buffer().writeUtf8(body), maxChunkSize) + fun chunkedBody( + body: String, + maxChunkSize: Int, + ): Builder = chunkedBody(Buffer().writeUtf8(body), maxChunkSize) /** Sets the headers and returns this. */ - fun headers(headers: Headers) = apply { - this.headers = headers.newBuilder() - } + fun headers(headers: Headers) = + apply { + this.headers = headers.newBuilder() + } /** Sets the trailers and returns this. */ - fun trailers(trailers: Headers) = apply { - this.trailers = trailers.newBuilder() - } + fun trailers(trailers: Headers) = + apply { + this.trailers = trailers.newBuilder() + } /** Sets the socket policy and returns this. */ - fun socketPolicy(socketPolicy: SocketPolicy) = apply { - this.socketPolicy = socketPolicy - } + fun socketPolicy(socketPolicy: SocketPolicy) = + apply { + this.socketPolicy = socketPolicy + } /** * Throttles the request reader and response writer to sleep for the given period after each * series of [bytesPerPeriod] bytes are transferred. Use this to simulate network behavior. */ - fun throttleBody(bytesPerPeriod: Long, period: Long, unit: TimeUnit) = apply { + fun throttleBody( + bytesPerPeriod: Long, + period: Long, + unit: TimeUnit, + ) = apply { throttleBytesPerPeriod = bytesPerPeriod throttlePeriodNanos = unit.toNanos(period) } @@ -342,11 +375,17 @@ class MockResponse { * Set the delayed time of the response body to [delay]. This applies to the response body * only; response headers are not affected. */ - fun bodyDelay(delay: Long, unit: TimeUnit) = apply { + fun bodyDelay( + delay: Long, + unit: TimeUnit, + ) = apply { bodyDelayNanos = unit.toNanos(delay) } - fun headersDelay(delay: Long, unit: TimeUnit) = apply { + fun headersDelay( + delay: Long, + unit: TimeUnit, + ) = apply { headersDelayNanos = unit.toNanos(delay) } @@ -354,29 +393,32 @@ class MockResponse { * When [protocols][MockWebServer.protocols] include [HTTP_2][okhttp3.Protocol], this attaches a * pushed stream to this response. */ - fun addPush(promise: PushPromise) = apply { - this.pushPromises += promise - } + fun addPush(promise: PushPromise) = + apply { + this.pushPromises += promise + } /** * When [protocols][MockWebServer.protocols] include [HTTP_2][okhttp3.Protocol], this pushes * [settings] before writing the response. */ - fun settings(settings: Settings) = apply { - this.settings.clear() - this.settings.merge(settings) - } + fun settings(settings: Settings) = + apply { + this.settings.clear() + this.settings.merge(settings) + } /** * Attempts to perform a web socket upgrade on the connection. * This will overwrite any previously set status, body, or streamHandler. */ - fun webSocketUpgrade(listener: WebSocketListener) = apply { - status = "HTTP/1.1 101 Switching Protocols" - setHeader("Connection", "Upgrade") - setHeader("Upgrade", "websocket") - webSocketListener = listener - } + fun webSocketUpgrade(listener: WebSocketListener) = + apply { + status = "HTTP/1.1 101 Switching Protocols" + setHeader("Connection", "Upgrade") + setHeader("Upgrade", "websocket") + webSocketListener = listener + } /** * Configures this response to be served as a response to an HTTP CONNECT request, either for @@ -385,23 +427,26 @@ class MockResponse { * When a new connection is received, all in-tunnel responses are served before the connection is * upgraded to HTTPS or HTTP/2. */ - fun inTunnel() = apply { - removeHeader("Content-Length") - inTunnel = true - } + fun inTunnel() = + apply { + removeHeader("Content-Length") + inTunnel = true + } /** * Adds an HTTP 1xx response to precede this response. Note that this response's * [headers delay][headersDelay] applies after this response is transmitted. Set a * headers delay on that response to delay its transmission. */ - fun addInformationalResponse(response: MockResponse) = apply { - informationalResponses += response - } + fun addInformationalResponse(response: MockResponse) = + apply { + informationalResponses += response + } - fun add100Continue() = apply { - addInformationalResponse(MockResponse(code = 100)) - } + fun add100Continue() = + apply { + addInformationalResponse(MockResponse(code = 100)) + } public override fun clone(): Builder = build().newBuilder() diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/MockWebServer.kt b/mockwebserver/src/main/kotlin/mockwebserver3/MockWebServer.kt index 3a1ff9d063ff..ef8b28599ea8 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/MockWebServer.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/MockWebServer.kt @@ -15,6 +15,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package mockwebserver3 import java.io.Closeable @@ -97,9 +98,10 @@ import okio.source * in sequence. */ class MockWebServer : Closeable { - private val taskRunnerBackend = TaskRunner.RealBackend( - threadFactory("MockWebServer TaskRunner", daemon = false) - ) + private val taskRunnerBackend = + TaskRunner.RealBackend( + threadFactory("MockWebServer TaskRunner", daemon = false), + ) private val taskRunner = TaskRunner(taskRunnerBackend) private val requestQueue = LinkedBlockingQueue() private val openClientSockets = @@ -126,6 +128,7 @@ class MockWebServer : Closeable { } return field } + @Synchronized set(value) { check(!started) { "serverSocketFactory must not be set after start()" } field = value @@ -280,8 +283,10 @@ class MockWebServer : Closeable { * @return the head of the request queue */ @Throws(InterruptedException::class) - fun takeRequest(timeout: Long, unit: TimeUnit): RecordedRequest? = - requestQueue.poll(timeout, unit) + fun takeRequest( + timeout: Long, + unit: TimeUnit, + ): RecordedRequest? = requestQueue.poll(timeout, unit) /** * Scripts [response] to be returned to a request made in sequence. The first request is @@ -291,8 +296,7 @@ class MockWebServer : Closeable { * @throws ClassCastException if the default dispatcher has been * replaced with [setDispatcher][dispatcher]. */ - fun enqueue(response: MockResponse) = - (dispatcher as QueueDispatcher).enqueueResponse(response) + fun enqueue(response: MockResponse) = (dispatcher as QueueDispatcher).enqueueResponse(response) /** * Starts the server on the loopback interface for the given port. @@ -301,7 +305,8 @@ class MockWebServer : Closeable { * use port 0 to avoid flakiness when a specific port is unavailable. */ @Throws(IOException::class) - @JvmOverloads fun start(port: Int = 0) = start(InetAddress.getByName("localhost"), port) + @JvmOverloads + fun start(port: Int = 0) = start(InetAddress.getByName("localhost"), port) /** * Starts the server on the given address and port. @@ -311,14 +316,18 @@ class MockWebServer : Closeable { * use port 0 to avoid flakiness when a specific port is unavailable. */ @Throws(IOException::class) - fun start(inetAddress: InetAddress, port: Int) = start(InetSocketAddress(inetAddress, port)) + fun start( + inetAddress: InetAddress, + port: Int, + ) = start(InetSocketAddress(inetAddress, port)) /** * Starts the server and binds to the given socket address. * * @param inetSocketAddress the socket address to bind the server on */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) private fun start(inetSocketAddress: InetSocketAddress) { check(!shutdown) { "shutdown() already called" } if (started) return @@ -432,9 +441,10 @@ class MockWebServer : Closeable { processHandshakeFailure(raw) return } - socket = sslSocketFactory!!.createSocket( - raw, raw.inetAddress.hostAddress, raw.port, true - ) + socket = + sslSocketFactory!!.createSocket( + raw, raw.inetAddress.hostAddress, raw.port, true, + ) val sslSocket = socket as SSLSocket sslSocket.useClientMode = false if (clientAuth == CLIENT_AUTH_REQUIRED) { @@ -452,10 +462,11 @@ class MockWebServer : Closeable { if (protocolNegotiationEnabled) { val protocolString = Platform.get().getSelectedProtocol(sslSocket) - protocol = when { - protocolString != null -> Protocol.get(protocolString) - else -> Protocol.HTTP_1_1 - } + protocol = + when { + protocolString != null -> Protocol.get(protocolString) + else -> Protocol.HTTP_1_1 + } Platform.get().afterHandshake(sslSocket) } else { protocol = Protocol.HTTP_1_1 @@ -463,10 +474,11 @@ class MockWebServer : Closeable { openClientSockets.remove(raw) } else -> { - protocol = when { - Protocol.H2_PRIOR_KNOWLEDGE in protocols -> Protocol.H2_PRIOR_KNOWLEDGE - else -> Protocol.HTTP_1_1 - } + protocol = + when { + Protocol.H2_PRIOR_KNOWLEDGE in protocols -> Protocol.H2_PRIOR_KNOWLEDGE + else -> Protocol.HTTP_1_1 + } socket = raw } } @@ -478,10 +490,11 @@ class MockWebServer : Closeable { if (protocol === Protocol.HTTP_2 || protocol === Protocol.H2_PRIOR_KNOWLEDGE) { val http2SocketHandler = Http2SocketHandler(socket, protocol) - val connection = Http2Connection.Builder(false, taskRunner) - .socket(socket) - .listener(http2SocketHandler) - .build() + val connection = + Http2Connection.Builder(false, taskRunner) + .socket(socket) + .listener(http2SocketHandler) + .build() connection.start() openConnections.add(connection) openClientSockets.remove(socket) @@ -498,7 +511,7 @@ class MockWebServer : Closeable { if (sequenceNumber == 0) { logger.warning( - "${this@MockWebServer} connection from ${raw.inetAddress} didn't make a request" + "${this@MockWebServer} connection from ${raw.inetAddress} didn't make a request", ) } @@ -538,7 +551,7 @@ class MockWebServer : Closeable { private fun processOneRequest( socket: Socket, source: BufferedSource, - sink: BufferedSink + sink: BufferedSink, ): Boolean { if (source.exhausted()) { return false // No more requests on this socket. @@ -581,7 +594,7 @@ class MockWebServer : Closeable { if (logger.isLoggable(Level.FINE)) { logger.fine( - "${this@MockWebServer} received request: $request and responded: $response" + "${this@MockWebServer} received request: $request and responded: $response", ) } @@ -607,9 +620,13 @@ class MockWebServer : Closeable { val context = SSLContext.getInstance("TLS") context.init(null, arrayOf(UNTRUSTED_TRUST_MANAGER), SecureRandom()) val sslSocketFactory = context.socketFactory - val socket = sslSocketFactory.createSocket( - raw, raw.inetAddress.hostAddress, raw.port, true - ) as SSLSocket + val socket = + sslSocketFactory.createSocket( + raw, + raw.inetAddress.hostAddress, + raw.port, + true, + ) as SSLSocket try { socket.startHandshake() // we're testing a handshake failure throw AssertionError() @@ -619,10 +636,20 @@ class MockWebServer : Closeable { } @Throws(InterruptedException::class) - private fun dispatchBookkeepingRequest(sequenceNumber: Int, socket: Socket) { - val request = RecordedRequest( - "", headersOf(), emptyList(), 0L, Buffer(), sequenceNumber, socket - ) + private fun dispatchBookkeepingRequest( + sequenceNumber: Int, + socket: Socket, + ) { + val request = + RecordedRequest( + "", + headersOf(), + emptyList(), + 0L, + Buffer(), + sequenceNumber, + socket, + ) atomicRequestCount.incrementAndGet() requestQueue.add(request) dispatcher.dispatch(request) @@ -634,7 +661,7 @@ class MockWebServer : Closeable { socket: Socket, source: BufferedSource, sink: BufferedSink, - sequenceNumber: Int + sequenceNumber: Int, ): RecordedRequest { var request = "" val headers = Headers.Builder() @@ -674,12 +701,13 @@ class MockWebServer : Closeable { var hasBody = false val policy = dispatcher.peek() - val requestBodySink = requestBody.withThrottlingAndSocketPolicy( - policy = policy, - disconnectHalfway = policy.socketPolicy == DisconnectDuringRequestBody, - expectedByteCount = contentLength, - socket = socket, - ).buffer() + val requestBodySink = + requestBody.withThrottlingAndSocketPolicy( + policy = policy, + disconnectHalfway = policy.socketPolicy == DisconnectDuringRequestBody, + expectedByteCount = contentLength, + socket = socket, + ).buffer() requestBodySink.use { when { policy.socketPolicy is DoNotReadRequestBody -> { @@ -725,7 +753,7 @@ class MockWebServer : Closeable { body = requestBody.buffer, sequenceNumber = sequenceNumber, socket = socket, - failure = failure + failure = failure, ) } @@ -735,47 +763,52 @@ class MockWebServer : Closeable { source: BufferedSource, sink: BufferedSink, request: RecordedRequest, - response: MockResponse + response: MockResponse, ) { val key = request.headers["Sec-WebSocket-Key"] - val webSocketResponse = response.newBuilder() - .setHeader("Sec-WebSocket-Accept", WebSocketProtocol.acceptHeader(key!!)) - .build() + val webSocketResponse = + response.newBuilder() + .setHeader("Sec-WebSocket-Accept", WebSocketProtocol.acceptHeader(key!!)) + .build() writeHttpResponse(socket, sink, webSocketResponse) // Adapt the request and response into our Request and Response domain model. val scheme = if (request.handshake != null) "https" else "http" val authority = request.headers["Host"] // Has host and port. - val fancyRequest = Request.Builder() - .url("$scheme://$authority/") - .headers(request.headers) - .build() - val fancyResponse = Response.Builder() - .code(webSocketResponse.code) - .message(webSocketResponse.message) - .headers(webSocketResponse.headers) - .request(fancyRequest) - .protocol(Protocol.HTTP_1_1) - .build() + val fancyRequest = + Request.Builder() + .url("$scheme://$authority/") + .headers(request.headers) + .build() + val fancyResponse = + Response.Builder() + .code(webSocketResponse.code) + .message(webSocketResponse.message) + .headers(webSocketResponse.headers) + .request(fancyRequest) + .protocol(Protocol.HTTP_1_1) + .build() val connectionClose = CountDownLatch(1) - val streams = object : RealWebSocket.Streams(false, source, sink) { - override fun close() = connectionClose.countDown() + val streams = + object : RealWebSocket.Streams(false, source, sink) { + override fun close() = connectionClose.countDown() - override fun cancel() { - socket.closeQuietly() + override fun cancel() { + socket.closeQuietly() + } } - } - val webSocket = RealWebSocket( - taskRunner = taskRunner, - originalRequest = fancyRequest, - listener = webSocketResponse.webSocketListener!!, - random = SecureRandom(), - pingIntervalMillis = 0, - extensions = WebSocketExtensions.parse(webSocketResponse.headers), - // Compress all messages if compression is enabled. - minimumDeflateSize = 0L, - ) + val webSocket = + RealWebSocket( + taskRunner = taskRunner, + originalRequest = fancyRequest, + listener = webSocketResponse.webSocketListener!!, + random = SecureRandom(), + pingIntervalMillis = 0, + extensions = WebSocketExtensions.parse(webSocketResponse.headers), + // Compress all messages if compression is enabled. + minimumDeflateSize = 0L, + ) val name = "MockWebServer WebSocket ${request.path!!}" webSocket.initReaderAndWriter(name, streams) try { @@ -789,7 +822,11 @@ class MockWebServer : Closeable { } @Throws(IOException::class) - private fun writeHttpResponse(socket: Socket, sink: BufferedSink, response: MockResponse) { + private fun writeHttpResponse( + socket: Socket, + sink: BufferedSink, + response: MockResponse, + ) { sleepNanos(response.headersDelayNanos) sink.writeUtf8(response.status) sink.writeUtf8("\r\n") @@ -798,12 +835,13 @@ class MockWebServer : Closeable { val body = response.body ?: return sleepNanos(response.bodyDelayNanos) - val responseBodySink = sink.withThrottlingAndSocketPolicy( - policy = response, - disconnectHalfway = response.socketPolicy == DisconnectDuringResponseBody, - expectedByteCount = body.contentLength, - socket = socket, - ).buffer() + val responseBodySink = + sink.withThrottlingAndSocketPolicy( + policy = response, + disconnectHalfway = response.socketPolicy == DisconnectDuringResponseBody, + expectedByteCount = body.contentLength, + socket = socket, + ).buffer() body.writeTo(responseBodySink) responseBodySink.emit() @@ -813,7 +851,10 @@ class MockWebServer : Closeable { } @Throws(IOException::class) - private fun writeHeaders(sink: BufferedSink, headers: Headers) { + private fun writeHeaders( + sink: BufferedSink, + headers: Headers, + ) { for ((name, value) in headers) { sink.writeUtf8(name) sink.writeUtf8(": ") @@ -834,25 +875,28 @@ class MockWebServer : Closeable { var result: Sink = this if (policy.throttlePeriodNanos > 0L) { - result = ThrottledSink( - delegate = result, - bytesPerPeriod = policy.throttleBytesPerPeriod, - periodDelayNanos = policy.throttlePeriodNanos, - ) + result = + ThrottledSink( + delegate = result, + bytesPerPeriod = policy.throttleBytesPerPeriod, + periodDelayNanos = policy.throttlePeriodNanos, + ) } if (disconnectHalfway) { - val halfwayByteCount = when { - expectedByteCount != -1L -> expectedByteCount / 2 - else -> 0L - } - result = TriggerSink( - delegate = result, - triggerByteCount = halfwayByteCount, - ) { - result.flush() - socket.close() - } + val halfwayByteCount = + when { + expectedByteCount != -1L -> expectedByteCount / 2 + else -> 0L + } + result = + TriggerSink( + delegate = result, + triggerByteCount = halfwayByteCount, + ) { + result.flush() + socket.close() + } } return result @@ -871,13 +915,16 @@ class MockWebServer : Closeable { /** A buffer wrapper that drops data after [bodyLimit] bytes. */ private class TruncatingBuffer( - private var remainingByteCount: Long + private var remainingByteCount: Long, ) : Sink { val buffer = Buffer() var receivedByteCount = 0L @Throws(IOException::class) - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { val toRead = minOf(remainingByteCount, byteCount) if (toRead > 0L) { source.read(buffer, toRead) @@ -904,7 +951,7 @@ class MockWebServer : Closeable { /** Processes HTTP requests layered over HTTP/2. */ private inner class Http2SocketHandler constructor( private val socket: Socket, - private val protocol: Protocol + private val protocol: Protocol, ) : Http2Connection.Listener() { private val sequenceNumber = AtomicInteger() @@ -935,7 +982,7 @@ class MockWebServer : Closeable { if (logger.isLoggable(Level.FINE)) { logger.fine( "${this@MockWebServer} received request: $request " + - "and responded: $response protocol is $protocol" + "and responded: $response protocol is $protocol", ) } @@ -990,12 +1037,13 @@ class MockWebServer : Closeable { if (readBody && peek.streamHandler == null && peek.socketPolicy !is DoNotReadRequestBody) { try { val contentLengthString = headers["content-length"] - val requestBodySink = body.withThrottlingAndSocketPolicy( - policy = peek, - disconnectHalfway = peek.socketPolicy == DisconnectDuringRequestBody, - expectedByteCount = contentLengthString?.toLong() ?: Long.MAX_VALUE, - socket = socket, - ).buffer() + val requestBodySink = + body.withThrottlingAndSocketPolicy( + policy = peek, + disconnectHalfway = peek.socketPolicy == DisconnectDuringRequestBody, + expectedByteCount = contentLengthString?.toLong() ?: Long.MAX_VALUE, + socket = socket, + ).buffer() requestBodySink.use { it.writeAll(stream.getSource()) } @@ -1012,7 +1060,7 @@ class MockWebServer : Closeable { body = body, sequenceNumber = sequenceNumber.getAndIncrement(), socket = socket, - failure = exception + failure = exception, ) } @@ -1029,7 +1077,7 @@ class MockWebServer : Closeable { private fun writeResponse( stream: Http2Stream, request: RecordedRequest, - response: MockResponse + response: MockResponse, ) { val settings = response.settings stream.connection.setSettings(settings) @@ -1042,9 +1090,11 @@ class MockWebServer : Closeable { val trailers = response.trailers val body = response.body val streamHandler = response.streamHandler - val outFinished = (body == null && - response.pushPromises.isEmpty() && - streamHandler == null) + val outFinished = ( + body == null && + response.pushPromises.isEmpty() && + streamHandler == null + ) val flushHeaders = body == null || bodyDelayNanos != 0L require(!outFinished || trailers.size == 0) { "unsupported: no body and non-empty trailers $trailers" @@ -1059,12 +1109,13 @@ class MockWebServer : Closeable { pushPromises(stream, request, response.pushPromises) if (body != null) { sleepNanos(bodyDelayNanos) - val responseBodySink = stream.getSink().withThrottlingAndSocketPolicy( - policy = response, - disconnectHalfway = response.socketPolicy == DisconnectDuringResponseBody, - expectedByteCount = body.contentLength, - socket = socket - ).buffer() + val responseBodySink = + stream.getSink().withThrottlingAndSocketPolicy( + policy = response, + disconnectHalfway = response.socketPolicy == DisconnectDuringResponseBody, + expectedByteCount = body.contentLength, + socket = socket, + ).buffer() responseBodySink.use { body.writeTo(responseBodySink) } @@ -1079,7 +1130,7 @@ class MockWebServer : Closeable { private fun pushPromises( stream: Http2Stream, request: RecordedRequest, - promises: List + promises: List, ) { for (pushPromise in promises) { val pushedHeaders = mutableListOf
() @@ -1100,8 +1151,8 @@ class MockWebServer : Closeable { bodySize = 0, body = Buffer(), sequenceNumber = sequenceNumber.getAndIncrement(), - socket = socket - ) + socket = socket, + ), ) val hasBody = pushPromise.response.body != null val pushedStream = stream.connection.pushStream(stream.id, pushedHeaders, hasBody) @@ -1115,20 +1166,21 @@ class MockWebServer : Closeable { private const val CLIENT_AUTH_REQUESTED = 1 private const val CLIENT_AUTH_REQUIRED = 2 - private val UNTRUSTED_TRUST_MANAGER = object : X509TrustManager { - @Throws(CertificateException::class) - override fun checkClientTrusted( - chain: Array, - authType: String - ) = throw CertificateException() + private val UNTRUSTED_TRUST_MANAGER = + object : X509TrustManager { + @Throws(CertificateException::class) + override fun checkClientTrusted( + chain: Array, + authType: String, + ) = throw CertificateException() - override fun checkServerTrusted( - chain: Array, - authType: String - ) = throw AssertionError() + override fun checkServerTrusted( + chain: Array, + authType: String, + ) = throw AssertionError() - override fun getAcceptedIssuers(): Array = throw AssertionError() - } + override fun getAcceptedIssuers(): Array = throw AssertionError() + } private val logger = Logger.getLogger(MockWebServer::class.java.name) } diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/QueueDispatcher.kt b/mockwebserver/src/main/kotlin/mockwebserver3/QueueDispatcher.kt index 2f11931b6cfa..2b75c0d2965c 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/QueueDispatcher.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/QueueDispatcher.kt @@ -68,11 +68,12 @@ open class QueueDispatcher : Dispatcher() { } open fun setFailFast(failFast: Boolean) { - val failFastResponse = if (failFast) { - MockResponse(code = HttpURLConnection.HTTP_NOT_FOUND) - } else { - null - } + val failFastResponse = + if (failFast) { + MockResponse(code = HttpURLConnection.HTTP_NOT_FOUND) + } else { + null + } setFailFast(failFastResponse) } diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/RecordedRequest.kt b/mockwebserver/src/main/kotlin/mockwebserver3/RecordedRequest.kt index bc50a4273eb5..23728fa60f5c 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/RecordedRequest.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/RecordedRequest.kt @@ -31,34 +31,28 @@ import okio.Buffer /** An HTTP request that came into the mock web server. */ class RecordedRequest( val requestLine: String, - /** All headers. */ val headers: Headers, - /** * The sizes of the chunks of this request's body, or an empty list if the request's body * was empty or unchunked. */ val chunkSizes: List, - /** The total size of the body of this POST request (before truncation).*/ val bodySize: Long, - /** The body of this POST request. This may be truncated. */ val body: Buffer, - /** * The index of this request on its HTTP connection. Since a single HTTP connection may serve * multiple requests, each request is assigned its own sequence number. */ val sequenceNumber: Int, socket: Socket, - /** * The failure MockWebServer recorded when attempting to decode this request. If, for example, * the inbound request was truncated, this exception will be non-null. */ - val failure: IOException? = null + val failure: IOException? = null, ) { val method: String? val path: String? @@ -102,12 +96,13 @@ class RecordedRequest( 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" - } + 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 this.requestUrl = "$scheme://$hostAndPort$path".toHttpUrlOrNull() diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/SocketPolicy.kt b/mockwebserver/src/main/kotlin/mockwebserver3/SocketPolicy.kt index 408be99a20aa..6e02f8d7f852 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/SocketPolicy.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/SocketPolicy.kt @@ -30,7 +30,6 @@ package mockwebserver3 * server has closed the socket before follow up requests are made. */ sealed interface SocketPolicy { - /** * Shutdown [MockWebServer] after writing response. */ diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/internal/ThrottledSink.kt b/mockwebserver/src/main/kotlin/mockwebserver3/internal/ThrottledSink.kt index f75bf7761c8e..4dbfca0edd9d 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/internal/ThrottledSink.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/internal/ThrottledSink.kt @@ -29,7 +29,11 @@ internal class ThrottledSink( private val periodDelayNanos: Long, ) : Sink by delegate { private var bytesWrittenSinceLastDelay = 0L - override fun write(source: Buffer, byteCount: Long) { + + override fun write( + source: Buffer, + byteCount: Long, + ) { var bytesLeft = byteCount while (bytesLeft > 0) { diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/internal/TriggerSink.kt b/mockwebserver/src/main/kotlin/mockwebserver3/internal/TriggerSink.kt index 4de87552503f..09826b494cc6 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/internal/TriggerSink.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/internal/TriggerSink.kt @@ -30,7 +30,10 @@ internal class TriggerSink( ) : Sink by delegate { private var bytesWritten = 0L - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { if (byteCount == 0L) return // Avoid double-triggering. if (bytesWritten == triggerByteCount) { diff --git a/mockwebserver/src/main/kotlin/mockwebserver3/internal/duplex/MockStreamHandler.kt b/mockwebserver/src/main/kotlin/mockwebserver3/internal/duplex/MockStreamHandler.kt index 4bc91644eef2..db4e0449d527 100644 --- a/mockwebserver/src/main/kotlin/mockwebserver3/internal/duplex/MockStreamHandler.kt +++ b/mockwebserver/src/main/kotlin/mockwebserver3/internal/duplex/MockStreamHandler.kt @@ -34,37 +34,41 @@ class MockStreamHandler : StreamHandler { private val actions = LinkedBlockingQueue() private val results = LinkedBlockingQueue>() - fun receiveRequest(expected: String) = apply { - actions += { stream -> - val actual = stream.requestBody.readUtf8(expected.utf8Size()) - if (actual != expected) throw AssertionError("$actual != $expected") + fun receiveRequest(expected: String) = + apply { + actions += { stream -> + val actual = stream.requestBody.readUtf8(expected.utf8Size()) + if (actual != expected) throw AssertionError("$actual != $expected") + } } - } - fun exhaustRequest() = apply { - actions += { stream -> - if (!stream.requestBody.exhausted()) throw AssertionError("expected exhausted") + fun exhaustRequest() = + apply { + actions += { stream -> + if (!stream.requestBody.exhausted()) throw AssertionError("expected exhausted") + } } - } - fun cancelStream() = apply { - actions += { stream -> stream.cancel() } - } + fun cancelStream() = + apply { + actions += { stream -> stream.cancel() } + } - fun requestIOException() = apply { - actions += { stream -> - try { - stream.requestBody.exhausted() - throw AssertionError("expected IOException") - } catch (expected: IOException) { + fun requestIOException() = + apply { + actions += { stream -> + try { + stream.requestBody.exhausted() + throw AssertionError("expected IOException") + } catch (expected: IOException) { + } } } - } @JvmOverloads fun sendResponse( s: String, - responseSent: CountDownLatch = CountDownLatch(0) + responseSent: CountDownLatch = CountDownLatch(0), ) = apply { actions += { stream -> stream.responseBody.writeUtf8(s) @@ -73,11 +77,15 @@ class MockStreamHandler : StreamHandler { } } - fun exhaustResponse() = apply { - actions += { stream -> stream.responseBody.close() } - } + fun exhaustResponse() = + apply { + actions += { stream -> stream.responseBody.close() } + } - fun sleep(duration: Long, unit: TimeUnit) = apply { + fun sleep( + duration: Long, + unit: TimeUnit, + ) = apply { actions += { Thread.sleep(unit.toMillis(duration)) } } @@ -88,9 +96,7 @@ class MockStreamHandler : StreamHandler { } /** Returns a task that processes both request and response from [stream]. */ - private fun serviceStreamTask( - stream: Stream, - ): FutureTask { + private fun serviceStreamTask(stream: Stream): FutureTask { return FutureTask { stream.requestBody.use { stream.responseBody.use { @@ -106,8 +112,9 @@ class MockStreamHandler : StreamHandler { /** Returns once all stream actions complete successfully. */ fun awaitSuccess() { - val futureTask = results.poll(5, TimeUnit.SECONDS) - ?: throw AssertionError("no onRequest call received") + val futureTask = + results.poll(5, TimeUnit.SECONDS) + ?: throw AssertionError("no onRequest call received") futureTask.get(5, TimeUnit.SECONDS) } } diff --git a/mockwebserver/src/test/java/mockwebserver3/CustomDispatcherTest.kt b/mockwebserver/src/test/java/mockwebserver3/CustomDispatcherTest.kt index 682c790fb03d..ced412e037ad 100644 --- a/mockwebserver/src/test/java/mockwebserver3/CustomDispatcherTest.kt +++ b/mockwebserver/src/test/java/mockwebserver3/CustomDispatcherTest.kt @@ -37,12 +37,13 @@ class CustomDispatcherTest { @Test fun simpleDispatch() { val requestsMade = mutableListOf() - val dispatcher: Dispatcher = object : Dispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse { - requestsMade.add(request) - return MockResponse() + val dispatcher: Dispatcher = + object : Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + requestsMade.add(request) + return MockResponse() + } } - } assertThat(requestsMade.size).isEqualTo(0) mockWebServer.dispatcher = dispatcher val url = mockWebServer.url("/").toUrl() @@ -59,14 +60,15 @@ class CustomDispatcherTest { val secondRequest = "/bar" val firstRequest = "/foo" val latch = CountDownLatch(1) - val dispatcher: Dispatcher = object : Dispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse { - if (request.path == firstRequest) { - latch.await() + val dispatcher: Dispatcher = + object : Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + if (request.path == firstRequest) { + latch.await() + } + return MockResponse() } - return MockResponse() } - } mockWebServer.dispatcher = dispatcher val startsFirst = buildRequestThread(firstRequest, firstResponseCode) startsFirst.start() @@ -85,7 +87,10 @@ class CustomDispatcherTest { assertThat(secondResponseCode.get()).isEqualTo(200) } - private fun buildRequestThread(path: String, responseCode: AtomicInteger): Thread { + private fun buildRequestThread( + path: String, + responseCode: AtomicInteger, + ): Thread { return Thread { val url = mockWebServer.url(path).toUrl() val conn: HttpURLConnection diff --git a/mockwebserver/src/test/java/mockwebserver3/MockResponseSniTest.kt b/mockwebserver/src/test/java/mockwebserver3/MockResponseSniTest.kt index b312a5d61f80..1367de61c6cc 100644 --- a/mockwebserver/src/test/java/mockwebserver3/MockResponseSniTest.kt +++ b/mockwebserver/src/test/java/mockwebserver3/MockResponseSniTest.kt @@ -55,17 +55,19 @@ class MockResponseSniTest { val handshakeCertificates = localhost() server.useHttps(handshakeCertificates.sslSocketFactory()) - val dns = Dns { - Dns.SYSTEM.lookup(server.hostName) - } - - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .dns(dns) - .build() + val dns = + Dns { + Dns.SYSTEM.lookup(server.hostName) + } + + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .dns(dns) + .build() server.enqueue(MockResponse()) @@ -84,36 +86,41 @@ class MockResponseSniTest { */ @Test fun domainFronting() { - val heldCertificate = HeldCertificate.Builder() - .commonName("server name") - .addSubjectAlternativeName("url-host.com") - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate(heldCertificate) - .addTrustedCertificate(heldCertificate.certificate) - .build() + val heldCertificate = + HeldCertificate.Builder() + .commonName("server name") + .addSubjectAlternativeName("url-host.com") + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate(heldCertificate) + .addTrustedCertificate(heldCertificate.certificate) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) - val dns = Dns { - Dns.SYSTEM.lookup(server.hostName) - } + val dns = + Dns { + Dns.SYSTEM.lookup(server.hostName) + } - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .dns(dns) - .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .dns(dns) + .build() server.enqueue(MockResponse()) - val call = client.newCall( - Request( - url = "https://url-host.com:${server.port}/".toHttpUrl(), - headers = headersOf("Host", "header-host"), + val call = + client.newCall( + Request( + url = "https://url-host.com:${server.port}/".toHttpUrl(), + headers = headersOf("Host", "header-host"), + ), ) - ) val response = call.execute() assertThat(response.isSuccessful).isTrue() @@ -150,34 +157,39 @@ class MockResponseSniTest { * tell MockWebServer to act as a proxy. */ private fun requestToHostnameViaProxy(hostnameOrIpAddress: String): RecordedRequest { - val heldCertificate = HeldCertificate.Builder() - .commonName("server name") - .addSubjectAlternativeName(hostnameOrIpAddress) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate(heldCertificate) - .addTrustedCertificate(heldCertificate.certificate) - .build() + val heldCertificate = + HeldCertificate.Builder() + .commonName("server name") + .addSubjectAlternativeName(hostnameOrIpAddress) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate(heldCertificate) + .addTrustedCertificate(heldCertificate.certificate) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .build() server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse()) - val call = client.newCall( - Request( - url = server.url("/").newBuilder() - .host(hostnameOrIpAddress) - .build() + val call = + client.newCall( + Request( + url = + server.url("/").newBuilder() + .host(hostnameOrIpAddress) + .build(), + ), ) - ) val response = call.execute() assertThat(response.isSuccessful).isTrue() diff --git a/mockwebserver/src/test/java/mockwebserver3/MockWebServerTest.kt b/mockwebserver/src/test/java/mockwebserver3/MockWebServerTest.kt index 738051eb1009..c54ef56afce1 100644 --- a/mockwebserver/src/test/java/mockwebserver3/MockWebServerTest.kt +++ b/mockwebserver/src/test/java/mockwebserver3/MockWebServerTest.kt @@ -92,15 +92,16 @@ class MockWebServerTest { @Test fun setResponseMockReason() { - val reasons = arrayOf( - "Mock Response", - "Informational", - "OK", - "Redirection", - "Client Error", - "Server Error", - "Mock Response" - ) + val reasons = + arrayOf( + "Mock Response", + "Informational", + "OK", + "Redirection", + "Client Error", + "Server Error", + "Mock Response", + ) for (i in 0..599) { val builder = MockResponse.Builder().code(i) val expectedReason = reasons[i / 100] @@ -128,30 +129,33 @@ class MockWebServerTest { @Test fun mockResponseAddHeader() { - val builder = MockResponse.Builder() - .clearHeaders() - .addHeader("Cookie: s=square") - .addHeader("Cookie", "a=android") + val builder = + MockResponse.Builder() + .clearHeaders() + .addHeader("Cookie: s=square") + .addHeader("Cookie", "a=android") assertThat(headersToList(builder)).containsExactly("Cookie: s=square", "Cookie: a=android") } @Test fun mockResponseSetHeader() { - val builder = MockResponse.Builder() - .clearHeaders() - .addHeader("Cookie: s=square") - .addHeader("Cookie: a=android") - .addHeader("Cookies: delicious") + val builder = + MockResponse.Builder() + .clearHeaders() + .addHeader("Cookie: s=square") + .addHeader("Cookie: a=android") + .addHeader("Cookies: delicious") builder.setHeader("cookie", "r=robot") assertThat(headersToList(builder)).containsExactly("Cookies: delicious", "cookie: r=robot") } @Test fun mockResponseSetHeaders() { - val builder = MockResponse.Builder() - .clearHeaders() - .addHeader("Cookie: s=square") - .addHeader("Cookies: delicious") + val builder = + MockResponse.Builder() + .clearHeaders() + .addHeader("Cookie: s=square") + .addHeader("Cookies: delicious") builder.headers(Headers.Builder().add("Cookie", "a=android").build()) assertThat(headersToList(builder)).containsExactly("Cookie: a=android") } @@ -175,14 +179,18 @@ class MockWebServerTest { @Test fun redirect() { - server.enqueue(MockResponse.Builder() - .code(HttpURLConnection.HTTP_MOVED_TEMP) - .addHeader("Location: " + server.url("/new-path")) - .body("This page has moved!") - .build()) - server.enqueue(MockResponse.Builder() - .body("This is the new location!") - .build()) + server.enqueue( + MockResponse.Builder() + .code(HttpURLConnection.HTTP_MOVED_TEMP) + .addHeader("Location: " + server.url("/new-path")) + .body("This page has moved!") + .build(), + ) + server.enqueue( + MockResponse.Builder() + .body("This is the new location!") + .build(), + ) val connection = server.url("/").toUrl().openConnection() val reader = BufferedReader(InputStreamReader(connection!!.getInputStream(), UTF_8)) assertThat(reader.readLine()).isEqualTo("This is the new location!") @@ -203,9 +211,11 @@ class MockWebServerTest { Thread.sleep(1000) } catch (ignored: InterruptedException) { } - server.enqueue(MockResponse.Builder() - .body("enqueued in the background") - .build()) + server.enqueue( + MockResponse.Builder() + .body("enqueued in the background") + .build(), + ) }.start() val connection = server.url("/").toUrl().openConnection() val reader = BufferedReader(InputStreamReader(connection!!.getInputStream(), UTF_8)) @@ -214,11 +224,13 @@ class MockWebServerTest { @Test fun nonHexadecimalChunkSize() { - server.enqueue(MockResponse.Builder() - .body("G\r\nxxxxxxxxxxxxxxxx\r\n0\r\n\r\n") - .clearHeaders() - .addHeader("Transfer-encoding: chunked") - .build()) + server.enqueue( + MockResponse.Builder() + .body("G\r\nxxxxxxxxxxxxxxxx\r\n0\r\n\r\n") + .clearHeaders() + .addHeader("Transfer-encoding: chunked") + .build(), + ) val connection = server.url("/").toUrl().openConnection() try { connection.getInputStream().read() @@ -230,14 +242,18 @@ class MockWebServerTest { @Test fun responseTimeout() { - server.enqueue(MockResponse.Builder() - .body("ABC") - .clearHeaders() - .addHeader("Content-Length: 4") - .build()) - server.enqueue(MockResponse.Builder() - .body("DEF") - .build()) + server.enqueue( + MockResponse.Builder() + .body("ABC") + .clearHeaders() + .addHeader("Content-Length: 4") + .build(), + ) + server.enqueue( + MockResponse.Builder() + .body("DEF") + .build(), + ) val urlConnection = server.url("/").toUrl().openConnection() urlConnection!!.readTimeout = 1000 val inputStream = urlConnection.getInputStream() @@ -263,9 +279,11 @@ class MockWebServerTest { @Disabled("Not actually failing where expected") @Test fun disconnectAtStart() { - server.enqueue(MockResponse.Builder() - .socketPolicy(DisconnectAtStart) - .build()) + server.enqueue( + MockResponse.Builder() + .socketPolicy(DisconnectAtStart) + .build(), + ) server.enqueue(MockResponse()) // The jdk's HttpUrlConnection is a bastard. server.enqueue(MockResponse()) try { @@ -293,9 +311,11 @@ class MockWebServerTest { @Test fun throttleRequest() { assumeNotWindows() - server.enqueue(MockResponse.Builder() - .throttleBody(3, 500, TimeUnit.MILLISECONDS) - .build()) + server.enqueue( + MockResponse.Builder() + .throttleBody(3, 500, TimeUnit.MILLISECONDS) + .build(), + ) val startNanos = System.nanoTime() val connection = server.url("/").toUrl().openConnection() connection.doOutput = true @@ -314,10 +334,12 @@ class MockWebServerTest { @Test fun throttleResponse() { assumeNotWindows() - server.enqueue(MockResponse.Builder() - .body("ABCDEF") - .throttleBody(3, 500, TimeUnit.MILLISECONDS) - .build()) + server.enqueue( + MockResponse.Builder() + .body("ABCDEF") + .throttleBody(3, 500, TimeUnit.MILLISECONDS) + .build(), + ) val startNanos = System.nanoTime() val connection = server.url("/").toUrl().openConnection() val inputStream = connection!!.getInputStream() @@ -337,10 +359,12 @@ class MockWebServerTest { @Test fun delayResponse() { assumeNotWindows() - server.enqueue(MockResponse.Builder() - .body("ABCDEF") - .bodyDelay(1, TimeUnit.SECONDS) - .build()) + server.enqueue( + MockResponse.Builder() + .body("ABCDEF") + .bodyDelay(1, TimeUnit.SECONDS) + .build(), + ) val startNanos = System.nanoTime() val connection = server.url("/").toUrl().openConnection() val inputStream = connection!!.getInputStream() @@ -353,9 +377,11 @@ class MockWebServerTest { @Test fun disconnectRequestHalfway() { - server.enqueue(MockResponse.Builder() - .socketPolicy(DisconnectDuringRequestBody) - .build()) + server.enqueue( + MockResponse.Builder() + .socketPolicy(DisconnectDuringRequestBody) + .build(), + ) // Limit the size of the request body that the server holds in memory to an arbitrary // 3.5 MBytes so this test can pass on devices with little memory. server.bodyLimit = 7 * 512 * 1024 @@ -386,10 +412,12 @@ class MockWebServerTest { @Test fun disconnectResponseHalfway() { - server.enqueue(MockResponse.Builder() - .body("ab") - .socketPolicy(DisconnectDuringResponseBody) - .build()) + server.enqueue( + MockResponse.Builder() + .body("ab") + .socketPolicy(DisconnectDuringResponseBody) + .build(), + ) val connection = server.url("/").toUrl().openConnection() assertThat(connection!!.contentLength).isEqualTo(2) val inputStream = connection.getInputStream() @@ -468,9 +496,11 @@ class MockWebServerTest { @Test fun requestUrlReconstructed() { - server.enqueue(MockResponse.Builder() - .body("hello world") - .build()) + server.enqueue( + MockResponse.Builder() + .body("hello world") + .build(), + ) val url = server.url("/a/deep/path?key=foo%20bar").toUrl() val connection = url.openConnection() as HttpURLConnection val inputStream = connection.inputStream @@ -479,7 +509,8 @@ class MockWebServerTest { assertThat(reader.readLine()).isEqualTo("hello world") val request = server.takeRequest() 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 assertThat(requestUrl!!.scheme).isEqualTo("http") assertThat(requestUrl.host).isEqualTo(server.hostName) @@ -490,9 +521,11 @@ class MockWebServerTest { @Test fun shutdownServerAfterRequest() { - server.enqueue(MockResponse.Builder() - .socketPolicy(ShutdownServerAfterResponse) - .build()) + server.enqueue( + MockResponse.Builder() + .socketPolicy(ShutdownServerAfterResponse) + .build(), + ) val url = server.url("/").toUrl() val connection = url.openConnection() as HttpURLConnection assertThat(connection.responseCode).isEqualTo(HttpURLConnection.HTTP_OK) @@ -506,9 +539,11 @@ class MockWebServerTest { @Test fun http100Continue() { - server.enqueue(MockResponse.Builder() - .body("response") - .build()) + server.enqueue( + MockResponse.Builder() + .body("response") + .build(), + ) val url = server.url("/").toUrl() val connection = url.openConnection() as HttpURLConnection connection.doOutput = true @@ -523,11 +558,13 @@ class MockWebServerTest { @Test fun multiple1xxResponses() { - server.enqueue(MockResponse.Builder() - .add100Continue() - .add100Continue() - .body("response") - .build()) + server.enqueue( + MockResponse.Builder() + .add100Continue() + .add100Continue() + .body("response") + .build(), + ) val url = server.url("/").toUrl() val connection = url.openConnection() as HttpURLConnection connection.doOutput = true @@ -546,8 +583,9 @@ class MockWebServerTest { fail() } catch (expected: IllegalArgumentException) { assertThat(expected.message).isEqualTo( - "protocols containing h2_prior_knowledge cannot use other protocols: " - + "[h2_prior_knowledge, http/1.1]") + "protocols containing h2_prior_knowledge cannot use other protocols: " + + "[h2_prior_knowledge, http/1.1]", + ) } } @@ -559,8 +597,9 @@ class MockWebServerTest { fail() } catch (expected: IllegalArgumentException) { assertThat(expected.message).isEqualTo( - "protocols containing h2_prior_knowledge cannot use other protocols: " - + "[h2_prior_knowledge, h2_prior_knowledge]") + "protocols containing h2_prior_knowledge cannot use other protocols: " + + "[h2_prior_knowledge, h2_prior_knowledge]", + ) } } @@ -575,9 +614,11 @@ class MockWebServerTest { fun https() { val handshakeCertificates = platform.localhostHandshakeCertificates() server.useHttps(handshakeCertificates.sslSocketFactory()) - server.enqueue(MockResponse.Builder() - .body("abc") - .build()) + server.enqueue( + MockResponse.Builder() + .body("abc") + .build(), + ) val url = server.url("/") val connection = url.toUrl().openConnection() as HttpsURLConnection connection.sslSocketFactory = handshakeCertificates.sslSocketFactory() @@ -601,32 +642,40 @@ class MockWebServerTest { platform.assumeNotBouncyCastle() platform.assumeNotConscrypt() - val clientCa = HeldCertificate.Builder() - .certificateAuthority(0) - .build() - val serverCa = HeldCertificate.Builder() - .certificateAuthority(0) - .build() - val serverCertificate = HeldCertificate.Builder() - .signedBy(serverCa) - .addSubjectAlternativeName(server.hostName) - .build() - val serverHandshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(clientCa.certificate) - .heldCertificate(serverCertificate) - .build() + val clientCa = + HeldCertificate.Builder() + .certificateAuthority(0) + .build() + val serverCa = + HeldCertificate.Builder() + .certificateAuthority(0) + .build() + val serverCertificate = + HeldCertificate.Builder() + .signedBy(serverCa) + .addSubjectAlternativeName(server.hostName) + .build() + val serverHandshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(clientCa.certificate) + .heldCertificate(serverCertificate) + .build() server.useHttps(serverHandshakeCertificates.sslSocketFactory()) - server.enqueue(MockResponse.Builder() - .body("abc") - .build()) + server.enqueue( + MockResponse.Builder() + .body("abc") + .build(), + ) server.requestClientAuth() - val clientCertificate = HeldCertificate.Builder() - .signedBy(clientCa) - .build() - val clientHandshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(serverCa.certificate) - .heldCertificate(clientCertificate) - .build() + val clientCertificate = + HeldCertificate.Builder() + .signedBy(clientCa) + .build() + val clientHandshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(serverCa.certificate) + .heldCertificate(clientCertificate) + .build() val url = server.url("/") val connection = url.toUrl().openConnection() as HttpsURLConnection connection.sslSocketFactory = clientHandshakeCertificates.sslSocketFactory() @@ -647,13 +696,16 @@ class MockWebServerTest { @Test fun proxiedRequestGetsCorrectRequestUrl() { - server.enqueue(MockResponse.Builder() - .body("Result") - .build()) - val proxiedClient = OkHttpClient.Builder() - .proxy(server.toProxyAddress()) - .readTimeout(Duration.ofMillis(100)) - .build() + server.enqueue( + MockResponse.Builder() + .body("Result") + .build(), + ) + val proxiedClient = + OkHttpClient.Builder() + .proxy(server.toProxyAddress()) + .readTimeout(Duration.ofMillis(100)) + .build() val request = Request.Builder().url("http://android.com/").build() proxiedClient.newCall(request).execute().use { response -> assertThat(response.body.string()).isEqualTo("Result") diff --git a/mockwebserver/src/test/java/mockwebserver3/RecordedRequestTest.kt b/mockwebserver/src/test/java/mockwebserver3/RecordedRequestTest.kt index e2120f7446df..9b6a24cf082e 100644 --- a/mockwebserver/src/test/java/mockwebserver3/RecordedRequestTest.kt +++ b/mockwebserver/src/test/java/mockwebserver3/RecordedRequestTest.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package mockwebserver3 import assertk.assertThat @@ -32,44 +33,50 @@ class RecordedRequestTest { private val headers: Headers = EMPTY_HEADERS @Test fun testIPv4() { - val socket = FakeSocket( - localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)), - localPort = 80 - ) + val socket = + FakeSocket( + localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)), + localPort = 80, + ) val request = RecordedRequest("GET / HTTP/1.1", headers, emptyList(), 0, Buffer(), 0, socket) assertThat(request.requestUrl.toString()).isEqualTo("http://127.0.0.1/") } @Test fun testIpv6() { - val socket = FakeSocket( - localAddress = InetAddress.getByAddress( - "::1", - byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1) - ), - localPort = 80 - ) + val socket = + FakeSocket( + localAddress = + InetAddress.getByAddress( + "::1", + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), + ), + localPort = 80, + ) val request = RecordedRequest("GET / HTTP/1.1", headers, emptyList(), 0, Buffer(), 0, socket) assertThat(request.requestUrl.toString()).isEqualTo("http://[::1]/") } @Test fun testUsesLocal() { - val socket = FakeSocket( - localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)), - localPort = 80 - ) + val socket = + FakeSocket( + localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)), + localPort = 80, + ) val request = RecordedRequest("GET / HTTP/1.1", headers, emptyList(), 0, Buffer(), 0, socket) assertThat(request.requestUrl.toString()).isEqualTo("http://127.0.0.1/") } @Test fun testHostname() { val headers = headersOf("Host", "host-from-header.com") - val socket = FakeSocket( - localAddress = InetAddress.getByAddress( - "host-from-address.com", - byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1) - ), - localPort = 80 - ) + val socket = + FakeSocket( + localAddress = + InetAddress.getByAddress( + "host-from-address.com", + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), + ), + localPort = 80, + ) val request = RecordedRequest("GET / HTTP/1.1", headers, emptyList(), 0, Buffer(), 0, socket) assertThat(request.requestUrl.toString()).isEqualTo("http://host-from-header.com/") } @@ -78,11 +85,14 @@ class RecordedRequestTest { private val localAddress: InetAddress, private val localPort: Int, private val remoteAddress: InetAddress = localAddress, - private val remotePort: Int = 1234 + private val remotePort: Int = 1234, ) : Socket() { override fun getInetAddress() = remoteAddress + override fun getLocalAddress() = localAddress + override fun getLocalPort() = localPort + override fun getPort() = remotePort } } diff --git a/mockwebserver/src/test/java/mockwebserver3/internal/http2/Http2Server.kt b/mockwebserver/src/test/java/mockwebserver3/internal/http2/Http2Server.kt index c6016ac4f3aa..007af924d9d3 100644 --- a/mockwebserver/src/test/java/mockwebserver3/internal/http2/Http2Server.kt +++ b/mockwebserver/src/test/java/mockwebserver3/internal/http2/Http2Server.kt @@ -39,7 +39,7 @@ import okio.source /** A basic HTTP/2 server that serves the contents of a local directory. */ class Http2Server( private val baseDirectory: File, - private val sslSocketFactory: SSLSocketFactory + private val sslSocketFactory: SSLSocketFactory, ) : Http2Connection.Listener() { private fun run() { val serverSocket = ServerSocket(8888) @@ -54,10 +54,11 @@ class Http2Server( if (protocol != Protocol.HTTP_2) { throw ProtocolException("Protocol $protocol unsupported") } - val connection = Http2Connection.Builder(false, TaskRunner.INSTANCE) - .socket(sslSocket) - .listener(this) - .build() + val connection = + Http2Connection.Builder(false, TaskRunner.INSTANCE) + .socket(sslSocket) + .listener(this) + .build() connection.start() } catch (e: IOException) { logger.log(Level.INFO, "Http2Server connection failure: $e") @@ -70,11 +71,13 @@ class Http2Server( } private fun doSsl(socket: Socket): SSLSocket { - val sslSocket = sslSocketFactory.createSocket( - socket, socket.inetAddress.hostAddress, - socket.port, - true - ) as SSLSocket + val sslSocket = + sslSocketFactory.createSocket( + socket, + socket.inetAddress.hostAddress, + socket.port, + true, + ) as SSLSocket sslSocket.useClientMode = false Platform.get().configureTlsExtensions(sslSocket, null, listOf(Protocol.HTTP_2)) sslSocket.startHandshake() @@ -111,32 +114,40 @@ class Http2Server( } } - private fun send404(stream: Http2Stream, path: String) { - val responseHeaders = listOf( - Header(":status", "404"), - Header(":version", "HTTP/1.1"), - Header("content-type", "text/plain") - ) + private fun send404( + stream: Http2Stream, + path: String, + ) { + val responseHeaders = + listOf( + Header(":status", "404"), + Header(":version", "HTTP/1.1"), + Header("content-type", "text/plain"), + ) stream.writeHeaders( responseHeaders = responseHeaders, outFinished = false, - flushHeaders = false + flushHeaders = false, ) val out = stream.getSink().buffer() out.writeUtf8("Not found: $path") out.close() } - private fun serveDirectory(stream: Http2Stream, files: Array) { - val responseHeaders = listOf( - Header(":status", "200"), - Header(":version", "HTTP/1.1"), - Header("content-type", "text/html; charset=UTF-8") - ) + private fun serveDirectory( + stream: Http2Stream, + files: Array, + ) { + val responseHeaders = + listOf( + Header(":status", "200"), + Header(":version", "HTTP/1.1"), + Header("content-type", "text/html; charset=UTF-8"), + ) stream.writeHeaders( responseHeaders = responseHeaders, outFinished = false, - flushHeaders = false + flushHeaders = false, ) val out = stream.getSink().buffer() for (file in files) { @@ -146,16 +157,20 @@ class Http2Server( out.close() } - private fun serveFile(stream: Http2Stream, file: File) { - val responseHeaders = listOf( - Header(":status", "200"), - Header(":version", "HTTP/1.1"), - Header("content-type", contentType(file)) - ) + private fun serveFile( + stream: Http2Stream, + file: File, + ) { + val responseHeaders = + listOf( + Header(":status", "200"), + Header(":version", "HTTP/1.1"), + Header("content-type", contentType(file)), + ) stream.writeHeaders( responseHeaders = responseHeaders, outFinished = false, - flushHeaders = false + flushHeaders = false, ) file.source().use { source -> stream.getSink().buffer().use { sink -> @@ -186,10 +201,11 @@ class Http2Server( println("Usage: Http2Server ") return } - val server = Http2Server( - File(args[0]), - localhost().sslContext().socketFactory - ) + val server = + Http2Server( + File(args[0]), + localhost().sslContext().socketFactory, + ) server.run() } } diff --git a/native-image-tests/src/main/kotlin/okhttp3/DotListener.kt b/native-image-tests/src/main/kotlin/okhttp3/DotListener.kt index 7124e455c91f..ed1bb03a3b77 100644 --- a/native-image-tests/src/main/kotlin/okhttp3/DotListener.kt +++ b/native-image-tests/src/main/kotlin/okhttp3/DotListener.kt @@ -15,19 +15,22 @@ */ package okhttp3 +import java.io.OutputStream +import java.io.PrintStream import org.junit.platform.engine.TestExecutionResult import org.junit.platform.launcher.TestExecutionListener import org.junit.platform.launcher.TestIdentifier import org.junit.platform.launcher.TestPlan -import java.io.OutputStream -import java.io.PrintStream -object DotListener: TestExecutionListener { +object DotListener : TestExecutionListener { private var originalSystemErr: PrintStream? = null private var originalSystemOut: PrintStream? = null private var testCount = 0 - override fun executionSkipped(testIdentifier: TestIdentifier, reason: String) { + override fun executionSkipped( + testIdentifier: TestIdentifier, + reason: String, + ) { printStatus("-") } @@ -40,7 +43,7 @@ object DotListener: TestExecutionListener { override fun executionFinished( testIdentifier: TestIdentifier, - testExecutionResult: TestExecutionResult + testExecutionResult: TestExecutionResult, ) { if (!testIdentifier.isContainer) { when (testExecutionResult.status!!) { @@ -59,8 +62,8 @@ object DotListener: TestExecutionListener { originalSystemOut = System.out originalSystemErr = System.err - System.setOut(object: PrintStream(OutputStream.nullOutputStream()) {}) - System.setErr(object: PrintStream(OutputStream.nullOutputStream()) {}) + System.setOut(object : PrintStream(OutputStream.nullOutputStream()) {}) + System.setErr(object : PrintStream(OutputStream.nullOutputStream()) {}) } fun uninstall() { @@ -71,4 +74,4 @@ object DotListener: TestExecutionListener { System.setErr(it) } } -} \ No newline at end of file +} diff --git a/native-image-tests/src/main/kotlin/okhttp3/GenerateClassList.kt b/native-image-tests/src/main/kotlin/okhttp3/GenerateClassList.kt index f18ae68f0653..109a2cd3828e 100644 --- a/native-image-tests/src/main/kotlin/okhttp3/GenerateClassList.kt +++ b/native-image-tests/src/main/kotlin/okhttp3/GenerateClassList.kt @@ -15,26 +15,27 @@ */ package okhttp3 +import java.io.File import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor import org.junit.platform.engine.discovery.DiscoverySelectors -import java.io.File // TODO move to junit5 tags -val avoidedTests = setOf( - "okhttp3.BouncyCastleTest", - "okhttp3.ConscryptTest", - "okhttp3.CorrettoTest", - "okhttp3.OpenJSSETest", - "okhttp3.internal.platform.Jdk8WithJettyBootPlatformTest", - "okhttp3.internal.platform.Jdk9PlatformTest", - "okhttp3.internal.platform.PlatformTest", - "okhttp3.internal.platform.android.AndroidSocketAdapterTest", - "okhttp3.osgi.OsgiTest", - // Hanging. - "okhttp3.CookiesTest", - // Hanging. - "okhttp3.WholeOperationTimeoutTest", -) +val avoidedTests = + setOf( + "okhttp3.BouncyCastleTest", + "okhttp3.ConscryptTest", + "okhttp3.CorrettoTest", + "okhttp3.OpenJSSETest", + "okhttp3.internal.platform.Jdk8WithJettyBootPlatformTest", + "okhttp3.internal.platform.Jdk9PlatformTest", + "okhttp3.internal.platform.PlatformTest", + "okhttp3.internal.platform.android.AndroidSocketAdapterTest", + "okhttp3.osgi.OsgiTest", + // Hanging. + "okhttp3.CookiesTest", + // Hanging. + "okhttp3.WholeOperationTimeoutTest", + ) /** * Run periodically to refresh the known set of working tests. @@ -44,11 +45,12 @@ val avoidedTests = setOf( fun main() { val knownTestFile = File("native-image-tests/src/main/resources/testlist.txt") val testSelector = DiscoverySelectors.selectPackage("okhttp3") - val testClasses = findTests(listOf(testSelector)) - .filter { it.isContainer } - .mapNotNull { (it as? ClassBasedTestDescriptor)?.testClass?.name } - .filterNot { it in avoidedTests } - .sorted() - .distinct() + val testClasses = + findTests(listOf(testSelector)) + .filter { it.isContainer } + .mapNotNull { (it as? ClassBasedTestDescriptor)?.testClass?.name } + .filterNot { it in avoidedTests } + .sorted() + .distinct() knownTestFile.writeText(testClasses.joinToString("\n")) } diff --git a/native-image-tests/src/main/kotlin/okhttp3/RunTests.kt b/native-image-tests/src/main/kotlin/okhttp3/RunTests.kt index 3c4985798aed..4fdd4c6b9651 100644 --- a/native-image-tests/src/main/kotlin/okhttp3/RunTests.kt +++ b/native-image-tests/src/main/kotlin/okhttp3/RunTests.kt @@ -15,6 +15,9 @@ */ package okhttp3 +import java.io.File +import java.io.PrintWriter +import kotlin.system.exitProcess import org.junit.jupiter.engine.JupiterTestEngine import org.junit.platform.console.options.Theme import org.junit.platform.engine.DiscoverySelector @@ -30,9 +33,6 @@ import org.junit.platform.launcher.core.LauncherConfig import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder import org.junit.platform.launcher.core.LauncherFactory import org.junit.platform.launcher.listeners.SummaryGeneratingListener -import java.io.File -import java.io.PrintWriter -import kotlin.system.exitProcess /** * Graal main method to run tests with minimal reflection and automatic settings. @@ -49,13 +49,14 @@ fun main(vararg args: String) { val jupiterTestEngine = buildTestEngine() - val config = LauncherConfig.builder() - .enableTestExecutionListenerAutoRegistration(false) - .enableTestEngineAutoRegistration(false) - .enablePostDiscoveryFilterAutoRegistration(false) - .addTestEngines(jupiterTestEngine) - .addTestExecutionListeners(DotListener, summaryListener, treeListener) - .build() + val config = + LauncherConfig.builder() + .enableTestExecutionListenerAutoRegistration(false) + .enableTestEngineAutoRegistration(false) + .enablePostDiscoveryFilterAutoRegistration(false) + .addTestEngines(jupiterTestEngine) + .addTestExecutionListeners(DotListener, summaryListener, treeListener) + .build() val launcher: Launcher = LauncherFactory.create(config) val request: LauncherDiscoveryRequest = buildRequest(selectors) @@ -89,8 +90,9 @@ fun testSelectors(inputFile: File? = null): List { val lines = inputFile?.readLines() ?: sampleTestClass.getResource("/testlist.txt").readText().lines() - val flatClassnameList = lines - .filter { it.isNotBlank() } + val flatClassnameList = + lines + .filter { it.isNotBlank() } return flatClassnameList .mapNotNull { @@ -107,11 +109,12 @@ fun testSelectors(inputFile: File? = null): List { * Builds a Junit Test Plan request for a fixed set of classes, or potentially a recursive package. */ fun buildRequest(selectors: List): LauncherDiscoveryRequest { - val request: LauncherDiscoveryRequest = LauncherDiscoveryRequestBuilder.request() - // TODO replace junit.jupiter.extensions.autodetection.enabled with API approach. + val request: LauncherDiscoveryRequest = + LauncherDiscoveryRequestBuilder.request() + // TODO replace junit.jupiter.extensions.autodetection.enabled with API approach. // .enableImplicitConfigurationParameters(false) - .selectors(selectors) - .build() + .selectors(selectors) + .build() return request } @@ -136,11 +139,13 @@ fun findTests(selectors: List): List { * https://github.com/junit-team/junit5/issues/2469 */ fun treeListener(): TestExecutionListener { - val colorPalette = Class.forName("org.junit.platform.console.tasks.ColorPalette").getField("DEFAULT").apply { - isAccessible = true - }.get(null) + val colorPalette = + Class.forName("org.junit.platform.console.tasks.ColorPalette").getField("DEFAULT").apply { + isAccessible = true + }.get(null) return Class.forName( - "org.junit.platform.console.tasks.TreePrintingListener").declaredConstructors.first() + "org.junit.platform.console.tasks.TreePrintingListener", + ).declaredConstructors.first() .apply { isAccessible = true } diff --git a/native-image-tests/src/main/kotlin/okhttp3/SampleTest.kt b/native-image-tests/src/main/kotlin/okhttp3/SampleTest.kt index ee0a2c49a6b5..73c07198e738 100644 --- a/native-image-tests/src/main/kotlin/okhttp3/SampleTest.kt +++ b/native-image-tests/src/main/kotlin/okhttp3/SampleTest.kt @@ -26,7 +26,8 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ArgumentsSource class SampleTest { - @JvmField @RegisterExtension val clientRule = OkHttpClientTestRule() + @JvmField @RegisterExtension + val clientRule = OkHttpClientTestRule() @Test fun passingTest() { @@ -59,6 +60,6 @@ class SampleTest { } } -class SampleTestProvider: SimpleProvider() { +class SampleTestProvider : SimpleProvider() { override fun arguments() = listOf("A", "B") } diff --git a/native-image-tests/src/main/kotlin/okhttp3/TestRegistration.kt b/native-image-tests/src/main/kotlin/okhttp3/TestRegistration.kt index 484426e1c05c..0f882d4be118 100644 --- a/native-image-tests/src/main/kotlin/okhttp3/TestRegistration.kt +++ b/native-image-tests/src/main/kotlin/okhttp3/TestRegistration.kt @@ -16,11 +16,11 @@ package okhttp3 import com.oracle.svm.core.annotate.AutomaticFeature +import java.io.File +import java.lang.IllegalStateException import org.graalvm.nativeimage.hosted.Feature import org.graalvm.nativeimage.hosted.RuntimeClassInitialization import org.graalvm.nativeimage.hosted.RuntimeReflection -import java.io.File -import java.lang.IllegalStateException @AutomaticFeature class TestRegistration : Feature { @@ -40,7 +40,10 @@ class TestRegistration : Feature { registerParamProvider(access, "okhttp3.WebPlatformUrlTest\$TestDataParamProvider") } - private fun registerParamProvider(access: Feature.BeforeAnalysisAccess, provider: String) { + private fun registerParamProvider( + access: Feature.BeforeAnalysisAccess, + provider: String, + ) { val providerClass = access.findClassByName(provider) if (providerClass != null) { registerTest(access, providerClass) @@ -54,7 +57,10 @@ class TestRegistration : Feature { registerStandardClass(access, "org.junit.platform.console.tasks.TreePrintingListener") } - private fun registerStandardClass(access: Feature.BeforeAnalysisAccess, name: String) { + private fun registerStandardClass( + access: Feature.BeforeAnalysisAccess, + name: String, + ) { val clazz: Class<*> = access.findClassByName(name) ?: throw IllegalStateException("Missing class $name") RuntimeReflection.register(clazz) clazz.declaredConstructors.forEach { @@ -81,7 +87,10 @@ class TestRegistration : Feature { } } - private fun registerTest(access: Feature.BeforeAnalysisAccess, java: Class<*>) { + private fun registerTest( + access: Feature.BeforeAnalysisAccess, + java: Class<*>, + ) { access.registerAsUsed(java) RuntimeReflection.register(java) java.constructors.forEach { diff --git a/native-image-tests/src/test/kotlin/okhttp3/nativeImage/NativeImageTestsTest.kt b/native-image-tests/src/test/kotlin/okhttp3/nativeImage/NativeImageTestsTest.kt index a4ebf3027e96..6ba5f223e5f7 100644 --- a/native-image-tests/src/test/kotlin/okhttp3/nativeImage/NativeImageTestsTest.kt +++ b/native-image-tests/src/test/kotlin/okhttp3/nativeImage/NativeImageTestsTest.kt @@ -55,4 +55,4 @@ class NativeImageTestsTest { assertNotNull(listener) } -} \ No newline at end of file +} diff --git a/okcurl/src/main/kotlin/okhttp3/curl/Main.kt b/okcurl/src/main/kotlin/okhttp3/curl/Main.kt index b3e4334e7886..126af4c31dbb 100644 --- a/okcurl/src/main/kotlin/okhttp3/curl/Main.kt +++ b/okcurl/src/main/kotlin/okhttp3/curl/Main.kt @@ -40,35 +40,41 @@ import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.LoggingEventListener class Main : CliktCommand(name = NAME, help = "A curl for the next-generation web.") { - val method: String? by option("-X", "--request", help="Specify request command to use") + val method: String? by option("-X", "--request", help = "Specify request command to use") - val data: String? by option("-d", "--data", help="HTTP POST data") + val data: String? by option("-d", "--data", help = "HTTP POST data") - val headers: List? by option("-H", "--header", help="Custom header to pass to server").multiple() + val headers: List? by option("-H", "--header", help = "Custom header to pass to server").multiple() - val userAgent: String by option("-A", "--user-agent", help="User-Agent to send to server").default(NAME + "/" + versionString()) + val userAgent: String by option("-A", "--user-agent", help = "User-Agent to send to server").default(NAME + "/" + versionString()) - val connectTimeout: Int by option("--connect-timeout", help="Maximum time allowed for connection (seconds)").int().default(DEFAULT_TIMEOUT) + val connectTimeout: Int by option( + "--connect-timeout", + help = "Maximum time allowed for connection (seconds)", + ).int().default(DEFAULT_TIMEOUT) - val readTimeout: Int by option("--read-timeout", help="Maximum time allowed for reading data (seconds)").int().default(DEFAULT_TIMEOUT) + val readTimeout: Int by option("--read-timeout", help = "Maximum time allowed for reading data (seconds)").int().default(DEFAULT_TIMEOUT) - val callTimeout: Int by option("--call-timeout", help="Maximum time allowed for the entire call (seconds)").int().default(DEFAULT_TIMEOUT) + val callTimeout: Int by option( + "--call-timeout", + help = "Maximum time allowed for the entire call (seconds)", + ).int().default(DEFAULT_TIMEOUT) - val followRedirects: Boolean by option("-L", "--location", help="Follow redirects").flag() + val followRedirects: Boolean by option("-L", "--location", help = "Follow redirects").flag() - val allowInsecure: Boolean by option("-k", "--insecure", help="Allow connections to SSL sites without certs").flag() + val allowInsecure: Boolean by option("-k", "--insecure", help = "Allow connections to SSL sites without certs").flag() - val showHeaders: Boolean by option("-i", "--include", help="Include protocol headers in the output").flag() + val showHeaders: Boolean by option("-i", "--include", help = "Include protocol headers in the output").flag() - val showHttp2Frames: Boolean by option("--frames", help="Log HTTP/2 frames to STDERR").flag() + val showHttp2Frames: Boolean by option("--frames", help = "Log HTTP/2 frames to STDERR").flag() - val referer: String? by option("-e", "--referer", help="Referer URL") + val referer: String? by option("-e", "--referer", help = "Referer URL") - val verbose: Boolean by option("-v", "--verbose", help="Makes $NAME verbose during the operation").flag() + val verbose: Boolean by option("-v", "--verbose", help = "Makes $NAME verbose during the operation").flag() - val sslDebug: Boolean by option(help="Output SSL Debug").flag() + val sslDebug: Boolean by option(help = "Output SSL Debug").flag() - val url: String? by argument(name = "url", help="Remote resource URL") + val url: String? by argument(name = "url", help = "Remote resource URL") var client: Call.Factory? = null @@ -123,20 +129,26 @@ class Main : CliktCommand(name = NAME, help = "A curl for the next-generation we return prop.getProperty("version", "dev") } - private fun createInsecureTrustManager(): X509TrustManager = object : X509TrustManager { - override fun checkClientTrusted(chain: Array, authType: String) {} + private fun createInsecureTrustManager(): X509TrustManager = + object : X509TrustManager { + override fun checkClientTrusted( + chain: Array, + authType: String, + ) {} - override fun checkServerTrusted(chain: Array, authType: String) {} + override fun checkServerTrusted( + chain: Array, + authType: String, + ) {} - override fun getAcceptedIssuers(): Array = arrayOf() - } + override fun getAcceptedIssuers(): Array = arrayOf() + } private fun createInsecureSslSocketFactory(trustManager: TrustManager): SSLSocketFactory = - Platform.get().newSSLContext().apply { - init(null, arrayOf(trustManager), null) - }.socketFactory + Platform.get().newSSLContext().apply { + init(null, arrayOf(trustManager), null) + }.socketFactory - private fun createInsecureHostnameVerifier(): HostnameVerifier = - HostnameVerifier { _, _ -> true } + private fun createInsecureHostnameVerifier(): HostnameVerifier = HostnameVerifier { _, _ -> true } } } diff --git a/okcurl/src/main/kotlin/okhttp3/curl/internal/-MainCommon.kt b/okcurl/src/main/kotlin/okhttp3/curl/internal/-MainCommon.kt index a2a36415ad08..20b22b37cc16 100644 --- a/okcurl/src/main/kotlin/okhttp3/curl/internal/-MainCommon.kt +++ b/okcurl/src/main/kotlin/okhttp3/curl/internal/-MainCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.curl.internal import java.io.IOException @@ -53,15 +54,16 @@ internal fun Main.commonCreateRequest(): Request { } private fun Main.mediaType(): MediaType? { - val mimeType = headers?.let { - for (header in it) { - val parts = header.split(':', limit = 2) - if ("Content-Type".equals(parts[0], ignoreCase = true)) { - return@let parts[1].trim() + val mimeType = + headers?.let { + for (header in it) { + val parts = header.split(':', limit = 2) + if ("Content-Type".equals(parts[0], ignoreCase = true)) { + return@let parts[1].trim() + } } - } - return@let null - } ?: "application/x-www-form-urlencoded" + return@let null + } ?: "application/x-www-form-urlencoded" return mimeType.toMediaTypeOrNull() } diff --git a/okcurl/src/main/kotlin/okhttp3/curl/logging/LoggingUtil.kt b/okcurl/src/main/kotlin/okhttp3/curl/logging/LoggingUtil.kt index d44c6e508186..53ccc96334c5 100644 --- a/okcurl/src/main/kotlin/okhttp3/curl/logging/LoggingUtil.kt +++ b/okcurl/src/main/kotlin/okhttp3/curl/logging/LoggingUtil.kt @@ -1,32 +1,37 @@ package okhttp3.curl.logging -import okhttp3.internal.http2.Http2 import java.util.logging.ConsoleHandler import java.util.logging.Level import java.util.logging.LogManager import java.util.logging.LogRecord import java.util.logging.Logger +import okhttp3.internal.http2.Http2 class LoggingUtil { companion object { private val activeLoggers = mutableListOf() - fun configureLogging(debug: Boolean, showHttp2Frames: Boolean, sslDebug: Boolean) { + fun configureLogging( + debug: Boolean, + showHttp2Frames: Boolean, + sslDebug: Boolean, + ) { if (debug || showHttp2Frames || sslDebug) { if (sslDebug) { System.setProperty("javax.net.debug", "") } LogManager.getLogManager().reset() - val handler = object : ConsoleHandler() { - override fun publish(record: LogRecord) { - super.publish(record) + val handler = + object : ConsoleHandler() { + override fun publish(record: LogRecord) { + super.publish(record) - val parameters = record.parameters - if (sslDebug && record.loggerName == "javax.net.ssl" && parameters != null) { - System.err.println(parameters[0]) + val parameters = record.parameters + if (sslDebug && record.loggerName == "javax.net.ssl" && parameters != null) { + System.err.println(parameters[0]) + } } } - } if (debug) { handler.level = Level.ALL diff --git a/okcurl/src/main/kotlin/okhttp3/curl/logging/OneLineLogFormat.kt b/okcurl/src/main/kotlin/okhttp3/curl/logging/OneLineLogFormat.kt index 03924805f309..61c1749a2a1d 100644 --- a/okcurl/src/main/kotlin/okhttp3/curl/logging/OneLineLogFormat.kt +++ b/okcurl/src/main/kotlin/okhttp3/curl/logging/OneLineLogFormat.kt @@ -19,16 +19,17 @@ import java.util.logging.LogRecord * Why so much construction? */ class OneLineLogFormat : Formatter() { - private val d = DateTimeFormatterBuilder() - .appendValue(HOUR_OF_DAY, 2) - .appendLiteral(':') - .appendValue(MINUTE_OF_HOUR, 2) - .optionalStart() - .appendLiteral(':') - .appendValue(SECOND_OF_MINUTE, 2) - .optionalStart() - .appendFraction(NANO_OF_SECOND, 3, 3, true) - .toFormatter() + private val d = + DateTimeFormatterBuilder() + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .optionalStart() + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .optionalStart() + .appendFraction(NANO_OF_SECOND, 3, 3, true) + .toFormatter() private val offset = ZoneOffset.systemDefault() diff --git a/okcurl/src/test/kotlin/okhttp3/curl/MainTest.kt b/okcurl/src/test/kotlin/okhttp3/curl/MainTest.kt index 6acb23c37704..0a2598a2e694 100644 --- a/okcurl/src/test/kotlin/okhttp3/curl/MainTest.kt +++ b/okcurl/src/test/kotlin/okhttp3/curl/MainTest.kt @@ -15,14 +15,14 @@ */ package okhttp3.curl -import java.io.IOException -import okhttp3.RequestBody -import okio.Buffer import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isNull import assertk.assertions.startsWith +import java.io.IOException import kotlin.test.Test +import okhttp3.RequestBody +import okio.Buffer class MainTest { @Test @@ -34,7 +34,8 @@ class MainTest { } @Test - @Throws(IOException::class) fun put() { + @Throws(IOException::class) + fun put() { val request = fromArgs("-X", "PUT", "-d", "foo", "http://example.com").createRequest() assertThat(request.method).isEqualTo("PUT") assertThat(request.url.toString()).isEqualTo("http://example.com/") @@ -48,7 +49,7 @@ class MainTest { assertThat(request.method).isEqualTo("POST") assertThat(request.url.toString()).isEqualTo("http://example.com/") assertThat(body!!.contentType().toString()).isEqualTo( - "application/x-www-form-urlencoded; charset=utf-8" + "application/x-www-form-urlencoded; charset=utf-8", ) assertThat(bodyAsString(body)).isEqualTo("foo") } @@ -60,17 +61,21 @@ class MainTest { assertThat(request.method).isEqualTo("PUT") assertThat(request.url.toString()).isEqualTo("http://example.com/") assertThat(body!!.contentType().toString()).isEqualTo( - "application/x-www-form-urlencoded; charset=utf-8" + "application/x-www-form-urlencoded; charset=utf-8", ) assertThat(bodyAsString(body)).isEqualTo("foo") } @Test fun contentTypeHeader() { - val request = fromArgs( - "-d", "foo", "-H", "Content-Type: application/json", - "http://example.com" - ).createRequest() + val request = + fromArgs( + "-d", + "foo", + "-H", + "Content-Type: application/json", + "http://example.com", + ).createRequest() val body = request.body assertThat(request.method).isEqualTo("POST") assertThat(request.url.toString()).isEqualTo("http://example.com/") @@ -105,12 +110,14 @@ class MainTest { @Test fun headerSplitWithDate() { - val request = fromArgs( - "-H", "If-Modified-Since: Mon, 18 Aug 2014 15:16:06 GMT", - "http://example.com" - ).createRequest() + val request = + fromArgs( + "-H", + "If-Modified-Since: Mon, 18 Aug 2014 15:16:06 GMT", + "http://example.com", + ).createRequest() assertThat(request.header("If-Modified-Since")).isEqualTo( - "Mon, 18 Aug 2014 15:16:06 GMT" + "Mon, 18 Aug 2014 15:16:06 GMT", ) } diff --git a/okhttp-android/src/androidTest/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt b/okhttp-android/src/androidTest/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt index 0f540ee8f26f..22a17ad11690 100644 --- a/okhttp-android/src/androidTest/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt +++ b/okhttp-android/src/androidTest/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt @@ -50,14 +50,16 @@ import org.junit.Test * Run with "./gradlew :android-test:connectedCheck -PandroidBuild=true" and make sure ANDROID_SDK_ROOT is set. */ class AndroidAsyncDnsTest { - @JvmField @Rule val serverRule = MockWebServerRule() + @JvmField @Rule + val serverRule = MockWebServerRule() private lateinit var client: OkHttpClient private val localhost: HandshakeCertificates by lazy { // Generate a self-signed cert for the server to serve and the client to trust. - val heldCertificate = HeldCertificate.Builder() - .addSubjectAlternativeName("localhost") - .build() + val heldCertificate = + HeldCertificate.Builder() + .addSubjectAlternativeName("localhost") + .build() return@lazy HandshakeCertificates.Builder() .addPlatformTrustedCertificates() .heldCertificate(heldCertificate) @@ -69,10 +71,11 @@ class AndroidAsyncDnsTest { fun init() { assumeTrue("Supported on API 29+", Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) - client = OkHttpClient.Builder() - .dns(AsyncDns.toDns(AndroidAsyncDns.IPv4, AndroidAsyncDns.IPv6)) - .sslSocketFactory(localhost.sslSocketFactory(), localhost.trustManager) - .build() + client = + OkHttpClient.Builder() + .dns(AsyncDns.toDns(AndroidAsyncDns.IPv4, AndroidAsyncDns.IPv6)) + .sslSocketFactory(localhost.sslSocketFactory(), localhost.trustManager) + .build() serverRule.server.useHttps(localhost.sslSocketFactory()) } @@ -127,17 +130,26 @@ class AndroidAsyncDnsTest { val latch = CountDownLatch(1) // assumes an IPv4 address - AndroidAsyncDns.IPv4.query(hostname, object : AsyncDns.Callback { - override fun onResponse(hostname: String, addresses: List) { - allAddresses.addAll(addresses) - latch.countDown() - } - - override fun onFailure(hostname: String, e: IOException) { - exception = e - latch.countDown() - } - }) + AndroidAsyncDns.IPv4.query( + hostname, + object : AsyncDns.Callback { + override fun onResponse( + hostname: String, + addresses: List, + ) { + allAddresses.addAll(addresses) + latch.countDown() + } + + override fun onFailure( + hostname: String, + e: IOException, + ) { + exception = e + latch.countDown() + } + }, + ) latch.await() @@ -173,10 +185,11 @@ class AndroidAsyncDnsTest { val network = connectivityManager.activeNetwork ?: throw AssumptionViolatedException("No active network") - val client = OkHttpClient.Builder() - .dns(AsyncDns.toDns(AndroidAsyncDns.IPv4, AndroidAsyncDns.IPv6)) - .socketFactory(network.socketFactory) - .build() + val client = + OkHttpClient.Builder() + .dns(AsyncDns.toDns(AndroidAsyncDns.IPv4, AndroidAsyncDns.IPv6)) + .socketFactory(network.socketFactory) + .build() val call = client.newCall(Request("https://google.com/robots.txt".toHttpUrl())) diff --git a/okhttp-android/src/main/kotlin/okhttp3/android/AndroidAsyncDns.kt b/okhttp-android/src/main/kotlin/okhttp3/android/AndroidAsyncDns.kt index ff7eb63cf906..14896be59e8b 100644 --- a/okhttp-android/src/main/kotlin/okhttp3/android/AndroidAsyncDns.kt +++ b/okhttp-android/src/main/kotlin/okhttp3/android/AndroidAsyncDns.kt @@ -43,20 +43,34 @@ class AndroidAsyncDns( private val resolver = DnsResolver.getInstance() private val executor = Executors.newSingleThreadExecutor() - override fun query(hostname: String, callback: AsyncDns.Callback) { + override fun query( + hostname: String, + callback: AsyncDns.Callback, + ) { resolver.query( - network, hostname, dnsClass.type, DnsResolver.FLAG_EMPTY, executor, null, + network, + hostname, + dnsClass.type, + DnsResolver.FLAG_EMPTY, + executor, + null, object : DnsResolver.Callback> { - override fun onAnswer(addresses: List, rCode: Int) { + override fun onAnswer( + addresses: List, + rCode: Int, + ) { callback.onResponse(hostname, addresses) } override fun onError(e: DnsResolver.DnsException) { - callback.onFailure(hostname, UnknownHostException(e.message).apply { - initCause(e) - }) + callback.onFailure( + hostname, + UnknownHostException(e.message).apply { + initCause(e) + }, + ) } - } + }, ) } diff --git a/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt b/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt index 7308a612e554..137c27fa7ed6 100644 --- a/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt +++ b/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt @@ -43,16 +43,16 @@ import org.robolectric.annotation.Config sdk = [30], ) class RobolectricOkHttpClientTest { - private lateinit var context: Context private lateinit var client: OkHttpClient @Before fun setUp() { context = ApplicationProvider.getApplicationContext() - client = OkHttpClient.Builder() - .cache(Cache("/cache".toPath(), 10_000_000, FakeFileSystem())) - .build() + client = + OkHttpClient.Builder() + .cache(Cache("/cache".toPath(), 10_000_000, FakeFileSystem())) + .build() } @Test @@ -61,8 +61,9 @@ class RobolectricOkHttpClientTest { val request = Request("https://www.google.com/robots.txt".toHttpUrl()) - val networkRequest = request.newBuilder() - .build() + val networkRequest = + request.newBuilder() + .build() val call = client.newCall(networkRequest) diff --git a/okhttp-brotli/src/main/kotlin/okhttp3/brotli/BrotliInterceptor.kt b/okhttp-brotli/src/main/kotlin/okhttp3/brotli/BrotliInterceptor.kt index d5b0a5f813ef..758e926525cd 100644 --- a/okhttp-brotli/src/main/kotlin/okhttp3/brotli/BrotliInterceptor.kt +++ b/okhttp-brotli/src/main/kotlin/okhttp3/brotli/BrotliInterceptor.kt @@ -28,9 +28,10 @@ import okhttp3.brotli.internal.uncompress object BrotliInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { return if (chain.request().header("Accept-Encoding") == null) { - val request = chain.request().newBuilder() - .header("Accept-Encoding", "br,gzip") - .build() + val request = + chain.request().newBuilder() + .header("Accept-Encoding", "br,gzip") + .build() val response = chain.proceed(request) diff --git a/okhttp-brotli/src/main/kotlin/okhttp3/brotli/internal/Uncompress.kt b/okhttp-brotli/src/main/kotlin/okhttp3/brotli/internal/Uncompress.kt index 6765ca0fa125..11b4d0f33878 100644 --- a/okhttp-brotli/src/main/kotlin/okhttp3/brotli/internal/Uncompress.kt +++ b/okhttp-brotli/src/main/kotlin/okhttp3/brotli/internal/Uncompress.kt @@ -30,13 +30,14 @@ fun uncompress(response: Response): Response { val body = response.body val encoding = response.header("Content-Encoding") ?: return response - val decompressedSource = when { - encoding.equals("br", ignoreCase = true) -> - BrotliInputStream(body.source().inputStream()).source().buffer() - encoding.equals("gzip", ignoreCase = true) -> - GzipSource(body.source()).buffer() - else -> return response - } + val decompressedSource = + when { + encoding.equals("br", ignoreCase = true) -> + BrotliInputStream(body.source().inputStream()).source().buffer() + encoding.equals("gzip", ignoreCase = true) -> + GzipSource(body.source()).buffer() + else -> return response + } return response.newBuilder() .removeHeader("Content-Encoding") diff --git a/okhttp-brotli/src/test/java/okhttp3/brotli/BrotliInterceptorTest.kt b/okhttp-brotli/src/test/java/okhttp3/brotli/BrotliInterceptorTest.kt index 3a5a46a42337..0eda58594744 100644 --- a/okhttp-brotli/src/test/java/okhttp3/brotli/BrotliInterceptorTest.kt +++ b/okhttp-brotli/src/test/java/okhttp3/brotli/BrotliInterceptorTest.kt @@ -38,14 +38,15 @@ class BrotliInterceptorTest { @Test fun testUncompressBrotli() { val s = - "1bce00009c05ceb9f028d14e416230f718960a537b0922d2f7b6adef56532c08dff44551516690131494db" + - "6021c7e3616c82c1bc2416abb919aaa06e8d30d82cc2981c2f5c900bfb8ee29d5c03deb1c0dacff80e" + - "abe82ba64ed250a497162006824684db917963ecebe041b352a3e62d629cc97b95cac24265b175171e" + - "5cb384cd0912aeb5b5dd9555f2dd1a9b20688201" + "1bce00009c05ceb9f028d14e416230f718960a537b0922d2f7b6adef56532c08dff44551516690131494db" + + "6021c7e3616c82c1bc2416abb919aaa06e8d30d82cc2981c2f5c900bfb8ee29d5c03deb1c0dacff80e" + + "abe82ba64ed250a497162006824684db917963ecebe041b352a3e62d629cc97b95cac24265b175171e" + + "5cb384cd0912aeb5b5dd9555f2dd1a9b20688201" - val response = response("https://httpbin.org/brotli", s.decodeHex()) { - header("Content-Encoding", "br") - } + val response = + response("https://httpbin.org/brotli", s.decodeHex()) { + header("Content-Encoding", "br") + } val uncompressed = uncompress(response) @@ -57,15 +58,16 @@ class BrotliInterceptorTest { @Test fun testUncompressGzip() { val s = - "1f8b0800968f215d02ff558ec10e82301044ef7c45b3e75269d0c478e340e4a426e007086c4a636c9bb65e" + - "24fcbb5b484c3cec61deccecee9c3106eaa39dc3114e2cfa377296d8848f117d20369324500d03ba98" + - "d766b0a3368a0ce83d4f55581b14696c88894f31ba5e1b61bdfa79f7803eaf149a35619f29b3db0b29" + - "8abcbd54b7b6b97640c965bbfec238d9f4109ceb6edb01d66ba54d6247296441531e445970f627215b" + - "b22f1017320dd5000000" - - val response = response("https://httpbin.org/gzip", s.decodeHex()) { - header("Content-Encoding", "gzip") - } + "1f8b0800968f215d02ff558ec10e82301044ef7c45b3e75269d0c478e340e4a426e007086c4a636c9bb65e" + + "24fcbb5b484c3cec61deccecee9c3106eaa39dc3114e2cfa377296d8848f117d20369324500d03ba98" + + "d766b0a3368a0ce83d4f55581b14696c88894f31ba5e1b61bdfa79f7803eaf149a35619f29b3db0b29" + + "8abcbd54b7b6b97640c965bbfec238d9f4109ceb6edb01d66ba54d6247296441531e445970f627215b" + + "b22f1017320dd5000000" + + val response = + response("https://httpbin.org/gzip", s.decodeHex()) { + header("Content-Encoding", "gzip") + } val uncompressed = uncompress(response) @@ -86,9 +88,10 @@ class BrotliInterceptorTest { @Test fun testFailsUncompress() { - val response = response("https://httpbin.org/brotli", "bb919aaa06e8".decodeHex()) { - header("Content-Encoding", "br") - } + val response = + response("https://httpbin.org/brotli", "bb919aaa06e8".decodeHex()) { + header("Content-Encoding", "br") + } assertFailsWith { val failingResponse = uncompress(response) @@ -101,11 +104,12 @@ class BrotliInterceptorTest { @Test fun testSkipUncompressNoContentResponse() { - val response = response("https://httpbin.org/brotli", EMPTY) { - header("Content-Encoding", "br") - code(204) - message("NO CONTENT") - } + val response = + response("https://httpbin.org/brotli", EMPTY) { + header("Content-Encoding", "br") + code(204) + message("NO CONTENT") + } val same = uncompress(response) @@ -116,15 +120,15 @@ class BrotliInterceptorTest { private fun response( url: String, bodyHex: ByteString, - fn: Response.Builder.() -> Unit = {} + fn: Response.Builder.() -> Unit = {}, ): Response { return Response.Builder() - .body(bodyHex.toResponseBody("text/plain".toMediaType())) - .code(200) - .message("OK") - .request(Request.Builder().url(url).build()) - .protocol(Protocol.HTTP_2) - .apply(fn) - .build() + .body(bodyHex.toResponseBody("text/plain".toMediaType())) + .code(200) + .message("OK") + .request(Request.Builder().url(url).build()) + .protocol(Protocol.HTTP_2) + .apply(fn) + .build() } } diff --git a/okhttp-brotli/src/test/java/okhttp3/brotli/BrotliTestMain.kt b/okhttp-brotli/src/test/java/okhttp3/brotli/BrotliTestMain.kt index 5181b053dce7..b7eda8c2b5ad 100644 --- a/okhttp-brotli/src/test/java/okhttp3/brotli/BrotliTestMain.kt +++ b/okhttp-brotli/src/test/java/okhttp3/brotli/BrotliTestMain.kt @@ -19,7 +19,8 @@ import okhttp3.OkHttpClient import okhttp3.Request fun main() { - val client = OkHttpClient.Builder() + val client = + OkHttpClient.Builder() .addInterceptor(BrotliInterceptor) .build() @@ -27,7 +28,10 @@ fun main() { sendRequest("https://httpbin.org/gzip", client) } -private fun sendRequest(url: String, client: OkHttpClient) { +private fun sendRequest( + url: String, + client: OkHttpClient, +) { val req = Request.Builder().url(url).build() client.newCall(req).execute().use { diff --git a/okhttp-coroutines/src/main/kotlin/okhttp3/JvmCallExtensions.kt b/okhttp-coroutines/src/main/kotlin/okhttp3/JvmCallExtensions.kt index 4732a1782741..c8460de306db 100644 --- a/okhttp-coroutines/src/main/kotlin/okhttp3/JvmCallExtensions.kt +++ b/okhttp-coroutines/src/main/kotlin/okhttp3/JvmCallExtensions.kt @@ -17,23 +17,32 @@ package okhttp3 +import kotlin.coroutines.resumeWithException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.suspendCancellableCoroutine import okio.IOException -import kotlin.coroutines.resumeWithException @OptIn(ExperimentalCoroutinesApi::class) -suspend fun Call.executeAsync(): Response = suspendCancellableCoroutine { continuation -> - continuation.invokeOnCancellation { - this.cancel() - } - this.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - continuation.resumeWithException(e) +suspend fun Call.executeAsync(): Response = + suspendCancellableCoroutine { continuation -> + continuation.invokeOnCancellation { + this.cancel() } + this.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + continuation.resumeWithException(e) + } - override fun onResponse(call: Call, response: Response) { - continuation.resume(value = response, onCancellation = { call.cancel() }) - } - }) -} + override fun onResponse( + call: Call, + response: Response, + ) { + continuation.resume(value = response, onCancellation = { call.cancel() }) + } + }, + ) + } diff --git a/okhttp-coroutines/src/test/kotlin/okhttp3/SuspendCallTest.kt b/okhttp-coroutines/src/test/kotlin/okhttp3/SuspendCallTest.kt index 97711d413b64..883d04038df9 100644 --- a/okhttp-coroutines/src/test/kotlin/okhttp3/SuspendCallTest.kt +++ b/okhttp-coroutines/src/test/kotlin/okhttp3/SuspendCallTest.kt @@ -80,7 +80,7 @@ class SuspendCallTest { MockResponse.Builder() .bodyDelay(5, TimeUnit.SECONDS) .body("abc") - .build() + .build(), ) val call = client.newCall(request) @@ -109,7 +109,7 @@ class SuspendCallTest { MockResponse.Builder() .bodyDelay(5, TimeUnit.SECONDS) .body("abc") - .build() + .build(), ) val call = client.newCall(request) @@ -137,7 +137,7 @@ class SuspendCallTest { MockResponse( body = "abc", socketPolicy = DisconnectAfterRequest, - ) + ), ) val call = client.newCall(request) diff --git a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/BootstrapDns.kt b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/BootstrapDns.kt index ff403f2c2c54..056f6201d766 100644 --- a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/BootstrapDns.kt +++ b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/BootstrapDns.kt @@ -26,13 +26,13 @@ import okhttp3.Dns */ internal class BootstrapDns( private val dnsHostname: String, - private val dnsServers: List + private val dnsServers: List, ) : Dns { @Throws(UnknownHostException::class) override fun lookup(hostname: String): List { if (this.dnsHostname != hostname) { throw UnknownHostException( - "BootstrapDns called for $hostname instead of $dnsHostname" + "BootstrapDns called for $hostname instead of $dnsHostname", ) } diff --git a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt index b5d644d2206d..2944ddebb947 100644 --- a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt +++ b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt @@ -51,7 +51,7 @@ class DnsOverHttps internal constructor( @get:JvmName("includeIPv6") val includeIPv6: Boolean, @get:JvmName("post") val post: Boolean, @get:JvmName("resolvePrivateAddresses") val resolvePrivateAddresses: Boolean, - @get:JvmName("resolvePublicAddresses") val resolvePublicAddresses: Boolean + @get:JvmName("resolvePublicAddresses") val resolvePublicAddresses: Boolean, ) : Dns { @Throws(UnknownHostException::class) override fun lookup(hostname: String): List { @@ -94,37 +94,46 @@ class DnsOverHttps internal constructor( networkRequests: MutableList, results: MutableList, failures: MutableList, - type: Int + type: Int, ) { val request = buildRequest(hostname, type) val response = getCacheOnlyResponse(request) response?.let { processResponse(it, hostname, results, failures) } ?: networkRequests.add( - client.newCall(request)) + client.newCall(request), + ) } private fun executeRequests( hostname: String, networkRequests: List, responses: MutableList, - failures: MutableList + failures: MutableList, ) { val latch = CountDownLatch(networkRequests.size) for (call in networkRequests) { - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - synchronized(failures) { - failures.add(e) + call.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + synchronized(failures) { + failures.add(e) + } + latch.countDown() } - latch.countDown() - } - override fun onResponse(call: Call, response: Response) { - processResponse(response, hostname, responses, failures) - latch.countDown() - } - }) + override fun onResponse( + call: Call, + response: Response, + ) { + processResponse(response, hostname, responses, failures) + latch.countDown() + } + }, + ) } try { @@ -138,7 +147,7 @@ class DnsOverHttps internal constructor( response: Response, hostname: String, results: MutableList, - failures: MutableList + failures: MutableList, ) { try { val addresses = readResponse(hostname, response) @@ -153,7 +162,10 @@ class DnsOverHttps internal constructor( } @Throws(UnknownHostException::class) - private fun throwBestFailure(hostname: String, failures: List): List { + private fun throwBestFailure( + hostname: String, + failures: List, + ): List { if (failures.isEmpty()) { throw UnknownHostException(hostname) } @@ -179,7 +191,8 @@ class DnsOverHttps internal constructor( try { // Use the cache without hitting the network first // 504 code indicates that the Cache is stale - val preferCache = CacheControl.Builder() + val preferCache = + CacheControl.Builder() .onlyIfCached() .build() val cacheRequest = request.newBuilder().cacheControl(preferCache).build() @@ -199,7 +212,10 @@ class DnsOverHttps internal constructor( } @Throws(Exception::class) - private fun readResponse(hostname: String, response: Response): List { + private fun readResponse( + hostname: String, + response: Response, + ): List { if (response.cacheResponse == null && response.protocol !== Protocol.HTTP_2) { Platform.get().log("Incorrect protocol: ${response.protocol}", Platform.WARN) } @@ -213,7 +229,7 @@ class DnsOverHttps internal constructor( if (body.contentLength() > MAX_RESPONSE_SIZE) { throw IOException( - "response size exceeds limit ($MAX_RESPONSE_SIZE bytes): ${body.contentLength()} bytes" + "response size exceeds limit ($MAX_RESPONSE_SIZE bytes): ${body.contentLength()} bytes", ) } @@ -223,19 +239,22 @@ class DnsOverHttps internal constructor( } } - private fun buildRequest(hostname: String, type: Int): Request = - Request.Builder().header("Accept", DNS_MESSAGE.toString()).apply { - val query = DnsRecordCodec.encodeQuery(hostname, type) + private fun buildRequest( + hostname: String, + type: Int, + ): Request = + Request.Builder().header("Accept", DNS_MESSAGE.toString()).apply { + val query = DnsRecordCodec.encodeQuery(hostname, type) - if (post) { - url(url).post(query.toRequestBody(DNS_MESSAGE)) - } else { - val encoded = query.base64Url().replace("=", "") - val requestUrl = url.newBuilder().addQueryParameter("dns", encoded).build() + if (post) { + url(url).post(query.toRequestBody(DNS_MESSAGE)) + } else { + val encoded = query.base64Url().replace("=", "") + val requestUrl = url.newBuilder().addQueryParameter("dns", encoded).build() - url(requestUrl) - } - }.build() + url(requestUrl) + } + }.build() class Builder { internal var client: OkHttpClient? = null @@ -250,49 +269,56 @@ class DnsOverHttps internal constructor( fun build(): DnsOverHttps { val client = this.client ?: throw NullPointerException("client not set") return DnsOverHttps( - client.newBuilder().dns(buildBootstrapClient(this)).build(), - checkNotNull(url) { "url not set" }, - includeIPv6, - post, - resolvePrivateAddresses, - resolvePublicAddresses + client.newBuilder().dns(buildBootstrapClient(this)).build(), + checkNotNull(url) { "url not set" }, + includeIPv6, + post, + resolvePrivateAddresses, + resolvePublicAddresses, ) } - fun client(client: OkHttpClient) = apply { - this.client = client - } + fun client(client: OkHttpClient) = + apply { + this.client = client + } - fun url(url: HttpUrl) = apply { - this.url = url - } + fun url(url: HttpUrl) = + apply { + this.url = url + } - fun includeIPv6(includeIPv6: Boolean) = apply { - this.includeIPv6 = includeIPv6 - } + fun includeIPv6(includeIPv6: Boolean) = + apply { + this.includeIPv6 = includeIPv6 + } - fun post(post: Boolean) = apply { - this.post = post - } + fun post(post: Boolean) = + apply { + this.post = post + } - fun resolvePrivateAddresses(resolvePrivateAddresses: Boolean) = apply { - this.resolvePrivateAddresses = resolvePrivateAddresses - } + fun resolvePrivateAddresses(resolvePrivateAddresses: Boolean) = + apply { + this.resolvePrivateAddresses = resolvePrivateAddresses + } - fun resolvePublicAddresses(resolvePublicAddresses: Boolean) = apply { - this.resolvePublicAddresses = resolvePublicAddresses - } + fun resolvePublicAddresses(resolvePublicAddresses: Boolean) = + apply { + this.resolvePublicAddresses = resolvePublicAddresses + } - fun bootstrapDnsHosts(bootstrapDnsHosts: List?) = apply { - this.bootstrapDnsHosts = bootstrapDnsHosts - } + fun bootstrapDnsHosts(bootstrapDnsHosts: List?) = + apply { + this.bootstrapDnsHosts = bootstrapDnsHosts + } - fun bootstrapDnsHosts(vararg bootstrapDnsHosts: InetAddress): Builder = - bootstrapDnsHosts(bootstrapDnsHosts.toList()) + fun bootstrapDnsHosts(vararg bootstrapDnsHosts: InetAddress): Builder = bootstrapDnsHosts(bootstrapDnsHosts.toList()) - fun systemDns(systemDns: Dns) = apply { - this.systemDns = systemDns - } + fun systemDns(systemDns: Dns) = + apply { + this.systemDns = systemDns + } } companion object { diff --git a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsRecordCodec.kt b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsRecordCodec.kt index 2d8e7f42fcc6..60119081be0b 100644 --- a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsRecordCodec.kt +++ b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsRecordCodec.kt @@ -33,31 +33,38 @@ internal object DnsRecordCodec { private const val TYPE_PTR = 0x000c private val ASCII = Charsets.US_ASCII - fun encodeQuery(host: String, type: Int): ByteString = Buffer().apply { - writeShort(0) // query id - writeShort(256) // flags with recursion - writeShort(1) // question count - writeShort(0) // answerCount - writeShort(0) // authorityResourceCount - writeShort(0) // additional - - val nameBuf = Buffer() - val labels = host.split('.').dropLastWhile { it.isEmpty() } - for (label in labels) { - val utf8ByteCount = label.utf8Size() - require(utf8ByteCount == label.length.toLong()) { "non-ascii hostname: $host" } - nameBuf.writeByte(utf8ByteCount.toInt()) - nameBuf.writeUtf8(label) - } - nameBuf.writeByte(0) // end + fun encodeQuery( + host: String, + type: Int, + ): ByteString = + Buffer().apply { + writeShort(0) // query id + writeShort(256) // flags with recursion + writeShort(1) // question count + writeShort(0) // answerCount + writeShort(0) // authorityResourceCount + writeShort(0) // additional + + val nameBuf = Buffer() + val labels = host.split('.').dropLastWhile { it.isEmpty() } + for (label in labels) { + val utf8ByteCount = label.utf8Size() + require(utf8ByteCount == label.length.toLong()) { "non-ascii hostname: $host" } + nameBuf.writeByte(utf8ByteCount.toInt()) + nameBuf.writeUtf8(label) + } + nameBuf.writeByte(0) // end - nameBuf.copyTo(this, 0, nameBuf.size) - writeShort(type) - writeShort(1) // CLASS_IN - }.readByteString() + nameBuf.copyTo(this, 0, nameBuf.size) + writeShort(type) + writeShort(1) // CLASS_IN + }.readByteString() @Throws(Exception::class) - fun decodeAnswers(hostname: String, byteString: ByteString): List { + fun decodeAnswers( + hostname: String, + byteString: ByteString, + ): List { val result = mutableListOf() val buf = Buffer() @@ -91,7 +98,8 @@ internal object DnsRecordCodec { val type = buf.readShort().toInt() and 0xffff buf.readShort() // class - @Suppress("UNUSED_VARIABLE") val ttl = buf.readInt().toLong() and 0xffffffffL // ttl + @Suppress("UNUSED_VARIABLE") + val ttl = buf.readInt().toLong() and 0xffffffffL // ttl val length = buf.readShort().toInt() and 0xffff if (type == TYPE_A || type == TYPE_AAAA) { diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt index 48de726c0b8b..05b5f1d8f5a4 100644 --- a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt @@ -55,9 +55,10 @@ class DnsOverHttpsTest { private lateinit var server: MockWebServer private lateinit var dns: Dns private val cacheFs = FakeFileSystem() - private val bootstrapClient = OkHttpClient.Builder() - .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)) - .build() + private val bootstrapClient = + OkHttpClient.Builder() + .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)) + .build() @BeforeEach fun setUp(server: MockWebServer) { @@ -72,8 +73,8 @@ class DnsOverHttpsTest { dnsResponse( "0000818000010003000000000567726170680866616365626f6f6b03636f6d0000010001c00c000500010" + "0000a6d000603617069c012c0300005000100000cde000c04737461720463313072c012c04200010001000" + - "0003b00049df00112" - ) + "0003b00049df00112", + ), ) val result = dns.lookup("google.com") assertThat(result).isEqualTo(listOf(address("157.240.1.18"))) @@ -89,15 +90,15 @@ class DnsOverHttpsTest { dnsResponse( "0000818000010003000000000567726170680866616365626f6f6b03636f6d0000010001c00c0005000" + "100000a6d000603617069c012c0300005000100000cde000c04737461720463313072c012c0420001000" + - "10000003b00049df00112" - ) + "10000003b00049df00112", + ), ) server.enqueue( dnsResponse( "0000818000010003000000000567726170680866616365626f6f6b03636f6d00001c0001c00c0005000" + "100000a1b000603617069c012c0300005000100000b1f000c04737461720463313072c012c042001c000" + - "10000003b00102a032880f0290011faceb00c00000002" - ) + "10000003b00102a032880f0290011faceb00c00000002", + ), ) dns = buildLocalhost(bootstrapClient, true) val result = dns.lookup("google.com") @@ -111,7 +112,7 @@ class DnsOverHttpsTest { assertThat(listOf(request1.path, request2.path)) .containsExactlyInAnyOrder( "/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ", - "/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AABwAAQ" + "/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AABwAAQ", ) } @@ -121,8 +122,8 @@ class DnsOverHttpsTest { dnsResponse( "0000818300010000000100000e7364666c6b686673646c6b6a64660265650000010001c01b00060001000" + "007070038026e7303746c64c01b0a686f73746d61737465720d6565737469696e7465726e6574c01b5adb1" + - "2c100000e10000003840012750000000e10" - ) + "2c100000e10000003840012750000000e10", + ), ) try { dns.lookup("google.com") @@ -179,11 +180,11 @@ class DnsOverHttpsTest { dnsResponse( "0000818000010003000000000567726170680866616365626f6f6b03636f6d0000010001c00c000500010" + "0000a6d000603617069c012c0300005000100000cde000c04737461720463313072c012c04200010001000" + - "0003b00049df00112" + "0003b00049df00112", ) .newBuilder() .setHeader("cache-control", "private, max-age=298") - .build() + .build(), ) var result = cachedDns.lookup("google.com") assertThat(result).containsExactly(address("157.240.1.18")) @@ -204,29 +205,29 @@ class DnsOverHttpsTest { dnsResponse( "0000818000010003000000000567726170680866616365626f6f6b03636f6d0000010001c00c000500010" + "0000a6d000603617069c012c0300005000100000cde000c04737461720463313072c012c04200010001000" + - "0003b00049df00112" + "0003b00049df00112", ) .newBuilder() .setHeader("cache-control", "max-age=1") - .build() + .build(), ) var result = cachedDns.lookup("google.com") assertThat(result).containsExactly(address("157.240.1.18")) var recordedRequest = server.takeRequest(0, TimeUnit.SECONDS) assertThat(recordedRequest!!.method).isEqualTo("GET") assertThat(recordedRequest.path).isEqualTo( - "/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ" + "/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ", ) Thread.sleep(2000) server.enqueue( dnsResponse( "0000818000010003000000000567726170680866616365626f6f6b03636f6d0000010001c00c000500010" + "0000a6d000603617069c012c0300005000100000cde000c04737461720463313072c012c04200010001000" + - "0003b00049df00112" + "0003b00049df00112", ) .newBuilder() .setHeader("cache-control", "max-age=1") - .build() + .build(), ) result = cachedDns.lookup("google.com") assertThat(result).isEqualTo(listOf(address("157.240.1.18"))) @@ -244,7 +245,10 @@ class DnsOverHttpsTest { .build() } - private fun buildLocalhost(bootstrapClient: OkHttpClient, includeIPv6: Boolean): DnsOverHttps { + private fun buildLocalhost( + bootstrapClient: OkHttpClient, + includeIPv6: Boolean, + ): DnsOverHttps { val url = server.url("/lookup?ct") return DnsOverHttps.Builder().client(bootstrapClient) .includeIPv6(includeIPv6) diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsRecordCodecTest.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsRecordCodecTest.kt index cbdd77164247..7e29c5da611a 100644 --- a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsRecordCodecTest.kt +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsRecordCodecTest.kt @@ -14,12 +14,12 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3.dnsoverhttps import assertk.assertThat import assertk.assertions.containsExactly import assertk.assertions.isEqualTo -import assertk.fail import java.net.InetAddress import java.net.UnknownHostException import kotlin.test.assertFailsWith @@ -36,7 +36,10 @@ class DnsRecordCodecTest { assertThat(encoded).isEqualTo("AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ") } - private fun encodeQuery(host: String, type: Int): String { + private fun encodeQuery( + host: String, + type: Int, + ): String { return DnsRecordCodec.encodeQuery(host, type).base64Url().replace("=", "") } @@ -48,33 +51,45 @@ class DnsRecordCodecTest { @Test fun testGoogleDotComDecodingFromCloudflare() { - val encoded = decodeAnswers( - hostname = "test.com", - byteString = ("00008180000100010000000006676f6f676c6503636f6d0000010001c00c0001000100000043" + - "0004d83ad54e").decodeHex() - ) + val encoded = + decodeAnswers( + hostname = "test.com", + byteString = + ( + "00008180000100010000000006676f6f676c6503636f6d0000010001c00c0001000100000043" + + "0004d83ad54e" + ).decodeHex(), + ) assertThat(encoded).containsExactly(InetAddress.getByName("216.58.213.78")) } @Test fun testGoogleDotComDecodingFromGoogle() { - val decoded = decodeAnswers( - hostname = "test.com", - byteString = ("0000818000010003000000000567726170680866616365626f6f6b03636f6d0000010001c00c" + - "0005000100000a6d000603617069c012c0300005000100000cde000c04737461720463313072c012c0420001" + - "00010000003b00049df00112").decodeHex() - ) + val decoded = + decodeAnswers( + hostname = "test.com", + byteString = + ( + "0000818000010003000000000567726170680866616365626f6f6b03636f6d0000010001c00c" + + "0005000100000a6d000603617069c012c0300005000100000cde000c04737461720463313072c012c0420001" + + "00010000003b00049df00112" + ).decodeHex(), + ) assertThat(decoded).containsExactly(InetAddress.getByName("157.240.1.18")) } @Test fun testGoogleDotComDecodingFromGoogleIPv6() { - val decoded = decodeAnswers( - hostname = "test.com", - byteString = ("0000818000010003000000000567726170680866616365626f6f6b03636f6d00001c0001c00c" + - "0005000100000a1b000603617069c012c0300005000100000b1f000c04737461720463313072c012c042001c" + - "00010000003b00102a032880f0290011faceb00c00000002").decodeHex() - ) + val decoded = + decodeAnswers( + hostname = "test.com", + byteString = + ( + "0000818000010003000000000567726170680866616365626f6f6b03636f6d00001c0001c00c" + + "0005000100000a1b000603617069c012c0300005000100000b1f000c04737461720463313072c012c042001c" + + "00010000003b00102a032880f0290011faceb00c00000002" + ).decodeHex(), + ) assertThat(decoded) .containsExactly(InetAddress.getByName("2a03:2880:f029:11:face:b00c:0:2")) } @@ -84,9 +99,12 @@ class DnsRecordCodecTest { assertFailsWith { decodeAnswers( hostname = "sdflkhfsdlkjdf.ee", - byteString = ("0000818300010000000100000e7364666c6b686673646c6b6a64660265650000010001c01b" + - "00060001000007070038026e7303746c64c01b0a686f73746d61737465720d6565737469696e7465726e65" + - "74c01b5adb12c100000e10000003840012750000000e10").decodeHex() + byteString = + ( + "0000818300010000000100000e7364666c6b686673646c6b6a64660265650000010001c01b" + + "00060001000007070038026e7303746c64c01b0a686f73746d61737465720d6565737469696e7465726e65" + + "74c01b5adb12c100000e10000003840012750000000e10" + ).decodeHex(), ) }.also { expected -> assertThat(expected.message).isEqualTo("sdflkhfsdlkjdf.ee: NXDOMAIN") diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/TestDohMain.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/TestDohMain.kt index 606ff202601e..72ca545f355f 100644 --- a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/TestDohMain.kt +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/TestDohMain.kt @@ -24,7 +24,10 @@ import okhttp3.OkHttpClient import okhttp3.dnsoverhttps.DohProviders.providers import org.conscrypt.OpenSSLProvider -private fun runBatch(dnsProviders: List, names: List) { +private fun runBatch( + dnsProviders: List, + names: List, +) { var time = System.currentTimeMillis() for (dns in dnsProviders) { println("Testing ${dns.url}") @@ -54,46 +57,52 @@ fun main() { var names = listOf("google.com", "graph.facebook.com", "sdflkhfsdlkjdf.ee") try { println("uncached\n********\n") - var dnsProviders = providers( - client = bootstrapClient, - http2Only = false, - workingOnly = false, - getOnly = false, - ) + var dnsProviders = + providers( + client = bootstrapClient, + http2Only = false, + workingOnly = false, + getOnly = false, + ) runBatch(dnsProviders, names) - val dnsCache = Cache( - directory = File("./target/TestDohMain.cache.${System.currentTimeMillis()}"), - maxSize = 10L * 1024 * 1024 - ) + val dnsCache = + Cache( + directory = File("./target/TestDohMain.cache.${System.currentTimeMillis()}"), + maxSize = 10L * 1024 * 1024, + ) println("Bad targets\n***********\n") val url = "https://dns.cloudflare.com/.not-so-well-known/run-dmc-query".toHttpUrl() - val badProviders = listOf( - DnsOverHttps.Builder() - .client(bootstrapClient) - .url(url) - .post(true) - .build() - ) + val badProviders = + listOf( + DnsOverHttps.Builder() + .client(bootstrapClient) + .url(url) + .post(true) + .build(), + ) runBatch(badProviders, names) println("cached first run\n****************\n") names = listOf("google.com", "graph.facebook.com") - bootstrapClient = bootstrapClient.newBuilder() - .cache(dnsCache) - .build() - dnsProviders = providers( - client = bootstrapClient, - http2Only = true, - workingOnly = true, - getOnly = true, - ) + bootstrapClient = + bootstrapClient.newBuilder() + .cache(dnsCache) + .build() + dnsProviders = + providers( + client = bootstrapClient, + http2Only = true, + workingOnly = true, + getOnly = true, + ) runBatch(dnsProviders, names) println("cached second run\n*****************\n") - dnsProviders = providers( - client = bootstrapClient, - http2Only = true, - workingOnly = true, - getOnly = true, - ) + dnsProviders = + providers( + client = bootstrapClient, + http2Only = true, + workingOnly = true, + getOnly = true, + ) runBatch(dnsProviders, names) } finally { bootstrapClient.connectionPool.evictAll() diff --git a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackDecodeInteropTest.kt b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackDecodeInteropTest.kt index c7a267e77c7f..f0b6b035d3de 100644 --- a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackDecodeInteropTest.kt +++ b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackDecodeInteropTest.kt @@ -28,7 +28,7 @@ class HpackDecodeInteropTest : HpackDecodeTestBase() { fun testGoodDecoderInterop(story: Story) { assumeFalse( story === Story.MISSING, - "Test stories missing, checkout git submodule" + "Test stories missing, checkout git submodule", ) testDecoder(story) } diff --git a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackDecodeTestBase.kt b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackDecodeTestBase.kt index 4cb329a5b819..cc06775dc890 100644 --- a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackDecodeTestBase.kt +++ b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackDecodeTestBase.kt @@ -36,7 +36,7 @@ open class HpackDecodeTestBase { assertSetEquals( "seqno=$testCase.seqno", testCase.headersList, - hpackReader.getAndResetHeaderList() + hpackReader.getAndResetHeaderList(), ) } } diff --git a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackRoundTripTest.kt b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackRoundTripTest.kt index 457d2923f9ed..d6d29f1e9df2 100644 --- a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackRoundTripTest.kt +++ b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/HpackRoundTripTest.kt @@ -43,7 +43,7 @@ class HpackRoundTripTest : HpackDecodeTestBase() { fun testRoundTrip(story: Story) { assumeFalse( story === Story.MISSING, - "Test stories missing, checkout git submodule" + "Test stories missing, checkout git submodule", ) val newCases = mutableListOf() diff --git a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/hpackjson/HpackJsonUtil.kt b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/hpackjson/HpackJsonUtil.kt index fc16ea603758..5b43e2e8c3f9 100644 --- a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/hpackjson/HpackJsonUtil.kt +++ b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/hpackjson/HpackJsonUtil.kt @@ -35,13 +35,17 @@ import okio.source */ object HpackJsonUtil { @Suppress("unused") - private val MOSHI = Moshi.Builder() - .add(object : Any() { - @ToJson fun byteStringToJson(byteString: ByteString) = byteString.hex() - @FromJson fun byteStringFromJson(json: String) = json.decodeHex() - }) - .add(KotlinJsonAdapterFactory()) - .build() + private val MOSHI = + Moshi.Builder() + .add( + object : Any() { + @ToJson fun byteStringToJson(byteString: ByteString) = byteString.hex() + + @FromJson fun byteStringFromJson(json: String) = json.decodeHex() + }, + ) + .add(KotlinJsonAdapterFactory()) + .build() private val STORY_JSON_ADAPTER = MOSHI.adapter(Story::class.java) private val fileSystem = FileSystem.SYSTEM @@ -58,8 +62,9 @@ object HpackJsonUtil { /** Iterate through the hpack-test-case resources, only picking stories for the current draft. */ fun storiesForCurrentDraft(): Array { - val resource = HpackJsonUtil::class.java.getResource("/hpack-test-case") - ?: return arrayOf() + val resource = + HpackJsonUtil::class.java.getResource("/hpack-test-case") + ?: return arrayOf() val testCaseDirectory = File(resource.toURI()).toOkioPath() val result = mutableListOf() @@ -83,17 +88,20 @@ object HpackJsonUtil { val result = mutableListOf() var i = 0 while (true) { // break after last test. - val storyResourceName = String.format( - "/hpack-test-case/%s/story_%02d.json", - testFolderName, - i, - ) - val storyInputStream = HpackJsonUtil::class.java.getResourceAsStream(storyResourceName) - ?: break + val storyResourceName = + String.format( + "/hpack-test-case/%s/story_%02d.json", + testFolderName, + i, + ) + val storyInputStream = + HpackJsonUtil::class.java.getResourceAsStream(storyResourceName) + ?: break try { storyInputStream.use { - val story = readStory(storyInputStream.source().buffer()) - .copy(fileName = storyResourceName) + val story = + readStory(storyInputStream.source().buffer()) + .copy(fileName = storyResourceName) result.add(story) i++ } diff --git a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/hpackjson/Story.kt b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/hpackjson/Story.kt index bcab3fb7fd38..796b8097b190 100644 --- a/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/hpackjson/Story.kt +++ b/okhttp-hpacktests/src/test/java/okhttp3/internal/http2/hpackjson/Story.kt @@ -24,7 +24,6 @@ data class Story( val cases: List, val fileName: String? = null, ) { - // Used as the test name. override fun toString() = fileName ?: "?" diff --git a/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/GenerateIdnaMappingTableCode.kt b/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/GenerateIdnaMappingTableCode.kt index 90e5811b3d74..89f37b4c4c3d 100644 --- a/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/GenerateIdnaMappingTableCode.kt +++ b/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/GenerateIdnaMappingTableCode.kt @@ -33,9 +33,10 @@ fun main(vararg args: String) { fun loadIdnaMappingTableData(): IdnaMappingTableData { val path = "/okhttp3/internal/idna/IdnaMappingTable.txt".toPath() - val table = FileSystem.RESOURCES.read(path) { - readPlainTextIdnaMappingTable() - } + val table = + FileSystem.RESOURCES.read(path) { + readPlainTextIdnaMappingTable() + } return buildIdnaMappingTableData(table) } @@ -60,18 +61,18 @@ fun generateMappingTableFile(data: IdnaMappingTableData): FileSpec { .addModifiers(KModifier.INTERNAL) .initializer( """ - |%T(⇥ - |sections = "%L", - |ranges = "%L", - |mappings = "%L", - |⇤) - """.trimMargin(), + |%T(⇥ + |sections = "%L", + |ranges = "%L", + |mappings = "%L", + |⇤) + """.trimMargin(), idnaMappingTable, data.sections.escapeDataString(), data.ranges.escapeDataString(), data.mappings.escapeDataString(), ) - .build() + .build(), ) .build() } @@ -89,7 +90,8 @@ fun String.escapeDataString(): String { '$'.code, '\\'.code, '·'.code, - 127 -> append(String.format("\\u%04x", codePoint)) + 127, + -> append(String.format("\\u%04x", codePoint)) else -> appendCodePoint(codePoint) } diff --git a/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/MappedRange.kt b/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/MappedRange.kt index a8cb0bf75865..0e3d67a39fad 100644 --- a/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/MappedRange.kt +++ b/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/MappedRange.kt @@ -23,22 +23,22 @@ internal sealed interface MappedRange { data class Constant( override val rangeStart: Int, - val type: Int + val type: Int, ) : MappedRange { val b1: Int - get() = when (type) { - TYPE_IGNORED -> 119 - TYPE_VALID -> 120 - TYPE_DISALLOWED -> 121 - else -> error("unexpected type: $type") - } + get() = + when (type) { + TYPE_IGNORED -> 119 + TYPE_VALID -> 120 + TYPE_DISALLOWED -> 121 + else -> error("unexpected type: $type") + } } data class Inline1( override val rangeStart: Int, - private val mappedTo: ByteString + private val mappedTo: ByteString, ) : MappedRange { - val b1: Int get() { val b3bit8 = mappedTo[0] and 0x80 != 0 @@ -51,9 +51,8 @@ internal sealed interface MappedRange { data class Inline2( override val rangeStart: Int, - private val mappedTo: ByteString + private val mappedTo: ByteString, ) : MappedRange { - val b1: Int get() { val b2bit8 = mappedTo[0] and 0x80 != 0 @@ -75,17 +74,17 @@ internal sealed interface MappedRange { data class InlineDelta( override val rangeStart: Int, - val codepointDelta: Int + val codepointDelta: Int, ) : MappedRange { - private val absoluteDelta = abs(codepointDelta) val b1: Int - get() = when { - codepointDelta < 0 -> 0x40 or (absoluteDelta shr 14) - codepointDelta > 0 -> 0x50 or (absoluteDelta shr 14) - else -> error("Unexpected codepointDelta of 0") - } + get() = + when { + codepointDelta < 0 -> 0x40 or (absoluteDelta shr 14) + codepointDelta > 0 -> 0x50 or (absoluteDelta shr 14) + else -> error("Unexpected codepointDelta of 0") + } val b2: Int get() = absoluteDelta shr 7 and 0x7f @@ -100,6 +99,6 @@ internal sealed interface MappedRange { data class External( override val rangeStart: Int, - val mappedTo: ByteString + val mappedTo: ByteString, ) : MappedRange } diff --git a/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/MappingTables.kt b/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/MappingTables.kt index be6ac04adeac..b276e931f2be 100644 --- a/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/MappingTables.kt +++ b/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/MappingTables.kt @@ -135,26 +135,28 @@ internal fun sections(mappings: List): Map> { val sectionList = result.getOrPut(section) { mutableListOf() } - sectionList += when (mapping.type) { - TYPE_MAPPED -> run { - val deltaMapping = inlineDeltaOrNull(mapping) - if (deltaMapping != null) { - return@run deltaMapping - } + sectionList += + when (mapping.type) { + TYPE_MAPPED -> + run { + val deltaMapping = inlineDeltaOrNull(mapping) + if (deltaMapping != null) { + return@run deltaMapping + } + + when (mapping.mappedTo.size) { + 1 -> MappedRange.Inline1(rangeStart, mapping.mappedTo) + 2 -> MappedRange.Inline2(rangeStart, mapping.mappedTo) + else -> MappedRange.External(rangeStart, mapping.mappedTo) + } + } - when (mapping.mappedTo.size) { - 1 -> MappedRange.Inline1(rangeStart, mapping.mappedTo) - 2 -> MappedRange.Inline2(rangeStart, mapping.mappedTo) - else -> MappedRange.External(rangeStart, mapping.mappedTo) + TYPE_IGNORED, TYPE_VALID, TYPE_DISALLOWED -> { + MappedRange.Constant(rangeStart, mapping.type) } - } - TYPE_IGNORED, TYPE_VALID, TYPE_DISALLOWED -> { - MappedRange.Constant(rangeStart, mapping.type) + else -> error("unexpected mapping type: ${mapping.type}") } - - else -> error("unexpected mapping type: ${mapping.type}") - } } for (sectionList in result.values) { @@ -202,18 +204,20 @@ internal fun withoutSectionSpans(mappings: List): List { while (true) { if (current.spansSections) { - result += Mapping( - current.sourceCodePoint0, - current.section + 0x7f, - current.type, - current.mappedTo, - ) - current = Mapping( - current.section + 0x80, - current.sourceCodePoint1, - current.type, - current.mappedTo, - ) + result += + Mapping( + current.sourceCodePoint0, + current.section + 0x7f, + current.type, + current.mappedTo, + ) + current = + Mapping( + current.section + 0x80, + current.sourceCodePoint1, + current.type, + current.mappedTo, + ) } else { result += current current = if (i.hasNext()) i.next() else break @@ -246,12 +250,13 @@ internal fun mergeAdjacentRanges(mappings: List): List { index++ } - result += Mapping( - sourceCodePoint0 = mapping.sourceCodePoint0, - sourceCodePoint1 = unionWith.sourceCodePoint1, - type = type, - mappedTo = mappedTo, - ) + result += + Mapping( + sourceCodePoint0 = mapping.sourceCodePoint0, + sourceCodePoint1 = unionWith.sourceCodePoint1, + type = type, + mappedTo = mappedTo, + ) } return result @@ -262,11 +267,13 @@ internal fun canonicalizeType(type: Int): Int { TYPE_IGNORED -> TYPE_IGNORED TYPE_MAPPED, - TYPE_DISALLOWED_STD3_MAPPED -> TYPE_MAPPED + TYPE_DISALLOWED_STD3_MAPPED, + -> TYPE_MAPPED TYPE_DEVIATION, TYPE_DISALLOWED_STD3_VALID, - TYPE_VALID -> TYPE_VALID + TYPE_VALID, + -> TYPE_VALID TYPE_DISALLOWED -> TYPE_DISALLOWED @@ -279,4 +286,3 @@ internal infix fun Byte.and(mask: Int): Int = toInt() and mask internal infix fun Short.and(mask: Int): Int = toInt() and mask internal infix fun Int.and(mask: Long): Long = toLong() and mask - diff --git a/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/SimpleIdnaMappingTable.kt b/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/SimpleIdnaMappingTable.kt index 37290aba8442..ed284136cc1f 100644 --- a/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/SimpleIdnaMappingTable.kt +++ b/okhttp-idna-mapping-table/src/main/kotlin/okhttp3/internal/idn/SimpleIdnaMappingTable.kt @@ -42,14 +42,18 @@ class SimpleIdnaMappingTable internal constructor( /** * Returns true if the [codePoint] was applied successfully. Returns false if it was disallowed. */ - fun map(codePoint: Int, sink: BufferedSink): Boolean { - val index = mappings.binarySearch { - when { - it.sourceCodePoint1 < codePoint -> -1 - it.sourceCodePoint0 > codePoint -> 1 - else -> 0 + fun map( + codePoint: Int, + sink: BufferedSink, + ): Boolean { + val index = + mappings.binarySearch { + when { + it.sourceCodePoint1 < codePoint -> -1 + it.sourceCodePoint0 > codePoint -> 1 + else -> 0 + } } - } // Code points must be in 0..0x10ffff. require(index in mappings.indices) { "unexpected code point: $codePoint" } @@ -77,24 +81,25 @@ class SimpleIdnaMappingTable internal constructor( } } - -private val optionsDelimiter = Options.of( - // 0. - ".".encodeUtf8(), - // 1. - " ".encodeUtf8(), - // 2. - ";".encodeUtf8(), - // 3. - "#".encodeUtf8(), - // 4. - "\n".encodeUtf8(), -) - -private val optionsDot = Options.of( - // 0. - ".".encodeUtf8(), -) +private val optionsDelimiter = + Options.of( + // 0. + ".".encodeUtf8(), + // 1. + " ".encodeUtf8(), + // 2. + ";".encodeUtf8(), + // 3. + "#".encodeUtf8(), + // 4. + "\n".encodeUtf8(), + ) + +private val optionsDot = + Options.of( + // 0. + ".".encodeUtf8(), + ) private const val DELIMITER_DOT = 0 private const val DELIMITER_SPACE = 1 @@ -102,22 +107,23 @@ private const val DELIMITER_SEMICOLON = 2 private const val DELIMITER_HASH = 3 private const val DELIMITER_NEWLINE = 4 -private val optionsType = Options.of( - // 0. - "deviation ".encodeUtf8(), - // 1. - "disallowed ".encodeUtf8(), - // 2. - "disallowed_STD3_mapped ".encodeUtf8(), - // 3. - "disallowed_STD3_valid ".encodeUtf8(), - // 4. - "ignored ".encodeUtf8(), - // 5. - "mapped ".encodeUtf8(), - // 6. - "valid ".encodeUtf8(), -) +private val optionsType = + Options.of( + // 0. + "deviation ".encodeUtf8(), + // 1. + "disallowed ".encodeUtf8(), + // 2. + "disallowed_STD3_mapped ".encodeUtf8(), + // 3. + "disallowed_STD3_valid ".encodeUtf8(), + // 4. + "ignored ".encodeUtf8(), + // 5. + "mapped ".encodeUtf8(), + // 6. + "valid ".encodeUtf8(), + ) internal const val TYPE_DEVIATION = 0 internal const val TYPE_DISALLOWED = 1 @@ -182,14 +188,15 @@ fun BufferedSource.readPlainTextIdnaMappingTable(): SimpleIdnaMappingTable { // "002F" or "0000..002C" val sourceCodePoint0 = readHexadecimalUnsignedLong() - val sourceCodePoint1 = when (select(optionsDot)) { - DELIMITER_DOT -> { - if (readByte() != '.'.code.toByte()) throw IOException("expected '..'") - readHexadecimalUnsignedLong() - } + val sourceCodePoint1 = + when (select(optionsDot)) { + DELIMITER_DOT -> { + if (readByte() != '.'.code.toByte()) throw IOException("expected '..'") + readHexadecimalUnsignedLong() + } - else -> sourceCodePoint0 - } + else -> sourceCodePoint0 + } skipWhitespace() if (readByte() != ';'.code.toByte()) throw IOException("expected ';'") @@ -228,12 +235,13 @@ fun BufferedSource.readPlainTextIdnaMappingTable(): SimpleIdnaMappingTable { skipRestOfLine() - result += Mapping( - sourceCodePoint0.toInt(), - sourceCodePoint1.toInt(), - type, - mappedTo.readByteString(), - ) + result += + Mapping( + sourceCodePoint0.toInt(), + sourceCodePoint1.toInt(), + type, + mappedTo.readByteString(), + ) } return SimpleIdnaMappingTable(result) diff --git a/okhttp-idna-mapping-table/src/test/kotlin/okhttp3/internal/idn/MappingTablesTest.kt b/okhttp-idna-mapping-table/src/test/kotlin/okhttp3/internal/idn/MappingTablesTest.kt index 2e5351ef59ca..feb300d61a1a 100644 --- a/okhttp-idna-mapping-table/src/test/kotlin/okhttp3/internal/idn/MappingTablesTest.kt +++ b/okhttp-idna-mapping-table/src/test/kotlin/okhttp3/internal/idn/MappingTablesTest.kt @@ -34,8 +34,8 @@ class MappingTablesTest { Mapping(0x0234, 0x0236, TYPE_VALID, ByteString.EMPTY), Mapping(0x0237, 0x0239, TYPE_VALID, ByteString.EMPTY), Mapping(0x023a, 0x023a, TYPE_MAPPED, "b".encodeUtf8()), - ) - ) + ), + ), ).containsExactly( Mapping(0x0232, 0x0232, TYPE_MAPPED, "a".encodeUtf8()), Mapping(0x0233, 0x0239, TYPE_VALID, ByteString.EMPTY), @@ -49,8 +49,8 @@ class MappingTablesTest { listOf( Mapping(0x0041, 0x0041, TYPE_MAPPED, "a".encodeUtf8()), Mapping(0x0042, 0x0042, TYPE_MAPPED, "b".encodeUtf8()), - ) - ) + ), + ), ).containsExactly( Mapping(0x0041, 0x0041, TYPE_MAPPED, "a".encodeUtf8()), Mapping(0x0042, 0x0042, TYPE_MAPPED, "b".encodeUtf8()), @@ -62,8 +62,8 @@ class MappingTablesTest { mergeAdjacentRanges( listOf( Mapping(0x0000, 0x002c, TYPE_DISALLOWED_STD3_VALID, ByteString.EMPTY), - ) - ) + ), + ), ).containsExactly( Mapping(0x0000, 0x002c, TYPE_VALID, ByteString.EMPTY), ) @@ -74,9 +74,9 @@ class MappingTablesTest { mergeAdjacentRanges( listOf( Mapping(0x0000, 0x002c, TYPE_DISALLOWED_STD3_VALID, ByteString.EMPTY), - Mapping(0x002d, 0x002e, TYPE_VALID, ByteString.EMPTY) - ) - ) + Mapping(0x002d, 0x002e, TYPE_VALID, ByteString.EMPTY), + ), + ), ).containsExactly( Mapping(0x0000, 0x002e, TYPE_VALID, ByteString.EMPTY), ) @@ -87,8 +87,8 @@ class MappingTablesTest { withoutSectionSpans( listOf( Mapping(0x40000, 0x40180, TYPE_DISALLOWED, ByteString.EMPTY), - ) - ) + ), + ), ).containsExactly( Mapping(0x40000, 0x4007f, TYPE_DISALLOWED, ByteString.EMPTY), Mapping(0x40080, 0x400ff, TYPE_DISALLOWED, ByteString.EMPTY), @@ -103,8 +103,8 @@ class MappingTablesTest { listOf( Mapping(0x40000, 0x4007f, TYPE_DISALLOWED, ByteString.EMPTY), Mapping(0x40080, 0x400ff, TYPE_DISALLOWED, ByteString.EMPTY), - ) - ) + ), + ), ).containsExactly( Mapping(0x40000, 0x4007f, TYPE_DISALLOWED, ByteString.EMPTY), Mapping(0x40080, 0x400ff, TYPE_DISALLOWED, ByteString.EMPTY), @@ -119,8 +119,8 @@ class MappingTablesTest { InlineDelta(2, 5), InlineDelta(3, 5), MappedRange.External(4, "a".encodeUtf8()), - ) - ) + ), + ), ).containsExactly( InlineDelta(1, 5), MappedRange.External(4, "a".encodeUtf8()), @@ -134,8 +134,8 @@ class MappingTablesTest { InlineDelta(1, 5), InlineDelta(2, 5), InlineDelta(3, 1), - ) - ) + ), + ), ).containsExactly( InlineDelta(1, 5), InlineDelta(3, 1), @@ -148,9 +148,9 @@ class MappingTablesTest { mappingOf( sourceCodePoint0 = 1, sourceCodePoint1 = 1, - mappedToCodePoints = listOf(2) - ) - ) + mappedToCodePoints = listOf(2), + ), + ), ).isEqualTo(InlineDelta(1, 1)) assertThat( @@ -158,9 +158,9 @@ class MappingTablesTest { mappingOf( sourceCodePoint0 = 2, sourceCodePoint1 = 2, - mappedToCodePoints = listOf(1) - ) - ) + mappedToCodePoints = listOf(1), + ), + ), ).isEqualTo(InlineDelta(2, -1)) } @@ -170,9 +170,9 @@ class MappingTablesTest { mappingOf( sourceCodePoint0 = 2, sourceCodePoint1 = 3, - mappedToCodePoints = listOf(2) - ) - ) + mappedToCodePoints = listOf(2), + ), + ), ).isEqualTo(null) } @@ -182,9 +182,9 @@ class MappingTablesTest { mappingOf( sourceCodePoint0 = 1, sourceCodePoint1 = 1, - mappedToCodePoints = listOf(2, 3) - ) - ) + mappedToCodePoints = listOf(2, 3), + ), + ), ).isEqualTo(null) } @@ -194,14 +194,14 @@ class MappingTablesTest { mappingOf( sourceCodePoint0 = 0, sourceCodePoint1 = 0, - mappedToCodePoints = listOf((1 shl 18) - 1) - ) - ) + mappedToCodePoints = listOf((1 shl 18) - 1), + ), + ), ).isEqualTo( InlineDelta( rangeStart = 0, - codepointDelta = InlineDelta.MAX_VALUE - ) + codepointDelta = InlineDelta.MAX_VALUE, + ), ) assertThat( @@ -209,24 +209,26 @@ class MappingTablesTest { mappingOf( sourceCodePoint0 = 0, sourceCodePoint1 = 0, - mappedToCodePoints = listOf(1 shl 18) - ) - ) + mappedToCodePoints = listOf(1 shl 18), + ), + ), ).isEqualTo(null) } private fun mappingOf( sourceCodePoint0: Int, sourceCodePoint1: Int, - mappedToCodePoints: List - ): Mapping = Mapping( - sourceCodePoint0 = sourceCodePoint0, - sourceCodePoint1 = sourceCodePoint1, - type = TYPE_MAPPED, - mappedTo = Buffer().also { - for (cp in mappedToCodePoints) { - it.writeUtf8CodePoint(cp) - } - }.readByteString() - ) + mappedToCodePoints: List, + ): Mapping = + Mapping( + sourceCodePoint0 = sourceCodePoint0, + sourceCodePoint1 = sourceCodePoint1, + type = TYPE_MAPPED, + mappedTo = + Buffer().also { + for (cp in mappedToCodePoints) { + it.writeUtf8CodePoint(cp) + } + }.readByteString(), + ) } diff --git a/okhttp-java-net-cookiejar/src/main/kotlin/okhttp3/java/net/cookiejar/JavaNetCookieJar.kt b/okhttp-java-net-cookiejar/src/main/kotlin/okhttp3/java/net/cookiejar/JavaNetCookieJar.kt index 2e2ecb80b044..3c4d94d4d3eb 100644 --- a/okhttp-java-net-cookiejar/src/main/kotlin/okhttp3/java/net/cookiejar/JavaNetCookieJar.kt +++ b/okhttp-java-net-cookiejar/src/main/kotlin/okhttp3/java/net/cookiejar/JavaNetCookieJar.kt @@ -14,8 +14,8 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") -package okhttp3.java.net.cookiejar +package okhttp3.java.net.cookiejar import java.io.IOException import java.net.CookieHandler @@ -32,8 +32,10 @@ import okhttp3.internal.trimSubstring /** A cookie jar that delegates to a [java.net.CookieHandler]. */ class JavaNetCookieJar(private val cookieHandler: CookieHandler) : CookieJar { - - override fun saveFromResponse(url: HttpUrl, cookies: List) { + override fun saveFromResponse( + url: HttpUrl, + cookies: List, + ) { val cookieStrings = mutableListOf() for (cookie in cookies) { cookieStrings.add(cookieToString(cookie, true)) @@ -47,18 +49,20 @@ class JavaNetCookieJar(private val cookieHandler: CookieHandler) : CookieJar { } override fun loadForRequest(url: HttpUrl): List { - val cookieHeaders = try { - // The RI passes all headers. We don't have 'em, so we don't pass 'em! - cookieHandler.get(url.toUri(), emptyMap>()) - } catch (e: IOException) { - Platform.get().log("Loading cookies failed for " + url.resolve("/...")!!, WARN, e) - return emptyList() - } + val cookieHeaders = + try { + // The RI passes all headers. We don't have 'em, so we don't pass 'em! + cookieHandler.get(url.toUri(), emptyMap>()) + } catch (e: IOException) { + Platform.get().log("Loading cookies failed for " + url.resolve("/...")!!, WARN, e) + return emptyList() + } var cookies: MutableList? = null for ((key, value) in cookieHeaders) { if (("Cookie".equals(key, ignoreCase = true) || "Cookie2".equals(key, ignoreCase = true)) && - value.isNotEmpty()) { + value.isNotEmpty() + ) { for (header in value) { if (cookies == null) cookies = mutableListOf() cookies.addAll(decodeHeaderAsJavaNetCookies(url, header)) @@ -77,7 +81,10 @@ class JavaNetCookieJar(private val cookieHandler: CookieHandler) : CookieJar { * Convert a request header to OkHttp's cookies via [HttpCookie]. That extra step handles * multiple cookies in a single request header, which [Cookie.parse] doesn't support. */ - private fun decodeHeaderAsJavaNetCookies(url: HttpUrl, header: String): List { + private fun decodeHeaderAsJavaNetCookies( + url: HttpUrl, + header: String, + ): List { val result = mutableListOf() var pos = 0 val limit = header.length @@ -92,22 +99,25 @@ class JavaNetCookieJar(private val cookieHandler: CookieHandler) : CookieJar { } // We have either name=value or just a name. - var value = if (equalsSign < pairEnd) { - header.trimSubstring(equalsSign + 1, pairEnd) - } else { - "" - } + var value = + if (equalsSign < pairEnd) { + header.trimSubstring(equalsSign + 1, pairEnd) + } else { + "" + } // If the value is "quoted", drop the quotes. if (value.startsWith("\"") && value.endsWith("\"") && value.length >= 2) { value = value.substring(1, value.length - 1) } - result.add(Cookie.Builder() + result.add( + Cookie.Builder() .name(name) .value(value) .domain(url.host) - .build()) + .build(), + ) pos = pairEnd + 1 } return result diff --git a/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt b/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt index 2761da7e29d2..3f247d41c3f6 100644 --- a/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt +++ b/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3.logging import java.io.IOException @@ -38,288 +39,295 @@ import okio.GzipSource * The format of the logs created by this class should not be considered stable and may * change slightly between releases. If you need a stable logging format, use your own interceptor. */ -class HttpLoggingInterceptor @JvmOverloads constructor( - private val logger: Logger = Logger.DEFAULT -) : Interceptor { - - @Volatile private var headersToRedact = emptySet() +class HttpLoggingInterceptor + @JvmOverloads + constructor( + private val logger: Logger = Logger.DEFAULT, + ) : Interceptor { + @Volatile private var headersToRedact = emptySet() + + @set:JvmName("level") + @Volatile + var level = Level.NONE + + enum class Level { + /** No logs. */ + NONE, + + /** + * Logs request and response lines. + * + * Example: + * ``` + * --> POST /greeting http/1.1 (3-byte body) + * + * <-- 200 OK (22ms, 6-byte body) + * ``` + */ + BASIC, + + /** + * Logs request and response lines and their respective headers. + * + * Example: + * ``` + * --> POST /greeting http/1.1 + * Host: example.com + * Content-Type: plain/text + * Content-Length: 3 + * --> END POST + * + * <-- 200 OK (22ms) + * Content-Type: plain/text + * Content-Length: 6 + * <-- END HTTP + * ``` + */ + HEADERS, + + /** + * Logs request and response lines and their respective headers and bodies (if present). + * + * Example: + * ``` + * --> POST /greeting http/1.1 + * Host: example.com + * Content-Type: plain/text + * Content-Length: 3 + * + * Hi? + * --> END POST + * + * <-- 200 OK (22ms) + * Content-Type: plain/text + * Content-Length: 6 + * + * Hello! + * <-- END HTTP + * ``` + */ + BODY, + } - @set:JvmName("level") - @Volatile var level = Level.NONE + fun interface Logger { + fun log(message: String) - enum class Level { - /** No logs. */ - NONE, + companion object { + /** A [Logger] defaults output appropriate for the current platform. */ + @JvmField + val DEFAULT: Logger = DefaultLogger() - /** - * Logs request and response lines. - * - * Example: - * ``` - * --> POST /greeting http/1.1 (3-byte body) - * - * <-- 200 OK (22ms, 6-byte body) - * ``` - */ - BASIC, + private class DefaultLogger : Logger { + override fun log(message: String) { + Platform.get().log(message) + } + } + } + } - /** - * Logs request and response lines and their respective headers. - * - * Example: - * ``` - * --> POST /greeting http/1.1 - * Host: example.com - * Content-Type: plain/text - * Content-Length: 3 - * --> END POST - * - * <-- 200 OK (22ms) - * Content-Type: plain/text - * Content-Length: 6 - * <-- END HTTP - * ``` - */ - HEADERS, + fun redactHeader(name: String) { + val newHeadersToRedact = TreeSet(String.CASE_INSENSITIVE_ORDER) + newHeadersToRedact += headersToRedact + newHeadersToRedact += name + headersToRedact = newHeadersToRedact + } /** - * Logs request and response lines and their respective headers and bodies (if present). - * - * Example: - * ``` - * --> POST /greeting http/1.1 - * Host: example.com - * Content-Type: plain/text - * Content-Length: 3 - * - * Hi? - * --> END POST - * - * <-- 200 OK (22ms) - * Content-Type: plain/text - * Content-Length: 6 + * Sets the level and returns this. * - * Hello! - * <-- END HTTP - * ``` + * This was deprecated in OkHttp 4.0 in favor of the [level] val. In OkHttp 4.3 it is + * un-deprecated because Java callers can't chain when assigning Kotlin vals. (The getter remains + * deprecated). */ - BODY - } - - fun interface Logger { - fun log(message: String) - - companion object { - /** A [Logger] defaults output appropriate for the current platform. */ - @JvmField - val DEFAULT: Logger = DefaultLogger() - private class DefaultLogger : Logger { - override fun log(message: String) { - Platform.get().log(message) - } + fun setLevel(level: Level) = + apply { + this.level = level } - } - } - - fun redactHeader(name: String) { - val newHeadersToRedact = TreeSet(String.CASE_INSENSITIVE_ORDER) - newHeadersToRedact += headersToRedact - newHeadersToRedact += name - headersToRedact = newHeadersToRedact - } - - /** - * Sets the level and returns this. - * - * This was deprecated in OkHttp 4.0 in favor of the [level] val. In OkHttp 4.3 it is - * un-deprecated because Java callers can't chain when assigning Kotlin vals. (The getter remains - * deprecated). - */ - fun setLevel(level: Level) = apply { - this.level = level - } - @JvmName("-deprecated_level") - @Deprecated( + @JvmName("-deprecated_level") + @Deprecated( message = "moved to var", replaceWith = ReplaceWith(expression = "level"), - level = DeprecationLevel.ERROR - ) - fun getLevel(): Level = level + level = DeprecationLevel.ERROR, + ) + fun getLevel(): Level = level - @Throws(IOException::class) - override fun intercept(chain: Interceptor.Chain): Response { - val level = this.level + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response { + val level = this.level - val request = chain.request() - if (level == Level.NONE) { - return chain.proceed(request) - } + val request = chain.request() + if (level == Level.NONE) { + return chain.proceed(request) + } - val logBody = level == Level.BODY - val logHeaders = logBody || level == Level.HEADERS + val logBody = level == Level.BODY + val logHeaders = logBody || level == Level.HEADERS - val requestBody = request.body + val requestBody = request.body - val connection = chain.connection() - var requestStartMessage = + val connection = chain.connection() + var requestStartMessage = ("--> ${request.method} ${request.url}${if (connection != null) " " + connection.protocol() else ""}") - if (!logHeaders && requestBody != null) { - requestStartMessage += " (${requestBody.contentLength()}-byte body)" - } - logger.log(requestStartMessage) + if (!logHeaders && requestBody != null) { + requestStartMessage += " (${requestBody.contentLength()}-byte body)" + } + logger.log(requestStartMessage) + + if (logHeaders) { + val headers = request.headers + + if (requestBody != null) { + // Request body headers are only present when installed as a network interceptor. When not + // already present, force them to be included (if available) so their values are known. + requestBody.contentType()?.let { + if (headers["Content-Type"] == null) { + logger.log("Content-Type: $it") + } + } + if (requestBody.contentLength() != -1L) { + if (headers["Content-Length"] == null) { + logger.log("Content-Length: ${requestBody.contentLength()}") + } + } + } - if (logHeaders) { - val headers = request.headers + for (i in 0 until headers.size) { + logHeader(headers, i) + } - if (requestBody != null) { - // Request body headers are only present when installed as a network interceptor. When not - // already present, force them to be included (if available) so their values are known. - requestBody.contentType()?.let { - if (headers["Content-Type"] == null) { - logger.log("Content-Type: $it") + if (!logBody || requestBody == null) { + logger.log("--> END ${request.method}") + } else if (bodyHasUnknownEncoding(request.headers)) { + logger.log("--> END ${request.method} (encoded body omitted)") + } else if (requestBody.isDuplex()) { + logger.log("--> END ${request.method} (duplex request body omitted)") + } else if (requestBody.isOneShot()) { + logger.log("--> END ${request.method} (one-shot body omitted)") + } else { + var buffer = Buffer() + requestBody.writeTo(buffer) + + var gzippedLength: Long? = null + if ("gzip".equals(headers["Content-Encoding"], ignoreCase = true)) { + gzippedLength = buffer.size + GzipSource(buffer).use { gzippedResponseBody -> + buffer = Buffer() + buffer.writeAll(gzippedResponseBody) + } } - } - if (requestBody.contentLength() != -1L) { - if (headers["Content-Length"] == null) { - logger.log("Content-Length: ${requestBody.contentLength()}") + + val charset: Charset = requestBody.contentType().charsetOrUtf8() + + logger.log("") + if (!buffer.isProbablyUtf8()) { + logger.log( + "--> END ${request.method} (binary ${requestBody.contentLength()}-byte body omitted)", + ) + } else if (gzippedLength != null) { + logger.log("--> END ${request.method} (${buffer.size}-byte, $gzippedLength-gzipped-byte body)") + } else { + logger.log(buffer.readString(charset)) + logger.log("--> END ${request.method} (${requestBody.contentLength()}-byte body)") } } } - for (i in 0 until headers.size) { - logHeader(headers, i) + val startNs = System.nanoTime() + val response: Response + try { + response = chain.proceed(request) + } catch (e: Exception) { + logger.log("<-- HTTP FAILED: $e") + throw e } - if (!logBody || requestBody == null) { - logger.log("--> END ${request.method}") - } else if (bodyHasUnknownEncoding(request.headers)) { - logger.log("--> END ${request.method} (encoded body omitted)") - } else if (requestBody.isDuplex()) { - logger.log("--> END ${request.method} (duplex request body omitted)") - } else if (requestBody.isOneShot()) { - logger.log("--> END ${request.method} (one-shot body omitted)") - } else { - var buffer = Buffer() - requestBody.writeTo(buffer) - - var gzippedLength: Long? = null - if ("gzip".equals(headers["Content-Encoding"], ignoreCase = true)) { - gzippedLength = buffer.size - GzipSource(buffer).use { gzippedResponseBody -> - buffer = Buffer() - buffer.writeAll(gzippedResponseBody) - } + val tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs) + + val responseBody = response.body!! + val contentLength = responseBody.contentLength() + val bodySize = if (contentLength != -1L) "$contentLength-byte" else "unknown-length" + logger.log( + buildString { + append("<-- ${response.code}") + if (response.message.isNotEmpty()) append(" ${response.message}") + append(" ${response.request.url} (${tookMs}ms") + if (!logHeaders) append(", $bodySize body") + append(")") + }, + ) + + if (logHeaders) { + val headers = response.headers + for (i in 0 until headers.size) { + logHeader(headers, i) } - val charset: Charset = requestBody.contentType().charsetOrUtf8() - - logger.log("") - if (!buffer.isProbablyUtf8()) { - logger.log( - "--> END ${request.method} (binary ${requestBody.contentLength()}-byte body omitted)" - ) - } else if (gzippedLength != null) { - logger.log("--> END ${request.method} (${buffer.size}-byte, $gzippedLength-gzipped-byte body)") + if (!logBody || !response.promisesBody()) { + logger.log("<-- END HTTP") + } else if (bodyHasUnknownEncoding(response.headers)) { + logger.log("<-- END HTTP (encoded body omitted)") + } else if (bodyIsStreaming(response)) { + logger.log("<-- END HTTP (streaming)") } else { - logger.log(buffer.readString(charset)) - logger.log("--> END ${request.method} (${requestBody.contentLength()}-byte body)") - } - } - } + val source = responseBody.source() + source.request(Long.MAX_VALUE) // Buffer the entire body. - val startNs = System.nanoTime() - val response: Response - try { - response = chain.proceed(request) - } catch (e: Exception) { - logger.log("<-- HTTP FAILED: $e") - throw e - } + val totalMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs) - val tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs) - - val responseBody = response.body!! - val contentLength = responseBody.contentLength() - val bodySize = if (contentLength != -1L) "$contentLength-byte" else "unknown-length" - logger.log( - buildString { - append("<-- ${response.code}") - if (response.message.isNotEmpty()) append(" ${response.message}") - append(" ${response.request.url} (${tookMs}ms") - if (!logHeaders) append(", $bodySize body") - append(")") - } - ) - - if (logHeaders) { - val headers = response.headers - for (i in 0 until headers.size) { - logHeader(headers, i) - } + var buffer = source.buffer - if (!logBody || !response.promisesBody()) { - logger.log("<-- END HTTP") - } else if (bodyHasUnknownEncoding(response.headers)) { - logger.log("<-- END HTTP (encoded body omitted)") - } else if (bodyIsStreaming(response)) { - logger.log("<-- END HTTP (streaming)") - } else { - val source = responseBody.source() - source.request(Long.MAX_VALUE) // Buffer the entire body. - - val totalMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs) - - var buffer = source.buffer - - var gzippedLength: Long? = null - if ("gzip".equals(headers["Content-Encoding"], ignoreCase = true)) { - gzippedLength = buffer.size - GzipSource(buffer.clone()).use { gzippedResponseBody -> - buffer = Buffer() - buffer.writeAll(gzippedResponseBody) + var gzippedLength: Long? = null + if ("gzip".equals(headers["Content-Encoding"], ignoreCase = true)) { + gzippedLength = buffer.size + GzipSource(buffer.clone()).use { gzippedResponseBody -> + buffer = Buffer() + buffer.writeAll(gzippedResponseBody) + } } - } - val charset: Charset = responseBody.contentType().charsetOrUtf8() + val charset: Charset = responseBody.contentType().charsetOrUtf8() - if (!buffer.isProbablyUtf8()) { - logger.log("") - logger.log("<-- END HTTP (${totalMs}ms, binary ${buffer.size}-byte body omitted)") - return response - } - - if (contentLength != 0L) { - logger.log("") - logger.log(buffer.clone().readString(charset)) - } + if (!buffer.isProbablyUtf8()) { + logger.log("") + logger.log("<-- END HTTP (${totalMs}ms, binary ${buffer.size}-byte body omitted)") + return response + } - logger.log( - buildString { - append("<-- END HTTP (${totalMs}ms, ${buffer.size}-byte") - if (gzippedLength != null) append(", $gzippedLength-gzipped-byte") - append(" body)") + if (contentLength != 0L) { + logger.log("") + logger.log(buffer.clone().readString(charset)) } - ) + + logger.log( + buildString { + append("<-- END HTTP (${totalMs}ms, ${buffer.size}-byte") + if (gzippedLength != null) append(", $gzippedLength-gzipped-byte") + append(" body)") + }, + ) + } } - } - return response - } + return response + } - private fun logHeader(headers: Headers, i: Int) { - val value = if (headers.name(i) in headersToRedact) "██" else headers.value(i) - logger.log(headers.name(i) + ": " + value) - } + private fun logHeader( + headers: Headers, + i: Int, + ) { + val value = if (headers.name(i) in headersToRedact) "██" else headers.value(i) + logger.log(headers.name(i) + ": " + value) + } - private fun bodyHasUnknownEncoding(headers: Headers): Boolean { - val contentEncoding = headers["Content-Encoding"] ?: return false - return !contentEncoding.equals("identity", ignoreCase = true) && + private fun bodyHasUnknownEncoding(headers: Headers): Boolean { + val contentEncoding = headers["Content-Encoding"] ?: return false + return !contentEncoding.equals("identity", ignoreCase = true) && !contentEncoding.equals("gzip", ignoreCase = true) - } + } - private fun bodyIsStreaming(response: Response): Boolean { - val contentType = response.body.contentType() - return contentType != null && contentType.type == "text" && contentType.subtype == "event-stream" + private fun bodyIsStreaming(response: Response): Boolean { + val contentType = response.body.contentType() + return contentType != null && contentType.type == "text" && contentType.subtype == "event-stream" + } } -} diff --git a/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/LoggingEventListener.kt b/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/LoggingEventListener.kt index dfd894a70102..35588a6bff2a 100644 --- a/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/LoggingEventListener.kt +++ b/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/LoggingEventListener.kt @@ -38,7 +38,7 @@ import okhttp3.Response * slightly between releases. If you need a stable logging format, use your own event listener. */ class LoggingEventListener private constructor( - private val logger: HttpLoggingInterceptor.Logger + private val logger: HttpLoggingInterceptor.Logger, ) : EventListener() { private var startNs: Long = 0 @@ -48,23 +48,41 @@ class LoggingEventListener private constructor( logWithTime("callStart: ${call.request()}") } - override fun proxySelectStart(call: Call, url: HttpUrl) { + override fun proxySelectStart( + call: Call, + url: HttpUrl, + ) { logWithTime("proxySelectStart: $url") } - override fun proxySelectEnd(call: Call, url: HttpUrl, proxies: List) { + override fun proxySelectEnd( + call: Call, + url: HttpUrl, + proxies: List, + ) { logWithTime("proxySelectEnd: $proxies") } - override fun dnsStart(call: Call, domainName: String) { + override fun dnsStart( + call: Call, + domainName: String, + ) { logWithTime("dnsStart: $domainName") } - override fun dnsEnd(call: Call, domainName: String, inetAddressList: List) { + override fun dnsEnd( + call: Call, + domainName: String, + inetAddressList: List, + ) { logWithTime("dnsEnd: $inetAddressList") } - override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) { + override fun connectStart( + call: Call, + inetSocketAddress: InetSocketAddress, + proxy: Proxy, + ) { logWithTime("connectStart: $inetSocketAddress $proxy") } @@ -72,7 +90,10 @@ class LoggingEventListener private constructor( logWithTime("secureConnectStart") } - override fun secureConnectEnd(call: Call, handshake: Handshake?) { + override fun secureConnectEnd( + call: Call, + handshake: Handshake?, + ) { logWithTime("secureConnectEnd: $handshake") } @@ -80,7 +101,7 @@ class LoggingEventListener private constructor( call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, - protocol: Protocol? + protocol: Protocol?, ) { logWithTime("connectEnd: $protocol") } @@ -90,16 +111,22 @@ class LoggingEventListener private constructor( inetSocketAddress: InetSocketAddress, proxy: Proxy, protocol: Protocol?, - ioe: IOException + ioe: IOException, ) { logWithTime("connectFailed: $protocol $ioe") } - override fun connectionAcquired(call: Call, connection: Connection) { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { logWithTime("connectionAcquired: $connection") } - override fun connectionReleased(call: Call, connection: Connection) { + override fun connectionReleased( + call: Call, + connection: Connection, + ) { logWithTime("connectionReleased") } @@ -107,7 +134,10 @@ class LoggingEventListener private constructor( logWithTime("requestHeadersStart") } - override fun requestHeadersEnd(call: Call, request: Request) { + override fun requestHeadersEnd( + call: Call, + request: Request, + ) { logWithTime("requestHeadersEnd") } @@ -115,11 +145,17 @@ class LoggingEventListener private constructor( logWithTime("requestBodyStart") } - override fun requestBodyEnd(call: Call, byteCount: Long) { + override fun requestBodyEnd( + call: Call, + byteCount: Long, + ) { logWithTime("requestBodyEnd: byteCount=$byteCount") } - override fun requestFailed(call: Call, ioe: IOException) { + override fun requestFailed( + call: Call, + ioe: IOException, + ) { logWithTime("requestFailed: $ioe") } @@ -127,7 +163,10 @@ class LoggingEventListener private constructor( logWithTime("responseHeadersStart") } - override fun responseHeadersEnd(call: Call, response: Response) { + override fun responseHeadersEnd( + call: Call, + response: Response, + ) { logWithTime("responseHeadersEnd: $response") } @@ -135,11 +174,17 @@ class LoggingEventListener private constructor( logWithTime("responseBodyStart") } - override fun responseBodyEnd(call: Call, byteCount: Long) { + override fun responseBodyEnd( + call: Call, + byteCount: Long, + ) { logWithTime("responseBodyEnd: byteCount=$byteCount") } - override fun responseFailed(call: Call, ioe: IOException) { + override fun responseFailed( + call: Call, + ioe: IOException, + ) { logWithTime("responseFailed: $ioe") } @@ -147,7 +192,10 @@ class LoggingEventListener private constructor( logWithTime("callEnd") } - override fun callFailed(call: Call, ioe: IOException) { + override fun callFailed( + call: Call, + ioe: IOException, + ) { logWithTime("callFailed: $ioe") } @@ -155,11 +203,17 @@ class LoggingEventListener private constructor( logWithTime("canceled") } - override fun satisfactionFailure(call: Call, response: Response) { + override fun satisfactionFailure( + call: Call, + response: Response, + ) { logWithTime("satisfactionFailure: $response") } - override fun cacheHit(call: Call, response: Response) { + override fun cacheHit( + call: Call, + response: Response, + ) { logWithTime("cacheHit: $response") } @@ -167,7 +221,10 @@ class LoggingEventListener private constructor( logWithTime("cacheMiss") } - override fun cacheConditionalHit(call: Call, cachedResponse: Response) { + override fun cacheConditionalHit( + call: Call, + cachedResponse: Response, + ) { logWithTime("cacheConditionalHit: $cachedResponse") } @@ -176,9 +233,11 @@ class LoggingEventListener private constructor( logger.log("[$timeMs ms] $message") } - open class Factory @JvmOverloads constructor( - private val logger: HttpLoggingInterceptor.Logger = HttpLoggingInterceptor.Logger.DEFAULT - ) : EventListener.Factory { - override fun create(call: Call): EventListener = LoggingEventListener(logger) - } + open class Factory + @JvmOverloads + constructor( + private val logger: HttpLoggingInterceptor.Logger = HttpLoggingInterceptor.Logger.DEFAULT, + ) : EventListener.Factory { + override fun create(call: Call): EventListener = LoggingEventListener(logger) + } } diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt index ccecfb4427b6..9f50930f476c 100644 --- a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt @@ -72,21 +72,24 @@ class HttpLoggingInterceptorTest { @BeforeEach fun setUp(server: MockWebServer) { this.server = server - client = OkHttpClient.Builder() - .addNetworkInterceptor(Interceptor { chain -> - when { - extraNetworkInterceptor != null -> extraNetworkInterceptor!!.intercept(chain) - else -> chain.proceed(chain.request()) - } - }) - .addNetworkInterceptor(networkInterceptor) - .addInterceptor(applicationInterceptor) - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager, - ) - .hostnameVerifier(hostnameVerifier) - .build() + client = + OkHttpClient.Builder() + .addNetworkInterceptor( + Interceptor { chain -> + when { + extraNetworkInterceptor != null -> extraNetworkInterceptor!!.intercept(chain) + else -> chain.proceed(chain.request()) + } + }, + ) + .addNetworkInterceptor(networkInterceptor) + .addInterceptor(applicationInterceptor) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(hostnameVerifier) + .build() host = "${server.hostName}:${server.port}" url = server.url("/") } @@ -153,7 +156,7 @@ class HttpLoggingInterceptorTest { MockResponse.Builder() .body("Hello!") .setHeader("Content-Type", PLAIN) - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -174,7 +177,7 @@ class HttpLoggingInterceptorTest { MockResponse.Builder() .chunkedBody("Hello!", 2) .setHeader("Content-Type", PLAIN) - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -278,13 +281,14 @@ class HttpLoggingInterceptorTest { fun headersPostNoLength() { setLevel(Level.HEADERS) server.enqueue(MockResponse()) - val body: RequestBody = object : RequestBody() { - override fun contentType() = PLAIN + val body: RequestBody = + object : RequestBody() { + override fun contentType() = PLAIN - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("Hi!") + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("Hi!") + } } - } val response = client.newCall(request().post(body).build()).execute() response.body.close() applicationLogs @@ -313,20 +317,21 @@ class HttpLoggingInterceptorTest { @Test fun headersPostWithHeaderOverrides() { setLevel(Level.HEADERS) - extraNetworkInterceptor = Interceptor { chain: Interceptor.Chain -> - chain.proceed( - chain.request() - .newBuilder() - .header("Content-Length", "2") - .header("Content-Type", "text/plain-ish") - .build() - ) - } + extraNetworkInterceptor = + Interceptor { chain: Interceptor.Chain -> + chain.proceed( + chain.request() + .newBuilder() + .header("Content-Length", "2") + .header("Content-Type", "text/plain-ish") + .build(), + ) + } server.enqueue(MockResponse()) client.newCall( request() .post("Hi?".toRequestBody(PLAIN)) - .build() + .build(), ).execute() applicationLogs .assertLogEqual("--> POST $url") @@ -359,7 +364,7 @@ class HttpLoggingInterceptorTest { MockResponse.Builder() .body("Hello!") .setHeader("Content-Type", PLAIN) - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -427,7 +432,7 @@ class HttpLoggingInterceptorTest { server.enqueue( MockResponse.Builder() .status("HTTP/1.1 $code No Content") - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -493,7 +498,7 @@ class HttpLoggingInterceptorTest { MockResponse.Builder() .body("Hello!") .setHeader("Content-Type", PLAIN) - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -530,7 +535,7 @@ class HttpLoggingInterceptorTest { MockResponse.Builder() .chunkedBody("Hello!", 2) .setHeader("Content-Type", PLAIN) - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -567,14 +572,15 @@ class HttpLoggingInterceptorTest { MockResponse.Builder() .setHeader("Content-Type", PLAIN) .body(Buffer().writeUtf8("Uncompressed")) - .build() + .build(), ) - val response = client.newCall( - request() - .addHeader("Content-Encoding", "gzip") - .post("Uncompressed".toRequestBody().gzip()) - .build() - ).execute() + val response = + client.newCall( + request() + .addHeader("Content-Encoding", "gzip") + .post("Uncompressed".toRequestBody().gzip()) + .build(), + ).execute() val responseBody = response.body assertThat(responseBody.string(), "Expected response body to be valid") .isEqualTo("Uncompressed") @@ -606,7 +612,7 @@ class HttpLoggingInterceptorTest { .setHeader("Content-Encoding", "gzip") .setHeader("Content-Type", PLAIN) .body(Buffer().write("H4sIAAAAAAAAAPNIzcnJ11HwQKIAdyO+9hMAAAA=".decodeBase64()!!)) - .build() + .build(), ) val response = client.newCall(request().build()).execute() val responseBody = response.body @@ -647,7 +653,7 @@ class HttpLoggingInterceptorTest { .setHeader("Content-Encoding", "br") .setHeader("Content-Type", PLAIN) .body(Buffer().write("iwmASGVsbG8sIEhlbGxvLCBIZWxsbwoD".decodeBase64()!!)) - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -693,9 +699,10 @@ class HttpLoggingInterceptorTest { |data: 113411 | | - """.trimMargin(), 8 + """.trimMargin(), + 8, ) - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -728,7 +735,7 @@ class HttpLoggingInterceptorTest { MockResponse.Builder() .setHeader("Content-Type", "text/html; charset=0") .body("Body with unknown charset") - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -774,7 +781,7 @@ class HttpLoggingInterceptorTest { MockResponse.Builder() .body(buffer) .setHeader("Content-Type", "image/png; charset=utf-8") - .build() + .build(), ) val response = client.newCall(request().build()).execute() response.body.close() @@ -805,10 +812,11 @@ class HttpLoggingInterceptorTest { @Test fun connectFail() { setLevel(Level.BASIC) - client = OkHttpClient.Builder() - .dns { hostname: String? -> throw UnknownHostException("reason") } - .addInterceptor(applicationInterceptor) - .build() + client = + OkHttpClient.Builder() + .dns { hostname: String? -> throw UnknownHostException("reason") } + .addInterceptor(applicationInterceptor) + .build() try { client.newCall(request().build()).execute() fail() @@ -840,31 +848,35 @@ class HttpLoggingInterceptorTest { @Test fun headersAreRedacted() { - val networkInterceptor = HttpLoggingInterceptor(networkLogs).setLevel( - Level.HEADERS - ) + val networkInterceptor = + HttpLoggingInterceptor(networkLogs).setLevel( + Level.HEADERS, + ) networkInterceptor.redactHeader("sEnSiTiVe") - val applicationInterceptor = HttpLoggingInterceptor(applicationLogs).setLevel( - Level.HEADERS - ) + val applicationInterceptor = + HttpLoggingInterceptor(applicationLogs).setLevel( + Level.HEADERS, + ) applicationInterceptor.redactHeader("sEnSiTiVe") - client = OkHttpClient.Builder() - .addNetworkInterceptor(networkInterceptor) - .addInterceptor(applicationInterceptor) - .build() + client = + OkHttpClient.Builder() + .addNetworkInterceptor(networkInterceptor) + .addInterceptor(applicationInterceptor) + .build() server.enqueue( MockResponse.Builder() .addHeader("SeNsItIvE", "Value").addHeader("Not-Sensitive", "Value") - .build() + .build(), ) - val response = client - .newCall( - request() - .addHeader("SeNsItIvE", "Value") - .addHeader("Not-Sensitive", "Value") - .build() - ) - .execute() + val response = + client + .newCall( + request() + .addHeader("SeNsItIvE", "Value") + .addHeader("Not-Sensitive", "Value") + .build(), + ) + .execute() response.body.close() applicationLogs .assertLogEqual("--> GET $url") @@ -903,25 +915,27 @@ class HttpLoggingInterceptorTest { server.enqueue( MockResponse.Builder() .body("Hello response!") - .build() + .build(), ) - val asyncRequestBody: RequestBody = object : RequestBody() { - override fun contentType(): MediaType? { - return null - } + val asyncRequestBody: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType? { + return null + } - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("Hello request!") - sink.close() - } + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("Hello request!") + sink.close() + } - override fun isDuplex(): Boolean { - return true + override fun isDuplex(): Boolean { + return true + } } - } - val request = request() - .post(asyncRequestBody) - .build() + val request = + request() + .post(asyncRequestBody) + .build() val response = client.newCall(request).execute() Assumptions.assumeTrue(response.protocol == Protocol.HTTP_2) assertThat(response.body.string()).isEqualTo("Hello response!") @@ -943,25 +957,27 @@ class HttpLoggingInterceptorTest { server.enqueue( MockResponse.Builder() .body("Hello response!") - .build() + .build(), ) - val asyncRequestBody: RequestBody = object : RequestBody() { - var counter = 0 + val asyncRequestBody: RequestBody = + object : RequestBody() { + var counter = 0 - override fun contentType() = null + override fun contentType() = null - override fun writeTo(sink: BufferedSink) { - counter++ - assertThat(counter).isLessThanOrEqualTo(1) - sink.writeUtf8("Hello request!") - sink.close() - } + override fun writeTo(sink: BufferedSink) { + counter++ + assertThat(counter).isLessThanOrEqualTo(1) + sink.writeUtf8("Hello request!") + sink.close() + } - override fun isOneShot() = true - } - val request = request() - .post(asyncRequestBody) - .build() + override fun isOneShot() = true + } + val request = + request() + .post(asyncRequestBody) + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("Hello response!") applicationLogs @@ -985,19 +1001,21 @@ class HttpLoggingInterceptorTest { private val logs = mutableListOf() private var index = 0 - fun assertLogEqual(expected: String) = apply { - assertThat(index, "No more messages found") - .isLessThan(logs.size) - assertThat(logs[index++]).isEqualTo(expected) - return this - } + fun assertLogEqual(expected: String) = + apply { + assertThat(index, "No more messages found") + .isLessThan(logs.size) + assertThat(logs[index++]).isEqualTo(expected) + return this + } - fun assertLogMatch(regex: Regex) = apply { - assertThat(index, "No more messages found") - .isLessThan(logs.size) - assertThat(logs[index++]) - .matches(Regex(prefix.pattern + regex.pattern, RegexOption.DOT_MATCHES_ALL)) - } + fun assertLogMatch(regex: Regex) = + apply { + assertThat(index, "No more messages found") + .isLessThan(logs.size) + assertThat(logs[index++]) + .matches(Regex(prefix.pattern + regex.pattern, RegexOption.DOT_MATCHES_ALL)) + } fun assertNoMoreLogs() { assertThat(logs.size, "More messages remain: ${logs.subList(index, logs.size)}") diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.kt b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.kt index 68924e07ae93..e519a53cd91c 100644 --- a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.kt +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.kt @@ -50,9 +50,10 @@ class LoggingEventListenerTest { val clientTestRule = OkHttpClientTestRule() private lateinit var server: MockWebServer private val handshakeCertificates = platform.localhostHandshakeCertificates() - private val logRecorder = HttpLoggingInterceptorTest.LogRecorder( - prefix = Regex("""\[\d+ ms] """) - ) + private val logRecorder = + HttpLoggingInterceptorTest.LogRecorder( + prefix = Regex("""\[\d+ ms] """), + ) private val loggingEventListenerFactory = LoggingEventListener.Factory(logRecorder) private lateinit var client: OkHttpClient private lateinit var url: HttpUrl @@ -60,14 +61,15 @@ class LoggingEventListenerTest { @BeforeEach fun setUp(server: MockWebServer) { this.server = server - client = clientTestRule.newClientBuilder() - .eventListenerFactory(loggingEventListenerFactory) - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .retryOnConnectionFailure(false) - .build() + client = + clientTestRule.newClientBuilder() + .eventListenerFactory(loggingEventListenerFactory) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .retryOnConnectionFailure(false) + .build() url = server.url("/") } @@ -78,7 +80,7 @@ class LoggingEventListenerTest { MockResponse.Builder() .body("Hello!") .setHeader("Content-Type", PLAIN) - .build() + .build(), ) val response = client.newCall(request().build()).execute() assertThat(response.body).isNotNull() @@ -91,7 +93,11 @@ class LoggingEventListenerTest { .assertLogMatch(Regex("""dnsEnd: \[.+]""")) .assertLogMatch(Regex("""connectStart: ${url.host}/.+ DIRECT""")) .assertLogMatch(Regex("""connectEnd: http/1.1""")) - .assertLogMatch(Regex("""connectionAcquired: Connection\{${url.host}:\d+, proxy=DIRECT hostAddress=${url.host}/.+ cipherSuite=none protocol=http/1\.1\}""")) + .assertLogMatch( + Regex( + """connectionAcquired: Connection\{${url.host}:\d+, proxy=DIRECT hostAddress=${url.host}/.+ cipherSuite=none protocol=http/1\.1\}""", + ), + ) .assertLogMatch(Regex("""requestHeadersStart""")) .assertLogMatch(Regex("""requestHeadersEnd""")) .assertLogMatch(Regex("""responseHeadersStart""")) @@ -116,7 +122,11 @@ class LoggingEventListenerTest { .assertLogMatch(Regex("""dnsEnd: \[.+]""")) .assertLogMatch(Regex("""connectStart: ${url.host}/.+ DIRECT""")) .assertLogMatch(Regex("""connectEnd: http/1.1""")) - .assertLogMatch(Regex("""connectionAcquired: Connection\{${url.host}:\d+, proxy=DIRECT hostAddress=${url.host}/.+ cipherSuite=none protocol=http/1\.1\}""")) + .assertLogMatch( + Regex( + """connectionAcquired: Connection\{${url.host}:\d+, proxy=DIRECT hostAddress=${url.host}/.+ cipherSuite=none protocol=http/1\.1\}""", + ), + ) .assertLogMatch(Regex("""requestHeadersStart""")) .assertLogMatch(Regex("""requestHeadersEnd""")) .assertLogMatch(Regex("""requestBodyStart""")) @@ -148,9 +158,15 @@ class LoggingEventListenerTest { .assertLogMatch(Regex("""dnsEnd: \[.+]""")) .assertLogMatch(Regex("""connectStart: ${url.host}/.+ DIRECT""")) .assertLogMatch(Regex("""secureConnectStart""")) - .assertLogMatch(Regex("""secureConnectEnd: Handshake\{tlsVersion=TLS_1_[23] cipherSuite=TLS_.* peerCertificates=\[CN=localhost] localCertificates=\[]\}""")) + .assertLogMatch( + Regex( + """secureConnectEnd: Handshake\{tlsVersion=TLS_1_[23] cipherSuite=TLS_.* peerCertificates=\[CN=localhost] localCertificates=\[]\}""", + ), + ) .assertLogMatch(Regex("""connectEnd: h2""")) - .assertLogMatch(Regex("""connectionAcquired: Connection\{${url.host}:\d+, proxy=DIRECT hostAddress=${url.host}/.+ cipherSuite=.+ protocol=h2\}""")) + .assertLogMatch( + Regex("""connectionAcquired: Connection\{${url.host}:\d+, proxy=DIRECT hostAddress=${url.host}/.+ cipherSuite=.+ protocol=h2\}"""), + ) .assertLogMatch(Regex("""requestHeadersStart""")) .assertLogMatch(Regex("""requestHeadersEnd""")) .assertLogMatch(Regex("""responseHeadersStart""")) @@ -164,10 +180,11 @@ class LoggingEventListenerTest { @Test fun dnsFail() { - client = OkHttpClient.Builder() - .dns { _ -> throw UnknownHostException("reason") } - .eventListenerFactory(loggingEventListenerFactory) - .build() + client = + OkHttpClient.Builder() + .dns { _ -> throw UnknownHostException("reason") } + .eventListenerFactory(loggingEventListenerFactory) + .build() try { client.newCall(request().build()).execute() fail() @@ -190,7 +207,7 @@ class LoggingEventListenerTest { server.enqueue( MockResponse.Builder() .socketPolicy(FailHandshake) - .build() + .build(), ) url = server.url("/") try { @@ -206,8 +223,16 @@ class LoggingEventListenerTest { .assertLogMatch(Regex("""dnsEnd: \[.+]""")) .assertLogMatch(Regex("""connectStart: ${url.host}/.+ DIRECT""")) .assertLogMatch(Regex("""secureConnectStart""")) - .assertLogMatch(Regex("""connectFailed: null \S+(?:SSLProtocolException|SSLHandshakeException|TlsFatalAlert): (?:Unexpected handshake message: client_hello|Handshake message sequence violation, 1|Read error|Handshake failed|unexpected_message\(10\)).*""")) - .assertLogMatch(Regex("""callFailed: \S+(?:SSLProtocolException|SSLHandshakeException|TlsFatalAlert): (?:Unexpected handshake message: client_hello|Handshake message sequence violation, 1|Read error|Handshake failed|unexpected_message\(10\)).*""")) + .assertLogMatch( + Regex( + """connectFailed: null \S+(?:SSLProtocolException|SSLHandshakeException|TlsFatalAlert): (?:Unexpected handshake message: client_hello|Handshake message sequence violation, 1|Read error|Handshake failed|unexpected_message\(10\)).*""", + ), + ) + .assertLogMatch( + Regex( + """callFailed: \S+(?:SSLProtocolException|SSLHandshakeException|TlsFatalAlert): (?:Unexpected handshake message: client_hello|Handshake message sequence violation, 1|Read error|Handshake failed|unexpected_message\(10\)).*""", + ), + ) .assertNoMoreLogs() } diff --git a/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSource.kt b/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSource.kt index ec280d5b5df9..8235f17b0843 100644 --- a/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSource.kt +++ b/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSource.kt @@ -33,6 +33,9 @@ interface EventSource { * asynchronous process to connect the socket. Once that succeeds or fails, `listener` will be * notified. The caller must cancel the returned event source when it is no longer in use. */ - fun newEventSource(request: Request, listener: EventSourceListener): EventSource + fun newEventSource( + request: Request, + listener: EventSourceListener, + ): EventSource } } diff --git a/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSourceListener.kt b/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSourceListener.kt index cf24ab51c4b5..8c595b178f4f 100644 --- a/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSourceListener.kt +++ b/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSourceListener.kt @@ -22,13 +22,21 @@ abstract class EventSourceListener { * Invoked when an event source has been accepted by the remote peer and may begin transmitting * events. */ - open fun onOpen(eventSource: EventSource, response: Response) { + open fun onOpen( + eventSource: EventSource, + response: Response, + ) { } /** * TODO description. */ - open fun onEvent(eventSource: EventSource, id: String?, type: String?, data: String) { + open fun onEvent( + eventSource: EventSource, + id: String?, + type: String?, + data: String, + ) { } /** @@ -43,6 +51,10 @@ abstract class EventSourceListener { * Invoked when an event source has been closed due to an error reading from or writing to the * network. Incoming events may have been lost. No further calls to this listener will be made. */ - open fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) { + open fun onFailure( + eventSource: EventSource, + t: Throwable?, + response: Response?, + ) { } } diff --git a/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSources.kt b/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSources.kt index f3dc002f39d7..88b8f47de5ce 100644 --- a/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSources.kt +++ b/okhttp-sse/src/main/kotlin/okhttp3/sse/EventSources.kt @@ -45,7 +45,10 @@ object EventSources { } @JvmStatic - fun processResponse(response: Response, listener: EventSourceListener) { + fun processResponse( + response: Response, + listener: EventSourceListener, + ) { val eventSource = RealEventSource(response.request, listener) eventSource.processResponse(response) } diff --git a/okhttp-sse/src/main/kotlin/okhttp3/sse/internal/RealEventSource.kt b/okhttp-sse/src/main/kotlin/okhttp3/sse/internal/RealEventSource.kt index 1cd3d135d479..f638d98b860f 100644 --- a/okhttp-sse/src/main/kotlin/okhttp3/sse/internal/RealEventSource.kt +++ b/okhttp-sse/src/main/kotlin/okhttp3/sse/internal/RealEventSource.kt @@ -27,18 +27,23 @@ import okhttp3.sse.EventSourceListener internal class RealEventSource( private val request: Request, - private val listener: EventSourceListener + private val listener: EventSourceListener, ) : EventSource, ServerSentEventReader.Callback, Callback { private var call: Call? = null + @Volatile private var canceled = false fun connect(callFactory: Call.Factory) { - call = callFactory.newCall(request).apply { - enqueue(this@RealEventSource) - } + call = + callFactory.newCall(request).apply { + enqueue(this@RealEventSource) + } } - override fun onResponse(call: Call, response: Response) { + override fun onResponse( + call: Call, + response: Response, + ) { processResponse(response) } @@ -52,8 +57,11 @@ internal class RealEventSource( val body = response.body if (!body.isEventStream()) { - listener.onFailure(this, - IllegalStateException("Invalid content-type: ${body.contentType()}"), response) + listener.onFailure( + this, + IllegalStateException("Invalid content-type: ${body.contentType()}"), + response, + ) return } @@ -71,10 +79,11 @@ internal class RealEventSource( } } } catch (e: Exception) { - val exception = when { - canceled -> IOException("canceled", e) - else -> e - } + val exception = + when { + canceled -> IOException("canceled", e) + else -> e + } listener.onFailure(this, exception, response) return } @@ -91,7 +100,10 @@ internal class RealEventSource( return contentType.type == "text" && contentType.subtype == "event-stream" } - override fun onFailure(call: Call, e: IOException) { + override fun onFailure( + call: Call, + e: IOException, + ) { listener.onFailure(this, e, null) } @@ -102,7 +114,11 @@ internal class RealEventSource( call?.cancel() } - override fun onEvent(id: String?, type: String?, data: String) { + override fun onEvent( + id: String?, + type: String?, + data: String, + ) { listener.onEvent(this, id, type, data) } diff --git a/okhttp-sse/src/main/kotlin/okhttp3/sse/internal/ServerSentEventReader.kt b/okhttp-sse/src/main/kotlin/okhttp3/sse/internal/ServerSentEventReader.kt index 53d60aea0617..c4933eb23378 100644 --- a/okhttp-sse/src/main/kotlin/okhttp3/sse/internal/ServerSentEventReader.kt +++ b/okhttp-sse/src/main/kotlin/okhttp3/sse/internal/ServerSentEventReader.kt @@ -24,12 +24,17 @@ import okio.Options class ServerSentEventReader( private val source: BufferedSource, - private val callback: Callback + private val callback: Callback, ) { private var lastId: String? = null interface Callback { - fun onEvent(id: String?, type: String?, data: String) + fun onEvent( + id: String?, + type: String?, + data: String, + ) + fun onRetryChange(timeMs: Long) } @@ -101,7 +106,11 @@ class ServerSentEventReader( } @Throws(IOException::class) - private fun completeEvent(id: String?, type: String?, data: Buffer) { + private fun completeEvent( + id: String?, + type: String?, + data: Buffer, + ) { if (data.size != 0L) { lastId = id data.skip(1L) // Leading newline. @@ -110,35 +119,49 @@ class ServerSentEventReader( } companion object { - val options = Options.of( - /* 0 */ "\r\n".encodeUtf8(), - /* 1 */ "\r".encodeUtf8(), - /* 2 */ "\n".encodeUtf8(), - - /* 3 */ "data: ".encodeUtf8(), - /* 4 */ "data:".encodeUtf8(), - - /* 5 */ "data\r\n".encodeUtf8(), - /* 6 */ "data\r".encodeUtf8(), - /* 7 */ "data\n".encodeUtf8(), - - /* 8 */ "id: ".encodeUtf8(), - /* 9 */ "id:".encodeUtf8(), - - /* 10 */ "id\r\n".encodeUtf8(), - /* 11 */ "id\r".encodeUtf8(), - /* 12 */ "id\n".encodeUtf8(), - - /* 13 */ "event: ".encodeUtf8(), - /* 14 */ "event:".encodeUtf8(), - - /* 15 */ "event\r\n".encodeUtf8(), - /* 16 */ "event\r".encodeUtf8(), - /* 17 */ "event\n".encodeUtf8(), - - /* 18 */ "retry: ".encodeUtf8(), - /* 19 */ "retry:".encodeUtf8() - ) + val options = + Options.of( + // 0 + "\r\n".encodeUtf8(), + // 1 + "\r".encodeUtf8(), + // 2 + "\n".encodeUtf8(), + // 3 + "data: ".encodeUtf8(), + // 4 + "data:".encodeUtf8(), + // 5 + "data\r\n".encodeUtf8(), + // 6 + "data\r".encodeUtf8(), + // 7 + "data\n".encodeUtf8(), + // 8 + "id: ".encodeUtf8(), + // 9 + "id:".encodeUtf8(), + // 10 + "id\r\n".encodeUtf8(), + // 11 + "id\r".encodeUtf8(), + // 12 + "id\n".encodeUtf8(), + // 13 + "event: ".encodeUtf8(), + // 14 + "event:".encodeUtf8(), + // 15 + "event\r\n".encodeUtf8(), + // 16 + "event\r".encodeUtf8(), + // 17 + "event\n".encodeUtf8(), + // 18 + "retry: ".encodeUtf8(), + // 19 + "retry:".encodeUtf8(), + ) private val CRLF = "\r\n".encodeUtf8() diff --git a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceHttpTest.kt b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceHttpTest.kt index 7884f6411b07..6484ecdee1f0 100644 --- a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceHttpTest.kt +++ b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceHttpTest.kt @@ -47,9 +47,10 @@ class EventSourceHttpTest { val clientTestRule = OkHttpClientTestRule() private val eventListener = RecordingEventListener() private val listener = EventSourceRecorder() - private var client = clientTestRule.newClientBuilder() - .eventListenerFactory(clientTestRule.wrap(eventListener)) - .build() + private var client = + clientTestRule.newClientBuilder() + .eventListenerFactory(clientTestRule.wrap(eventListener)) + .build() @BeforeEach fun before(server: MockWebServer) { @@ -70,9 +71,9 @@ class EventSourceHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ).setHeader("content-type", "text/event-stream") - .build() + .build(), ) val source = newEventSource() assertThat(source.request().url.encodedPath).isEqualTo("/") @@ -90,9 +91,9 @@ class EventSourceHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ).setHeader("content-type", "text/event-stream") - .build() + .build(), ) listener.enqueueCancel() // Will cancel in onOpen(). newEventSource() @@ -109,9 +110,9 @@ class EventSourceHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ).setHeader("content-type", "text/plain") - .build() + .build(), ) newEventSource() listener.assertFailure("Invalid content-type: text/plain") @@ -126,11 +127,11 @@ class EventSourceHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ) .setHeader("content-type", "text/event-stream") .code(401) - .build() + .build(), ) newEventSource() listener.assertFailure(null) @@ -138,15 +139,16 @@ class EventSourceHttpTest { @Test fun fullCallTimeoutDoesNotApplyOnceConnected() { - client = client.newBuilder() - .callTimeout(250, TimeUnit.MILLISECONDS) - .build() + client = + client.newBuilder() + .callTimeout(250, TimeUnit.MILLISECONDS) + .build() server.enqueue( MockResponse.Builder() .bodyDelay(500, TimeUnit.MILLISECONDS) .setHeader("content-type", "text/event-stream") .body("data: hey\n\n") - .build() + .build(), ) val source = newEventSource() assertThat(source.request().url.encodedPath).isEqualTo("/") @@ -157,15 +159,16 @@ class EventSourceHttpTest { @Test fun fullCallTimeoutAppliesToSetup() { - client = client.newBuilder() - .callTimeout(250, TimeUnit.MILLISECONDS) - .build() + client = + client.newBuilder() + .callTimeout(250, TimeUnit.MILLISECONDS) + .build() server.enqueue( MockResponse.Builder() .headersDelay(500, TimeUnit.MILLISECONDS) .setHeader("content-type", "text/event-stream") .body("data: hey\n\n") - .build() + .build(), ) newEventSource() listener.assertFailure("timeout") @@ -180,10 +183,10 @@ class EventSourceHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ) .setHeader("content-type", "text/event-stream") - .build() + .build(), ) newEventSource("text/plain") listener.assertOpen() @@ -201,9 +204,9 @@ class EventSourceHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ).setHeader("content-type", "text/event-stream") - .build() + .build(), ) newEventSource() listener.assertOpen() @@ -222,9 +225,9 @@ class EventSourceHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ).setHeader("content-type", "text/event-stream") - .build() + .build(), ) val source = newEventSource() assertThat(source.request().url.encodedPath).isEqualTo("/") @@ -247,13 +250,14 @@ class EventSourceHttpTest { "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", - "CallEnd" + "CallEnd", ) } private fun newEventSource(accept: String? = null): EventSource { - val builder = Request.Builder() - .url(server.url("/")) + val builder = + Request.Builder() + .url(server.url("/")) if (accept != null) { builder.header("Accept", accept) } diff --git a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceRecorder.kt b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceRecorder.kt index e754abdb18db..1e5c8f81d832 100644 --- a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceRecorder.kt +++ b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceRecorder.kt @@ -35,7 +35,10 @@ class EventSourceRecorder : EventSourceListener() { cancel = true } - override fun onOpen(eventSource: EventSource, response: Response) { + override fun onOpen( + eventSource: EventSource, + response: Response, + ) { get().log("[ES] onOpen", Platform.INFO, null) events.add(Open(eventSource, response)) drainCancelQueue(eventSource) @@ -52,9 +55,7 @@ class EventSourceRecorder : EventSourceListener() { drainCancelQueue(eventSource) } - override fun onClosed( - eventSource: EventSource, - ) { + override fun onClosed(eventSource: EventSource) { get().log("[ES] onClosed", Platform.INFO, null) events.add(Closed) drainCancelQueue(eventSource) @@ -70,9 +71,7 @@ class EventSourceRecorder : EventSourceListener() { drainCancelQueue(eventSource) } - private fun drainCancelQueue( - eventSource: EventSource, - ) { + private fun drainCancelQueue(eventSource: EventSource) { if (cancel) { cancel = false eventSource.cancel() diff --git a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourcesHttpTest.kt b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourcesHttpTest.kt index 2628d410be70..3ceb99ea15d9 100644 --- a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourcesHttpTest.kt +++ b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourcesHttpTest.kt @@ -61,13 +61,14 @@ class EventSourcesHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ).setHeader("content-type", "text/event-stream") - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val response = client.newCall(request).execute() processResponse(response, listener) listener.assertOpen() @@ -84,14 +85,15 @@ class EventSourcesHttpTest { |data: hey | | - """.trimMargin() + """.trimMargin(), ).setHeader("content-type", "text/event-stream") - .build() + .build(), ) listener.enqueueCancel() // Will cancel in onOpen(). - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val response = client.newCall(request).execute() processResponse(response, listener) listener.assertOpen() diff --git a/okhttp-sse/src/test/java/okhttp3/sse/internal/ServerSentEventIteratorTest.kt b/okhttp-sse/src/test/java/okhttp3/sse/internal/ServerSentEventIteratorTest.kt index f348aaf72df4..14c96a774559 100644 --- a/okhttp-sse/src/test/java/okhttp3/sse/internal/ServerSentEventIteratorTest.kt +++ b/okhttp-sse/src/test/java/okhttp3/sse/internal/ServerSentEventIteratorTest.kt @@ -42,7 +42,7 @@ class ServerSentEventIteratorTest { |data: 10 | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "YHOO\n+2\n10")) } @@ -56,7 +56,7 @@ class ServerSentEventIteratorTest { |data: 10 | | - """.trimMargin().replace("\n", "\r") + """.trimMargin().replace("\n", "\r"), ) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "YHOO\n+2\n10")) } @@ -70,7 +70,7 @@ class ServerSentEventIteratorTest { |data: 10 | | - """.trimMargin().replace("\n", "\r\n") + """.trimMargin().replace("\n", "\r\n"), ) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "YHOO\n+2\n10")) } @@ -89,7 +89,7 @@ class ServerSentEventIteratorTest { |data: 113411 | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event(null, "add", "73857293")) assertThat(callbacks.remove()).isEqualTo(Event(null, "remove", "2153")) @@ -106,7 +106,7 @@ class ServerSentEventIteratorTest { |id: 1 | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event("1", null, "first event")) } @@ -124,7 +124,7 @@ class ServerSentEventIteratorTest { |data: third event | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event("1", null, "first event")) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "second event")) @@ -142,7 +142,7 @@ class ServerSentEventIteratorTest { | |data: | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "")) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "\n")) @@ -157,7 +157,7 @@ class ServerSentEventIteratorTest { |data: test | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "test")) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "test")) @@ -170,7 +170,7 @@ class ServerSentEventIteratorTest { |data: test | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event(null, null, " test")) } @@ -188,7 +188,7 @@ class ServerSentEventIteratorTest { |data: third event | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event("1", null, "first event")) assertThat(callbacks.remove()).isEqualTo(Event("1", null, "second event")) @@ -207,7 +207,7 @@ class ServerSentEventIteratorTest { |data: second event | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event("1", null, "first event")) assertThat(callbacks.remove()).isEqualTo(Event("1", null, "second event")) @@ -223,7 +223,7 @@ class ServerSentEventIteratorTest { |id: 1 | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(22L) assertThat(callbacks.remove()).isEqualTo(Event("1", null, "first event")) @@ -237,7 +237,7 @@ class ServerSentEventIteratorTest { | |retry: hey | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(22L) } @@ -253,7 +253,7 @@ class ServerSentEventIteratorTest { |retrying | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "a")) } @@ -270,7 +270,7 @@ class ServerSentEventIteratorTest { |data | | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks.remove()).isEqualTo(Event(null, null, "c\n")) } @@ -281,21 +281,26 @@ class ServerSentEventIteratorTest { """ |retry | - """.trimMargin() + """.trimMargin(), ) assertThat(callbacks).isEmpty() } private fun consumeEvents(source: String) { - val callback: ServerSentEventReader.Callback = object : ServerSentEventReader.Callback { - override fun onEvent(id: String?, type: String?, data: String) { - callbacks.add(Event(id, type, data)) - } + val callback: ServerSentEventReader.Callback = + object : ServerSentEventReader.Callback { + override fun onEvent( + id: String?, + type: String?, + data: String, + ) { + callbacks.add(Event(id, type, data)) + } - override fun onRetryChange(timeMs: Long) { - callbacks.add(timeMs) + override fun onRetryChange(timeMs: Long) { + callbacks.add(timeMs) + } } - } val buffer = Buffer().writeUtf8(source) val reader = ServerSentEventReader(buffer, callback) while (reader.processNextEvent()) { diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/CallEvent.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/CallEvent.kt index 716ae2445f1a..3bf1afe733ed 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/CallEvent.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/CallEvent.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3 import java.io.IOException @@ -37,40 +38,38 @@ sealed class CallEvent { data class ProxySelectStart( override val timestampNs: Long, override val call: Call, - val url: HttpUrl + val url: HttpUrl, ) : CallEvent() data class ProxySelectEnd( override val timestampNs: Long, override val call: Call, val url: HttpUrl, - val proxies: List? + val proxies: List?, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is ProxySelectStart && call == event.call && url == event.url + override fun closes(event: CallEvent): Boolean = event is ProxySelectStart && call == event.call && url == event.url } data class DnsStart( override val timestampNs: Long, override val call: Call, - val domainName: String + val domainName: String, ) : CallEvent() data class DnsEnd( override val timestampNs: Long, override val call: Call, val domainName: String, - val inetAddressList: List + val inetAddressList: List, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is DnsStart && call == event.call && domainName == event.domainName + override fun closes(event: CallEvent): Boolean = event is DnsStart && call == event.call && domainName == event.domainName } data class ConnectStart( override val timestampNs: Long, override val call: Call, val inetSocketAddress: InetSocketAddress, - val proxy: Proxy? + val proxy: Proxy?, ) : CallEvent() data class ConnectEnd( @@ -78,7 +77,7 @@ sealed class CallEvent { override val call: Call, val inetSocketAddress: InetSocketAddress, val proxy: Proxy?, - val protocol: Protocol? + val protocol: Protocol?, ) : CallEvent() { override fun closes(event: CallEvent): Boolean = event is ConnectStart && call == event.call && inetSocketAddress == event.inetSocketAddress && proxy == event.proxy @@ -90,7 +89,7 @@ sealed class CallEvent { val inetSocketAddress: InetSocketAddress, val proxy: Proxy, val protocol: Protocol?, - val ioe: IOException + val ioe: IOException, ) : CallEvent() { override fun closes(event: CallEvent): Boolean = event is ConnectStart && call == event.call && inetSocketAddress == event.inetSocketAddress && proxy == event.proxy @@ -98,149 +97,139 @@ sealed class CallEvent { data class SecureConnectStart( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class SecureConnectEnd( override val timestampNs: Long, override val call: Call, - val handshake: Handshake? + val handshake: Handshake?, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is SecureConnectStart && call == event.call + override fun closes(event: CallEvent): Boolean = event is SecureConnectStart && call == event.call } data class ConnectionAcquired( override val timestampNs: Long, override val call: Call, - val connection: Connection + val connection: Connection, ) : CallEvent() data class ConnectionReleased( override val timestampNs: Long, override val call: Call, - val connection: Connection + val connection: Connection, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is ConnectionAcquired && call == event.call && connection == event.connection + override fun closes(event: CallEvent): Boolean = event is ConnectionAcquired && call == event.call && connection == event.connection } data class CallStart( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class CallEnd( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is CallStart && call == event.call + override fun closes(event: CallEvent): Boolean = event is CallStart && call == event.call } data class CallFailed( override val timestampNs: Long, override val call: Call, - val ioe: IOException + val ioe: IOException, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is CallStart && call == event.call + override fun closes(event: CallEvent): Boolean = event is CallStart && call == event.call } data class Canceled( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class RequestHeadersStart( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class RequestHeadersEnd( override val timestampNs: Long, override val call: Call, - val headerLength: Long + val headerLength: Long, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is RequestHeadersStart && call == event.call + override fun closes(event: CallEvent): Boolean = event is RequestHeadersStart && call == event.call } data class RequestBodyStart( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class RequestBodyEnd( override val timestampNs: Long, override val call: Call, - val bytesWritten: Long + val bytesWritten: Long, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is RequestBodyStart && call == event.call + override fun closes(event: CallEvent): Boolean = event is RequestBodyStart && call == event.call } data class RequestFailed( override val timestampNs: Long, override val call: Call, - val ioe: IOException + val ioe: IOException, ) : CallEvent() { - - override fun closes(event: CallEvent): Boolean = - event is RequestHeadersStart && call == event.call + override fun closes(event: CallEvent): Boolean = event is RequestHeadersStart && call == event.call } data class ResponseHeadersStart( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class ResponseHeadersEnd( override val timestampNs: Long, override val call: Call, - val headerLength: Long + val headerLength: Long, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is ResponseHeadersStart && call == event.call + override fun closes(event: CallEvent): Boolean = event is ResponseHeadersStart && call == event.call } data class ResponseBodyStart( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class ResponseBodyEnd( override val timestampNs: Long, override val call: Call, - val bytesRead: Long + val bytesRead: Long, ) : CallEvent() { - override fun closes(event: CallEvent): Boolean = - event is ResponseBodyStart && call == event.call + override fun closes(event: CallEvent): Boolean = event is ResponseBodyStart && call == event.call } data class ResponseFailed( override val timestampNs: Long, override val call: Call, - val ioe: IOException + val ioe: IOException, ) : CallEvent() data class SatisfactionFailure( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class CacheHit( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class CacheMiss( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() data class CacheConditionalHit( override val timestampNs: Long, - override val call: Call + override val call: Call, ) : CallEvent() } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/ClientRuleEventListener.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/ClientRuleEventListener.kt index 104c45e45205..14b64abc06b3 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/ClientRuleEventListener.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/ClientRuleEventListener.kt @@ -23,9 +23,9 @@ import java.util.concurrent.TimeUnit class ClientRuleEventListener( val delegate: EventListener = NONE, - var logger: (String) -> Unit + var logger: (String) -> Unit, ) : EventListener(), - EventListener.Factory { + EventListener.Factory { private var startNs: Long? = null override fun create(call: Call): EventListener = this @@ -40,7 +40,7 @@ class ClientRuleEventListener( override fun proxySelectStart( call: Call, - url: HttpUrl + url: HttpUrl, ) { logWithTime("proxySelectStart: $url") @@ -50,7 +50,7 @@ class ClientRuleEventListener( override fun proxySelectEnd( call: Call, url: HttpUrl, - proxies: List + proxies: List, ) { logWithTime("proxySelectEnd: $proxies") @@ -59,7 +59,7 @@ class ClientRuleEventListener( override fun dnsStart( call: Call, - domainName: String + domainName: String, ) { logWithTime("dnsStart: $domainName") @@ -69,7 +69,7 @@ class ClientRuleEventListener( override fun dnsEnd( call: Call, domainName: String, - inetAddressList: List + inetAddressList: List, ) { logWithTime("dnsEnd: $inetAddressList") @@ -79,7 +79,7 @@ class ClientRuleEventListener( override fun connectStart( call: Call, inetSocketAddress: InetSocketAddress, - proxy: Proxy + proxy: Proxy, ) { logWithTime("connectStart: $inetSocketAddress $proxy") @@ -94,7 +94,7 @@ class ClientRuleEventListener( override fun secureConnectEnd( call: Call, - handshake: Handshake? + handshake: Handshake?, ) { logWithTime("secureConnectEnd: $handshake") @@ -105,7 +105,7 @@ class ClientRuleEventListener( call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, - protocol: Protocol? + protocol: Protocol?, ) { logWithTime("connectEnd: $protocol") @@ -117,7 +117,7 @@ class ClientRuleEventListener( inetSocketAddress: InetSocketAddress, proxy: Proxy, protocol: Protocol?, - ioe: IOException + ioe: IOException, ) { logWithTime("connectFailed: $protocol $ioe") @@ -126,7 +126,7 @@ class ClientRuleEventListener( override fun connectionAcquired( call: Call, - connection: Connection + connection: Connection, ) { logWithTime("connectionAcquired: $connection") @@ -135,7 +135,7 @@ class ClientRuleEventListener( override fun connectionReleased( call: Call, - connection: Connection + connection: Connection, ) { logWithTime("connectionReleased") @@ -150,7 +150,7 @@ class ClientRuleEventListener( override fun requestHeadersEnd( call: Call, - request: Request + request: Request, ) { logWithTime("requestHeadersEnd") @@ -165,7 +165,7 @@ class ClientRuleEventListener( override fun requestBodyEnd( call: Call, - byteCount: Long + byteCount: Long, ) { logWithTime("requestBodyEnd: byteCount=$byteCount") @@ -174,7 +174,7 @@ class ClientRuleEventListener( override fun requestFailed( call: Call, - ioe: IOException + ioe: IOException, ) { logWithTime("requestFailed: $ioe") @@ -189,7 +189,7 @@ class ClientRuleEventListener( override fun responseHeadersEnd( call: Call, - response: Response + response: Response, ) { logWithTime("responseHeadersEnd: $response") @@ -204,7 +204,7 @@ class ClientRuleEventListener( override fun responseBodyEnd( call: Call, - byteCount: Long + byteCount: Long, ) { logWithTime("responseBodyEnd: byteCount=$byteCount") @@ -213,7 +213,7 @@ class ClientRuleEventListener( override fun responseFailed( call: Call, - ioe: IOException + ioe: IOException, ) { logWithTime("responseFailed: $ioe") @@ -228,7 +228,7 @@ class ClientRuleEventListener( override fun callFailed( call: Call, - ioe: IOException + ioe: IOException, ) { logWithTime("callFailed: $ioe") @@ -241,7 +241,10 @@ class ClientRuleEventListener( delegate.canceled(call) } - override fun satisfactionFailure(call: Call, response: Response) { + override fun satisfactionFailure( + call: Call, + response: Response, + ) { logWithTime("satisfactionFailure") delegate.satisfactionFailure(call, response) @@ -253,13 +256,19 @@ class ClientRuleEventListener( delegate.cacheMiss(call) } - override fun cacheHit(call: Call, response: Response) { + override fun cacheHit( + call: Call, + response: Response, + ) { logWithTime("cacheHit") delegate.cacheHit(call, response) } - override fun cacheConditionalHit(call: Call, cachedResponse: Response) { + override fun cacheConditionalHit( + call: Call, + cachedResponse: Response, + ) { logWithTime("cacheConditionalHit") delegate.cacheConditionalHit(call, cachedResponse) @@ -267,12 +276,13 @@ class ClientRuleEventListener( private fun logWithTime(message: String) { val startNs = startNs - val timeMs = if (startNs == null) { - // Event occurred before start, for an example an early cancel. - 0L - } else { - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs) - } + val timeMs = + if (startNs == null) { + // Event occurred before start, for an example an early cancel. + 0L + } else { + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs) + } logger.invoke("[$timeMs ms] $message") } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/ConnectionEvent.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/ConnectionEvent.kt index 91bad2cb5ac7..0da52ea65898 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/ConnectionEvent.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/ConnectionEvent.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3 import java.io.IOException @@ -35,17 +36,16 @@ sealed class ConnectionEvent { data class ConnectStart( override val timestampNs: Long, val route: Route, - val call: Call + val call: Call, ) : ConnectionEvent() data class ConnectFailed( override val timestampNs: Long, val route: Route, val call: Call, - val exception: IOException + val exception: IOException, ) : ConnectionEvent() { - override fun closes(event: ConnectionEvent): Boolean = - event is ConnectStart && call == event.call && route == event.route + override fun closes(event: ConnectionEvent): Boolean = event is ConnectStart && call == event.call && route == event.route } data class ConnectEnd( @@ -54,8 +54,7 @@ sealed class ConnectionEvent { val route: Route, val call: Call, ) : ConnectionEvent() { - override fun closes(event: ConnectionEvent): Boolean = - event is ConnectStart && call == event.call && route == event.route + override fun closes(event: ConnectionEvent): Boolean = event is ConnectStart && call == event.call && route == event.route } data class ConnectionClosed( @@ -66,15 +65,14 @@ sealed class ConnectionEvent { data class ConnectionAcquired( override val timestampNs: Long, override val connection: Connection, - val call: Call + val call: Call, ) : ConnectionEvent() data class ConnectionReleased( override val timestampNs: Long, override val connection: Connection, - val call: Call + val call: Call, ) : ConnectionEvent() { - override fun closes(event: ConnectionEvent): Boolean = event is ConnectionAcquired && connection == event.connection && call == event.call } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSession.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSession.kt index 5b187583a8d6..cf4a77c59cec 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSession.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSession.kt @@ -24,7 +24,6 @@ import javax.security.cert.X509Certificate /** An [SSLSession] that delegates all calls. */ abstract class DelegatingSSLSession(protected val delegate: SSLSession?) : SSLSession { - override fun getId(): ByteArray { return delegate!!.id } @@ -49,7 +48,10 @@ abstract class DelegatingSSLSession(protected val delegate: SSLSession?) : SSLSe return delegate!!.isValid } - override fun putValue(s: String, o: Any) { + override fun putValue( + s: String, + o: Any, + ) { delegate!!.putValue(s, o) } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSocket.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSocket.kt index 6164010a2681..5d10d5df4c65 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSocket.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSocket.kt @@ -198,7 +198,10 @@ abstract class DelegatingSSLSocket(protected val delegate: SSLSocket?) : SSLSock } @Throws(SocketException::class) - override fun setSoLinger(on: Boolean, timeout: Int) { + override fun setSoLinger( + on: Boolean, + timeout: Int, + ) { delegate!!.setSoLinger(on, timeout) } @@ -247,7 +250,10 @@ abstract class DelegatingSSLSocket(protected val delegate: SSLSocket?) : SSLSock } @Throws(IOException::class) - override fun connect(remoteAddr: SocketAddress, timeout: Int) { + override fun connect( + remoteAddr: SocketAddress, + timeout: Int, + ) { delegate!!.connect(remoteAddr, timeout) } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSocketFactory.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSocketFactory.kt index 6c26a2b95149..7cc63d15f01a 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSocketFactory.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSSLSocketFactory.kt @@ -33,28 +33,40 @@ open class DelegatingSSLSocketFactory(private val delegate: SSLSocketFactory) : } @Throws(IOException::class) - override fun createSocket(host: String, port: Int): SSLSocket { + override fun createSocket( + host: String, + port: Int, + ): SSLSocket { val sslSocket = delegate.createSocket(host, port) as SSLSocket return configureSocket(sslSocket) } @Throws(IOException::class) override fun createSocket( - host: String, port: Int, localAddress: InetAddress, localPort: Int + host: String, + port: Int, + localAddress: InetAddress, + localPort: Int, ): SSLSocket { val sslSocket = delegate.createSocket(host, port, localAddress, localPort) as SSLSocket return configureSocket(sslSocket) } @Throws(IOException::class) - override fun createSocket(host: InetAddress, port: Int): SSLSocket { + override fun createSocket( + host: InetAddress, + port: Int, + ): SSLSocket { val sslSocket = delegate.createSocket(host, port) as SSLSocket return configureSocket(sslSocket) } @Throws(IOException::class) override fun createSocket( - host: InetAddress, port: Int, localAddress: InetAddress, localPort: Int + host: InetAddress, + port: Int, + localAddress: InetAddress, + localPort: Int, ): SSLSocket { val sslSocket = delegate.createSocket(host, port, localAddress, localPort) as SSLSocket return configureSocket(sslSocket) @@ -70,7 +82,10 @@ open class DelegatingSSLSocketFactory(private val delegate: SSLSocketFactory) : @Throws(IOException::class) override fun createSocket( - socket: Socket, host: String, port: Int, autoClose: Boolean + socket: Socket, + host: String, + port: Int, + autoClose: Boolean, ): SSLSocket { val sslSocket = delegate.createSocket(socket, host, port, autoClose) as SSLSocket return configureSocket(sslSocket) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingServerSocketFactory.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingServerSocketFactory.kt index 9c70d8d666c8..abc6894e8cc4 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingServerSocketFactory.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingServerSocketFactory.kt @@ -38,13 +38,20 @@ open class DelegatingServerSocketFactory(private val delegate: ServerSocketFacto } @Throws(IOException::class) - override fun createServerSocket(port: Int, backlog: Int): ServerSocket { + override fun createServerSocket( + port: Int, + backlog: Int, + ): ServerSocket { val serverSocket = delegate.createServerSocket(port, backlog) return configureServerSocket(serverSocket) } @Throws(IOException::class) - override fun createServerSocket(port: Int, backlog: Int, ifAddress: InetAddress): ServerSocket { + override fun createServerSocket( + port: Int, + backlog: Int, + ifAddress: InetAddress, + ): ServerSocket { val serverSocket = delegate.createServerSocket(port, backlog, ifAddress) return configureServerSocket(serverSocket) } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSocketFactory.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSocketFactory.kt index d81af3722d73..9b65f409da2f 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSocketFactory.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/DelegatingSocketFactory.kt @@ -32,30 +32,40 @@ open class DelegatingSocketFactory(private val delegate: SocketFactory) : Socket } @Throws(IOException::class) - override fun createSocket(host: String, port: Int): Socket { + override fun createSocket( + host: String, + port: Int, + ): Socket { val socket = delegate.createSocket(host, port) return configureSocket(socket) } @Throws(IOException::class) override fun createSocket( - host: String, port: Int, localAddress: InetAddress, - localPort: Int + host: String, + port: Int, + localAddress: InetAddress, + localPort: Int, ): Socket { val socket = delegate.createSocket(host, port, localAddress, localPort) return configureSocket(socket) } @Throws(IOException::class) - override fun createSocket(host: InetAddress, port: Int): Socket { + override fun createSocket( + host: InetAddress, + port: Int, + ): Socket { val socket = delegate.createSocket(host, port) return configureSocket(socket) } @Throws(IOException::class) override fun createSocket( - host: InetAddress, port: Int, localAddress: InetAddress, - localPort: Int + host: InetAddress, + port: Int, + localAddress: InetAddress, + localPort: Int, ): Socket { val socket = delegate.createSocket(host, port, localAddress, localPort) return configureSocket(socket) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/FakeDns.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/FakeDns.kt index 3462f6a603a5..ecc26d18eb4c 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/FakeDns.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/FakeDns.kt @@ -29,7 +29,7 @@ class FakeDns : Dns { /** Sets the results for `hostname`. */ operator fun set( hostname: String, - addresses: List + addresses: List, ): FakeDns { hostAddresses[hostname] = addresses return this @@ -41,9 +41,10 @@ class FakeDns : Dns { return this } - @Throws(UnknownHostException::class) fun lookup( + @Throws(UnknownHostException::class) + fun lookup( hostname: String, - index: Int + index: Int, ): InetAddress { return hostAddresses[hostname]!![index] } @@ -66,7 +67,7 @@ class FakeDns : Dns { return (from until nextAddress) .map { return@map InetAddress.getByAddress( - Buffer().writeInt(it.toInt()).readByteArray() + Buffer().writeInt(it.toInt()).readByteArray(), ) } } @@ -78,7 +79,7 @@ class FakeDns : Dns { return (from until nextAddress) .map { return@map InetAddress.getByAddress( - Buffer().writeLong(0L).writeLong(it).readByteArray() + Buffer().writeLong(0L).writeLong(it).readByteArray(), ) } } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/FakeProxySelector.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/FakeProxySelector.kt index 26154b822296..0e8391d2049f 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/FakeProxySelector.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/FakeProxySelector.kt @@ -37,7 +37,7 @@ class FakeProxySelector : ProxySelector() { override fun connectFailed( uri: URI, sa: SocketAddress, - ioe: IOException + ioe: IOException, ) { } } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/FakeSSLSession.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/FakeSSLSession.kt index 9d245801ceeb..8f14cbd43d8b 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/FakeSSLSession.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/FakeSSLSession.kt @@ -67,7 +67,7 @@ class FakeSSLSession(vararg val certificates: Certificate) : SSLSession { } @Throws( - SSLPeerUnverifiedException::class + SSLPeerUnverifiedException::class, ) override fun getPeerCertificateChain(): Array { throw UnsupportedOperationException() @@ -96,7 +96,7 @@ class FakeSSLSession(vararg val certificates: Certificate) : SSLSession { override fun putValue( s: String, - obj: Any + obj: Any, ) { throw UnsupportedOperationException() } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/ForwardingRequestBody.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/ForwardingRequestBody.kt index 3c96d2d8de60..e0d231a8b427 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/ForwardingRequestBody.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/ForwardingRequestBody.kt @@ -20,6 +20,7 @@ import okio.BufferedSink open class ForwardingRequestBody(delegate: RequestBody?) : RequestBody() { private val delegate: RequestBody + fun delegate(): RequestBody { return delegate } @@ -28,7 +29,8 @@ open class ForwardingRequestBody(delegate: RequestBody?) : RequestBody() { return delegate.contentType() } - @Throws(IOException::class) override fun contentLength(): Long { + @Throws(IOException::class) + override fun contentLength(): Long { return delegate.contentLength() } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/ForwardingResponseBody.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/ForwardingResponseBody.kt index 4c5f80f705f5..9d118a8354b6 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/ForwardingResponseBody.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/ForwardingResponseBody.kt @@ -19,6 +19,7 @@ import okio.BufferedSource open class ForwardingResponseBody(delegate: ResponseBody?) : ResponseBody() { private val delegate: ResponseBody + fun delegate(): ResponseBody { return delegate } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/JsseDebugLogging.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/JsseDebugLogging.kt index 69d6aafbf3fe..ee7e44bfd2cb 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/JsseDebugLogging.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/JsseDebugLogging.kt @@ -22,25 +22,30 @@ import java.util.logging.LogRecord object JsseDebugLogging { data class JsseDebugMessage(val message: String, val param: String?) { enum class Type { - Handshake, Plaintext, Encrypted, Setup, Unknown + Handshake, + Plaintext, + Encrypted, + Setup, + Unknown, } val type: Type - get() = when { - message == "adding as trusted certificates" -> Type.Setup - message == "Raw read" || message == "Raw write" -> Type.Encrypted - message == "Plaintext before ENCRYPTION" || message == "Plaintext after DECRYPTION" -> Type.Plaintext - message.startsWith("System property ") -> Type.Setup - message.startsWith("Reload ") -> Type.Setup - message == "No session to resume." -> Type.Handshake - message.startsWith("Consuming ") -> Type.Handshake - message.startsWith("Produced ") -> Type.Handshake - message.startsWith("Negotiated ") -> Type.Handshake - message.startsWith("Found resumable session") -> Type.Handshake - message.startsWith("Resuming session") -> Type.Handshake - message.startsWith("Using PSK to derive early secret") -> Type.Handshake - else -> Type.Unknown - } + get() = + when { + message == "adding as trusted certificates" -> Type.Setup + message == "Raw read" || message == "Raw write" -> Type.Encrypted + message == "Plaintext before ENCRYPTION" || message == "Plaintext after DECRYPTION" -> Type.Plaintext + message.startsWith("System property ") -> Type.Setup + message.startsWith("Reload ") -> Type.Setup + message == "No session to resume." -> Type.Handshake + message.startsWith("Consuming ") -> Type.Handshake + message.startsWith("Produced ") -> Type.Handshake + message.startsWith("Negotiated ") -> Type.Handshake + message.startsWith("Found resumable session") -> Type.Handshake + message.startsWith("Resuming session") -> Type.Handshake + message.startsWith("Using PSK to derive early secret") -> Type.Handshake + else -> Type.Unknown + } override fun toString(): String { return if (param != null) { @@ -66,17 +71,20 @@ object JsseDebugLogging { fun enableJsseDebugLogging(debugHandler: (JsseDebugMessage) -> Unit = this::quietDebug): Closeable { System.setProperty("javax.net.debug", "") - return OkHttpDebugLogging.enable("javax.net.ssl", object : Handler() { - override fun publish(record: LogRecord) { - val param = record.parameters?.firstOrNull() as? String - debugHandler(JsseDebugMessage(record.message, param)) - } + return OkHttpDebugLogging.enable( + "javax.net.ssl", + object : Handler() { + override fun publish(record: LogRecord) { + val param = record.parameters?.firstOrNull() as? String + debugHandler(JsseDebugMessage(record.message, param)) + } - override fun flush() { - } + override fun flush() { + } - override fun close() { - } - }) + override fun close() { + } + }, + ) } -} \ No newline at end of file +} diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpClientTestRule.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpClientTestRule.kt index 4eb96e53150e..275d09f6a0a7 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpClientTestRule.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpClientTestRule.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3 import android.annotation.SuppressLint @@ -62,57 +63,60 @@ class OkHttpClientTestRule : BeforeEachCallback, AfterEachCallback { var recordFrames = false var recordSslDebug = false - private val sslExcludeFilter = Regex( - buildString { - append("^(?:") - append( - listOf( - "Inaccessible trust store", - "trustStore is", - "Reload the trust store", - "Reload trust certs", - "Reloaded", - "adding as trusted certificates", - "Ignore disabled cipher suite", - "Ignore unsupported cipher suite", - ).joinToString(separator = "|") - ) - append(").*") - } - ) - - private val testLogHandler = object : Handler() { - override fun publish(record: LogRecord) { - val recorded = when (record.loggerName) { - TaskRunner::class.java.name -> recordTaskRunner - Http2::class.java.name -> recordFrames - "javax.net.ssl" -> recordSslDebug && !sslExcludeFilter.matches(record.message) - else -> false - } + private val sslExcludeFilter = + Regex( + buildString { + append("^(?:") + append( + listOf( + "Inaccessible trust store", + "trustStore is", + "Reload the trust store", + "Reload trust certs", + "Reloaded", + "adding as trusted certificates", + "Ignore disabled cipher suite", + "Ignore unsupported cipher suite", + ).joinToString(separator = "|"), + ) + append(").*") + }, + ) + + private val testLogHandler = + object : Handler() { + override fun publish(record: LogRecord) { + val recorded = + when (record.loggerName) { + TaskRunner::class.java.name -> recordTaskRunner + Http2::class.java.name -> recordFrames + "javax.net.ssl" -> recordSslDebug && !sslExcludeFilter.matches(record.message) + else -> false + } - if (recorded) { - synchronized(clientEventsList) { - clientEventsList.add(record.message) + if (recorded) { + synchronized(clientEventsList) { + clientEventsList.add(record.message) - if (record.loggerName == "javax.net.ssl") { - val parameters = record.parameters + if (record.loggerName == "javax.net.ssl") { + val parameters = record.parameters - if (parameters != null) { - clientEventsList.add(parameters.first().toString()) + if (parameters != null) { + clientEventsList.add(parameters.first().toString()) + } } } } } - } - override fun flush() { - } + override fun flush() { + } - override fun close() { + override fun close() { + } + }.apply { + level = Level.FINEST } - }.apply { - level = Level.FINEST - } private fun applyLogger(fn: Logger.() -> Unit) { Logger.getLogger(OkHttpClient::class.java.`package`.name).fn() @@ -122,8 +126,7 @@ class OkHttpClientTestRule : BeforeEachCallback, AfterEachCallback { Logger.getLogger("javax.net.ssl").fn() } - fun wrap(eventListener: EventListener) = - EventListener.Factory { ClientRuleEventListener(eventListener, ::addEvent) } + fun wrap(eventListener: EventListener) = EventListener.Factory { ClientRuleEventListener(eventListener, ::addEvent) } fun wrap(eventListenerFactory: EventListener.Factory) = EventListener.Factory { call -> ClientRuleEventListener(eventListenerFactory.create(call), ::addEvent) } @@ -140,10 +143,11 @@ class OkHttpClientTestRule : BeforeEachCallback, AfterEachCallback { fun newClient(): OkHttpClient { var client = testClient if (client == null) { - client = initialClientBuilder() - .dns(SINGLE_INET_ADDRESS_DNS) // Prevent unexpected fallback addresses. - .eventListenerFactory { ClientRuleEventListener(logger = ::addEvent) } - .build() + client = + initialClientBuilder() + .dns(SINGLE_INET_ADDRESS_DNS) // Prevent unexpected fallback addresses. + .eventListenerFactory { ClientRuleEventListener(logger = ::addEvent) } + .build() connectionListener.forbidLock(RealConnectionPool.get(client.connectionPool)) connectionListener.forbidLock(client.dispatcher) testClient = client @@ -151,23 +155,24 @@ class OkHttpClientTestRule : BeforeEachCallback, AfterEachCallback { return client } - private fun initialClientBuilder(): OkHttpClient.Builder = if (isLoom()) { - val backend = TaskRunner.RealBackend(loomThreadFactory()) - val taskRunner = TaskRunner(backend) - - OkHttpClient.Builder() - .connectionPool( - buildConnectionPool( - connectionListener = connectionListener, - taskRunner = taskRunner, + private fun initialClientBuilder(): OkHttpClient.Builder = + if (isLoom()) { + val backend = TaskRunner.RealBackend(loomThreadFactory()) + val taskRunner = TaskRunner(backend) + + OkHttpClient.Builder() + .connectionPool( + buildConnectionPool( + connectionListener = connectionListener, + taskRunner = taskRunner, + ), ) - ) - .dispatcher(Dispatcher(backend.executor)) - .taskRunnerInternal(taskRunner) - } else { - OkHttpClient.Builder() - .connectionPool(ConnectionPool(connectionListener = connectionListener)) - } + .dispatcher(Dispatcher(backend.executor)) + .taskRunnerInternal(taskRunner) + } else { + OkHttpClient.Builder() + .connectionPool(ConnectionPool(connectionListener = connectionListener)) + } private fun loomThreadFactory(): ThreadFactory { val ofVirtual = Thread::class.java.getMethod("ofVirtual").invoke(null) @@ -322,10 +327,11 @@ class OkHttpClientTestRule : BeforeEachCallback, AfterEachCallback { * A network that resolves only one IP address per host. Use this when testing route selection * fallbacks to prevent the host machine's various IP addresses from interfering. */ - private val SINGLE_INET_ADDRESS_DNS = Dns { hostname -> - val addresses = Dns.SYSTEM.lookup(hostname) - listOf(addresses[0]) - } + private val SINGLE_INET_ADDRESS_DNS = + Dns { hostname -> + val addresses = Dns.SYSTEM.lookup(hostname) + listOf(addresses[0]) + } private operator fun Throwable?.plus(throwable: Throwable): Throwable { if (this != null) { diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt index 4c64630cb5c0..80d56c38c0d0 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt @@ -15,8 +15,6 @@ */ package okhttp3 -import okhttp3.internal.concurrent.TaskRunner -import okhttp3.internal.http2.Http2 import java.io.Closeable import java.util.concurrent.CopyOnWriteArraySet import java.util.logging.ConsoleHandler @@ -26,6 +24,8 @@ import java.util.logging.LogRecord import java.util.logging.Logger import java.util.logging.SimpleFormatter import kotlin.reflect.KClass +import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.http2.Http2 object OkHttpDebugLogging { // Keep references to loggers to prevent their configuration from being GC'd. @@ -35,15 +35,19 @@ object OkHttpDebugLogging { fun enableTaskRunner() = enable(TaskRunner::class) - fun logHandler() = ConsoleHandler().apply { - level = Level.FINE - formatter = object : SimpleFormatter() { - override fun format(record: LogRecord) = - String.format("[%1\$tF %1\$tT] %2\$s %n", record.millis, record.message) + fun logHandler() = + ConsoleHandler().apply { + level = Level.FINE + formatter = + object : SimpleFormatter() { + override fun format(record: LogRecord) = String.format("[%1\$tF %1\$tT] %2\$s %n", record.millis, record.message) + } } - } - fun enable(loggerClass: String, handler: Handler = logHandler()): Closeable { + fun enable( + loggerClass: String, + handler: Handler = logHandler(), + ): Closeable { val logger = Logger.getLogger(loggerClass) if (configuredLoggers.add(logger)) { logger.addHandler(handler) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingConnectionListener.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingConnectionListener.kt index 589c51a722be..96f63d5d1a2c 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingConnectionListener.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingConnectionListener.kt @@ -33,7 +33,7 @@ open class RecordingConnectionListener( * An override to ignore the normal order that is enforced. * EventListeners added by Interceptors will not see all events. */ - private val enforceOrder: Boolean = true + private val enforceOrder: Boolean = true, ) : ConnectionListener() { val eventSequence: Deque = ConcurrentLinkedDeque() @@ -51,7 +51,7 @@ open class RecordingConnectionListener( * Removes recorded events up to (and including) an event is found whose class equals [eventClass] * and returns it. */ - fun removeUpToEvent(eventClass: Class): T { + fun removeUpToEvent(eventClass: Class): T { val fullEventSequence = eventSequence.toList() try { while (true) { @@ -75,7 +75,7 @@ open class RecordingConnectionListener( */ fun takeEvent( eventClass: Class? = null, - elapsedMs: Long = -1L + elapsedMs: Long = -1L, ): ConnectionEvent { val result = eventSequence.remove() val actualElapsedNs = result.timestampNs - (lastTimestampNs ?: result.timestampNs) @@ -88,7 +88,7 @@ open class RecordingConnectionListener( if (elapsedMs != -1L) { assertThat( TimeUnit.NANOSECONDS.toMillis(actualElapsedNs) - .toDouble() + .toDouble(), ) .isCloseTo(elapsedMs.toDouble(), 100.0) } @@ -125,7 +125,7 @@ open class RecordingConnectionListener( if (eventSequence.isEmpty()) { assertThat(e).isInstanceOf(ConnectionEvent.ConnectStart::class.java) } else { - eventSequence.forEach loop@ { + eventSequence.forEach loop@{ when (e.closes(it)) { null -> return // no open event true -> return // found open event @@ -136,21 +136,40 @@ open class RecordingConnectionListener( } } - override fun connectStart(route: Route, call: Call) = logEvent(ConnectionEvent.ConnectStart(System.nanoTime(), route, call)) - - override fun connectFailed(route: Route, call: Call, failure: IOException) = logEvent(ConnectionEvent.ConnectFailed(System.nanoTime(), route, call, failure)) - - override fun connectEnd(connection: Connection, route: Route, call: Call) { + override fun connectStart( + route: Route, + call: Call, + ) = logEvent(ConnectionEvent.ConnectStart(System.nanoTime(), route, call)) + + override fun connectFailed( + route: Route, + call: Call, + failure: IOException, + ) = logEvent( + ConnectionEvent.ConnectFailed(System.nanoTime(), route, call, failure), + ) + + override fun connectEnd( + connection: Connection, + route: Route, + call: Call, + ) { logEvent(ConnectionEvent.ConnectEnd(System.nanoTime(), connection, route, call)) } override fun connectionClosed(connection: Connection) = logEvent(ConnectionEvent.ConnectionClosed(System.nanoTime(), connection)) - override fun connectionAcquired(connection: Connection, call: Call) { + override fun connectionAcquired( + connection: Connection, + call: Call, + ) { logEvent(ConnectionEvent.ConnectionAcquired(System.nanoTime(), connection, call)) } - override fun connectionReleased(connection: Connection, call: Call) { + override fun connectionReleased( + connection: Connection, + call: Call, + ) { if (eventSequence.find { it is ConnectionEvent.ConnectStart && it.connection == connection } != null && connection is RealConnection) { if (connection.noNewExchanges) { assertThat(eventSequence).matchesPredicate { deque -> diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingCookieJar.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingCookieJar.kt index 9940e8db44be..291de1f4c584 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingCookieJar.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingCookieJar.kt @@ -38,7 +38,7 @@ class RecordingCookieJar : CookieJar { override fun saveFromResponse( url: HttpUrl, - cookies: List + cookies: List, ) { responseCookies.add(cookies) } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingEventListener.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingEventListener.kt index 14f858ac0a20..3223f4eed833 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingEventListener.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingEventListener.kt @@ -63,7 +63,7 @@ open class RecordingEventListener( * An override to ignore the normal order that is enforced. * EventListeners added by Interceptors will not see all events. */ - private val enforceOrder: Boolean = true + private val enforceOrder: Boolean = true, ) : EventListener() { val eventSequence: Deque = ConcurrentLinkedDeque() @@ -107,7 +107,7 @@ open class RecordingEventListener( */ fun takeEvent( eventClass: Class? = null, - elapsedMs: Long = -1L + elapsedMs: Long = -1L, ): CallEvent { val result = eventSequence.remove() val actualElapsedNs = result.timestampNs - (lastTimestampNs ?: result.timestampNs) @@ -119,10 +119,10 @@ open class RecordingEventListener( if (elapsedMs != -1L) { assertThat( - TimeUnit.NANOSECONDS.toMillis(actualElapsedNs) - .toDouble() + TimeUnit.NANOSECONDS.toMillis(actualElapsedNs) + .toDouble(), ) - .isCloseTo(elapsedMs.toDouble(), 100.0) + .isCloseTo(elapsedMs.toDouble(), 100.0) } return result @@ -152,7 +152,7 @@ open class RecordingEventListener( if (eventSequence.isEmpty()) { assertThat(e).matchesPredicate { it is CallStart || it is Canceled } } else { - eventSequence.forEach loop@ { + eventSequence.forEach loop@{ when (e.closes(it)) { null -> return // no open event true -> return // found open event @@ -165,46 +165,44 @@ open class RecordingEventListener( override fun proxySelectStart( call: Call, - url: HttpUrl + url: HttpUrl, ) = logEvent(ProxySelectStart(System.nanoTime(), call, url)) override fun proxySelectEnd( call: Call, url: HttpUrl, - proxies: List + proxies: List, ) = logEvent(ProxySelectEnd(System.nanoTime(), call, url, proxies)) override fun dnsStart( call: Call, - domainName: String + domainName: String, ) = logEvent(DnsStart(System.nanoTime(), call, domainName)) override fun dnsEnd( call: Call, domainName: String, - inetAddressList: List + inetAddressList: List, ) = logEvent(DnsEnd(System.nanoTime(), call, domainName, inetAddressList)) override fun connectStart( call: Call, inetSocketAddress: InetSocketAddress, - proxy: Proxy + proxy: Proxy, ) = logEvent(ConnectStart(System.nanoTime(), call, inetSocketAddress, proxy)) - override fun secureConnectStart( - call: Call - ) = logEvent(SecureConnectStart(System.nanoTime(), call)) + override fun secureConnectStart(call: Call) = logEvent(SecureConnectStart(System.nanoTime(), call)) override fun secureConnectEnd( call: Call, - handshake: Handshake? + handshake: Handshake?, ) = logEvent(SecureConnectEnd(System.nanoTime(), call, handshake)) override fun connectEnd( call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, - protocol: Protocol? + protocol: Protocol?, ) = logEvent(ConnectEnd(System.nanoTime(), call, inetSocketAddress, proxy, protocol)) override fun connectFailed( @@ -212,96 +210,82 @@ open class RecordingEventListener( inetSocketAddress: InetSocketAddress, proxy: Proxy, protocol: Protocol?, - ioe: IOException + ioe: IOException, ) = logEvent(ConnectFailed(System.nanoTime(), call, inetSocketAddress, proxy, protocol, ioe)) override fun connectionAcquired( call: Call, - connection: Connection + connection: Connection, ) = logEvent(ConnectionAcquired(System.nanoTime(), call, connection)) override fun connectionReleased( call: Call, - connection: Connection + connection: Connection, ) = logEvent(ConnectionReleased(System.nanoTime(), call, connection)) - override fun callStart( - call: Call - ) = logEvent(CallStart(System.nanoTime(), call)) + override fun callStart(call: Call) = logEvent(CallStart(System.nanoTime(), call)) - override fun requestHeadersStart( - call: Call - ) = logEvent(RequestHeadersStart(System.nanoTime(), call)) + override fun requestHeadersStart(call: Call) = logEvent(RequestHeadersStart(System.nanoTime(), call)) override fun requestHeadersEnd( call: Call, - request: Request + request: Request, ) = logEvent(RequestHeadersEnd(System.nanoTime(), call, request.headers.byteCount())) - override fun requestBodyStart( - call: Call - ) = logEvent(RequestBodyStart(System.nanoTime(), call)) + override fun requestBodyStart(call: Call) = logEvent(RequestBodyStart(System.nanoTime(), call)) override fun requestBodyEnd( call: Call, - byteCount: Long + byteCount: Long, ) = logEvent(RequestBodyEnd(System.nanoTime(), call, byteCount)) override fun requestFailed( call: Call, - ioe: IOException + ioe: IOException, ) = logEvent(RequestFailed(System.nanoTime(), call, ioe)) - override fun responseHeadersStart( - call: Call - ) = logEvent(ResponseHeadersStart(System.nanoTime(), call)) + override fun responseHeadersStart(call: Call) = logEvent(ResponseHeadersStart(System.nanoTime(), call)) override fun responseHeadersEnd( call: Call, - response: Response + response: Response, ) = logEvent(ResponseHeadersEnd(System.nanoTime(), call, response.headers.byteCount())) - override fun responseBodyStart( - call: Call - ) = logEvent(ResponseBodyStart(System.nanoTime(), call)) + override fun responseBodyStart(call: Call) = logEvent(ResponseBodyStart(System.nanoTime(), call)) override fun responseBodyEnd( call: Call, - byteCount: Long + byteCount: Long, ) = logEvent(ResponseBodyEnd(System.nanoTime(), call, byteCount)) override fun responseFailed( call: Call, - ioe: IOException + ioe: IOException, ) = logEvent(ResponseFailed(System.nanoTime(), call, ioe)) - override fun callEnd( - call: Call - ) = logEvent(CallEnd(System.nanoTime(), call)) + override fun callEnd(call: Call) = logEvent(CallEnd(System.nanoTime(), call)) override fun callFailed( call: Call, - ioe: IOException + ioe: IOException, ) = logEvent(CallFailed(System.nanoTime(), call, ioe)) - override fun canceled( - call: Call - ) = logEvent(Canceled(System.nanoTime(), call)) + override fun canceled(call: Call) = logEvent(Canceled(System.nanoTime(), call)) override fun satisfactionFailure( call: Call, - response: Response + response: Response, ) = logEvent(SatisfactionFailure(System.nanoTime(), call)) - override fun cacheMiss( - call: Call - ) = logEvent(CacheMiss(System.nanoTime(), call)) + override fun cacheMiss(call: Call) = logEvent(CacheMiss(System.nanoTime(), call)) override fun cacheHit( call: Call, - response: Response + response: Response, ) = logEvent(CacheHit(System.nanoTime(), call)) - override fun cacheConditionalHit(call: Call, cachedResponse: Response) = - logEvent(CacheConditionalHit(System.nanoTime(), call)) + override fun cacheConditionalHit( + call: Call, + cachedResponse: Response, + ) = logEvent(CacheConditionalHit(System.nanoTime(), call)) } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingHostnameVerifier.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingHostnameVerifier.kt index a28ecb3ffa44..c91035cf4654 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingHostnameVerifier.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/RecordingHostnameVerifier.kt @@ -24,7 +24,7 @@ class RecordingHostnameVerifier : HostnameVerifier { @Synchronized override fun verify( hostname: String, - session: SSLSession + session: SSLSession, ): Boolean { calls.add("verify $hostname") return true diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/SimpleProvider.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/SimpleProvider.kt index a57517041298..19f8f80e5a1b 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/SimpleProvider.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/SimpleProvider.kt @@ -15,15 +15,14 @@ */ package okhttp3 +import kotlin.jvm.Throws import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider -import kotlin.jvm.Throws -abstract class SimpleProvider: ArgumentsProvider { - override fun provideArguments(context: ExtensionContext) = - arguments().map { Arguments.of(it) }.stream() +abstract class SimpleProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext) = arguments().map { Arguments.of(it) }.stream() @Throws(Exception::class) abstract fun arguments(): List -} \ No newline at end of file +} diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/SpecificHostSocketFactory.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/SpecificHostSocketFactory.kt index c9ce20f046c9..691723efdc22 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/SpecificHostSocketFactory.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/SpecificHostSocketFactory.kt @@ -25,21 +25,24 @@ import okhttp3.internal.platform.Platform * A [SocketFactory] that redirects connections to [defaultAddress] or specific overridden address via [set]. */ class SpecificHostSocketFactory( - val defaultAddress: InetSocketAddress? + val defaultAddress: InetSocketAddress?, ) : DelegatingSocketFactory(getDefault()) { private val hostMapping = mutableMapOf() /** Sets the [real] address for [requested]. */ operator fun set( requested: InetAddress, - real: InetSocketAddress + real: InetSocketAddress, ) { hostMapping[requested] = real } override fun createSocket(): Socket { return object : Socket() { - override fun connect(endpoint: SocketAddress?, timeout: Int) { + override fun connect( + endpoint: SocketAddress?, + timeout: Int, + ) { val requested = (endpoint as InetSocketAddress) val inetSocketAddress = hostMapping[requested.address] ?: defaultAddress ?: requested Platform.get().log("Socket connection to: $inetSocketAddress was: $requested") diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/TestUtilJvm.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/TestUtilJvm.kt index 34e0322d24a1..9bb5bcc6a419 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/TestUtilJvm.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/TestUtilJvm.kt @@ -42,7 +42,7 @@ object TestUtil { @JvmStatic fun repeat( c: Char, - count: Int + count: Int, ): String { val array = CharArray(count) Arrays.fill(array, c) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt index e10627e59a8f..46c2f4a9a4be 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt @@ -53,14 +53,16 @@ class TestValueFactory : Closeable { var proxy: Proxy = Proxy.NO_PROXY var proxySelector: ProxySelector = RecordingProxySelector() var proxyAuthenticator: Authenticator = RecordingOkAuthenticator("password", null) - var connectionSpecs: List = listOf( - ConnectionSpec.MODERN_TLS, - ConnectionSpec.COMPATIBLE_TLS, - ConnectionSpec.CLEARTEXT, - ) - var protocols: List = listOf( - Protocol.HTTP_1_1, - ) + var connectionSpecs: List = + listOf( + ConnectionSpec.MODERN_TLS, + ConnectionSpec.COMPATIBLE_TLS, + ConnectionSpec.CLEARTEXT, + ) + var protocols: List = + listOf( + Protocol.HTTP_1_1, + ) var handshakeCertificates: HandshakeCertificates = localhost() var sslSocketFactory: SSLSocketFactory? = handshakeCertificates.sslSocketFactory() var hostnameVerifier: HostnameVerifier? = HttpsURLConnection.getDefaultHostnameVerifier() @@ -73,13 +75,14 @@ class TestValueFactory : Closeable { idleAtNanos: Long = Long.MAX_VALUE, taskRunner: TaskRunner = this.taskRunner, ): RealConnection { - val result = RealConnection.newTestConnection( - taskRunner = taskRunner, - connectionPool = pool, - route = route, - socket = Socket(), - idleAtNs = idleAtNanos - ) + val result = + RealConnection.newTestConnection( + taskRunner = taskRunner, + connectionPool = pool, + route = route, + socket = Socket(), + idleAtNs = idleAtNanos, + ) synchronized(result) { pool.put(result) } return result } @@ -93,7 +96,7 @@ class TestValueFactory : Closeable { maxIdleConnections = maxIdleConnections, keepAliveDuration = 100L, timeUnit = TimeUnit.NANOSECONDS, - connectionListener = ConnectionListener.NONE + connectionListener = ConnectionListener.NONE, ) } @@ -120,7 +123,6 @@ class TestValueFactory : Closeable { ) } - fun newHttpsAddress( uriHost: String = this.uriHost, uriPort: Int = this.uriPort, @@ -148,18 +150,16 @@ class TestValueFactory : Closeable { fun newRoute( address: Address = newAddress(), proxy: Proxy = this.proxy, - socketAddress: InetSocketAddress = InetSocketAddress.createUnresolved(uriHost, uriPort) + socketAddress: InetSocketAddress = InetSocketAddress.createUnresolved(uriHost, uriPort), ): Route { return Route( address = address, proxy = proxy, - socketAddress = socketAddress + socketAddress = socketAddress, ) } - fun newChain( - call: RealCall, - ): RealInterceptorChain { + fun newChain(call: RealCall): RealInterceptorChain { return RealInterceptorChain( call = call, interceptors = listOf(), @@ -168,7 +168,7 @@ class TestValueFactory : Closeable { request = call.request(), connectTimeoutMillis = 10_000, readTimeoutMillis = 10_000, - writeTimeoutMillis = 10_000 + writeTimeoutMillis = 10_000, ) } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/UppercaseRequestInterceptor.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/UppercaseRequestInterceptor.kt index 868bade49542..34607b5d1444 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/UppercaseRequestInterceptor.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/UppercaseRequestInterceptor.kt @@ -32,15 +32,16 @@ class UppercaseRequestInterceptor : Interceptor { /** Returns a request that transforms `request` to be all uppercase. */ private fun uppercaseRequest(request: Request): Request { - val uppercaseBody: RequestBody = object : ForwardingRequestBody(request.body) { - @Throws(IOException::class) - override fun writeTo(sink: BufferedSink) { - delegate().writeTo(uppercaseSink(sink).buffer()) + val uppercaseBody: RequestBody = + object : ForwardingRequestBody(request.body) { + @Throws(IOException::class) + override fun writeTo(sink: BufferedSink) { + delegate().writeTo(uppercaseSink(sink).buffer()) + } } - } return request.newBuilder() - .method(request.method, uppercaseBody) - .build() + .method(request.method, uppercaseBody) + .build() } private fun uppercaseSink(sink: Sink): Sink { @@ -48,12 +49,13 @@ class UppercaseRequestInterceptor : Interceptor { @Throws(IOException::class) override fun write( source: Buffer, - byteCount: Long + byteCount: Long, ) { val bytes = source.readByteString(byteCount) delegate.write( - Buffer() - .write(bytes.toAsciiUppercase()), byteCount + Buffer() + .write(bytes.toAsciiUppercase()), + byteCount, ) } } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/UppercaseResponseInterceptor.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/UppercaseResponseInterceptor.kt index 8df383f76a24..16f0e72b626b 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/UppercaseResponseInterceptor.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/UppercaseResponseInterceptor.kt @@ -37,8 +37,8 @@ class UppercaseResponseInterceptor : Interceptor { } } return response.newBuilder() - .body(uppercaseBody) - .build() + .body(uppercaseBody) + .build() } private fun uppercaseSource(source: BufferedSource): ForwardingSource { @@ -46,7 +46,7 @@ class UppercaseResponseInterceptor : Interceptor { @Throws(IOException::class) override fun read( sink: Buffer, - byteCount: Long + byteCount: Long, ): Long { val buffer = Buffer() val read = delegate.read(buffer, byteCount) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/RecordingOkAuthenticator.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/RecordingOkAuthenticator.kt index a26c0b31613f..bed721b8cd10 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/RecordingOkAuthenticator.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/RecordingOkAuthenticator.kt @@ -23,7 +23,7 @@ import okhttp3.Route class RecordingOkAuthenticator( val credential: String?, - val scheme: String? + val scheme: String?, ) : Authenticator { val responses = mutableListOf() val routes = mutableListOf() @@ -35,16 +35,17 @@ class RecordingOkAuthenticator( @Throws(IOException::class) override fun authenticate( route: Route?, - response: Response + response: Response, ): Request? { if (route == null) throw NullPointerException("route == null") responses += response routes += route if (!schemeMatches(response) || credential == null) return null - val header = when (response.code) { - 407 -> "Proxy-Authorization" - else -> "Authorization" - } + val header = + when (response.code) { + 407 -> "Proxy-Authorization" + else -> "Authorization" + } return response.request.newBuilder() .addHeader(header, credential) .build() diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt index 356888484dab..ae953c32d407 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt @@ -98,64 +98,74 @@ class TaskFaker : Closeable { private var isRunningAllTasks = false /** A task runner that posts tasks to this fake. Tasks won't be executed until requested. */ - val taskRunner: TaskRunner = TaskRunner(object : TaskRunner.Backend { - override fun execute(taskRunner: TaskRunner, runnable: Runnable) { - taskRunner.assertThreadHoldsLock() - val acquiredTaskRunnerLock = AtomicBoolean() - - tasksExecutor.execute { - taskRunner.lock.withLock { - acquiredTaskRunnerLock.set(true) - taskRunner.condition.signalAll() - - tasksRunningCount++ - if (tasksRunningCount > 1) isParallel = true - try { - if (!isRunningAllTasks) { - stall() + val taskRunner: TaskRunner = + TaskRunner( + object : TaskRunner.Backend { + override fun execute( + taskRunner: TaskRunner, + runnable: Runnable, + ) { + taskRunner.assertThreadHoldsLock() + val acquiredTaskRunnerLock = AtomicBoolean() + + tasksExecutor.execute { + taskRunner.lock.withLock { + acquiredTaskRunnerLock.set(true) + taskRunner.condition.signalAll() + + tasksRunningCount++ + if (tasksRunningCount > 1) isParallel = true + try { + if (!isRunningAllTasks) { + stall() + } + runnable.run() + } catch (e: InterruptedException) { + if (!tasksExecutor.isShutdown) throw e // Ignore shutdown-triggered interruptions. + } finally { + tasksRunningCount-- + taskBecameStalled.release() + } } - runnable.run() - } catch (e: InterruptedException) { - if (!tasksExecutor.isShutdown) throw e // Ignore shutdown-triggered interruptions. - } finally { - tasksRunningCount-- - taskBecameStalled.release() } - } - } - // Execute() must not return until the launched task stalls. - while (!acquiredTaskRunnerLock.get()) { - taskRunner.condition.await() - } - } + // Execute() must not return until the launched task stalls. + while (!acquiredTaskRunnerLock.get()) { + taskRunner.condition.await() + } + } - override fun nanoTime() = nanoTime + override fun nanoTime() = nanoTime - override fun coordinatorNotify(taskRunner: TaskRunner) { - taskRunner.assertThreadHoldsLock() - check(waitingCoordinatorThread != null) + override fun coordinatorNotify(taskRunner: TaskRunner) { + taskRunner.assertThreadHoldsLock() + check(waitingCoordinatorThread != null) - stalledTasks.remove(waitingCoordinatorThread) - taskRunner.condition.signalAll() - } + stalledTasks.remove(waitingCoordinatorThread) + taskRunner.condition.signalAll() + } - override fun coordinatorWait(taskRunner: TaskRunner, nanos: Long) { - taskRunner.assertThreadHoldsLock() + override fun coordinatorWait( + taskRunner: TaskRunner, + nanos: Long, + ) { + taskRunner.assertThreadHoldsLock() - check(waitingCoordinatorThread == null) - if (nanos == 0L) return + check(waitingCoordinatorThread == null) + if (nanos == 0L) return - waitingCoordinatorThread = Thread.currentThread() - try { - stall() - } finally { - waitingCoordinatorThread = null - } - } + waitingCoordinatorThread = Thread.currentThread() + try { + stall() + } finally { + waitingCoordinatorThread = null + } + } - override fun decorate(queue: BlockingQueue) = TaskFakerBlockingQueue(queue) - }, logger = logger) + override fun decorate(queue: BlockingQueue) = TaskFakerBlockingQueue(queue) + }, + logger = logger, + ) /** Wait for the test thread to proceed. */ private fun stall() { @@ -275,13 +285,16 @@ class TaskFaker : Closeable { * like [poll]. It is only usable within task faker tasks. */ private inner class TaskFakerBlockingQueue( - val delegate: BlockingQueue + val delegate: BlockingQueue, ) : AbstractQueue(), BlockingQueue { override val size: Int = delegate.size override fun poll(): T = delegate.poll() - override fun poll(timeout: Long, unit: TimeUnit): T? { + override fun poll( + timeout: Long, + unit: TimeUnit, + ): T? { taskRunner.assertThreadHoldsLock() val waitUntil = nanoTime + unit.toNanos(timeout) @@ -306,7 +319,11 @@ class TaskFaker : Closeable { override fun peek(): T = error("unsupported") - override fun offer(element: T, timeout: Long, unit: TimeUnit) = error("unsupported") + override fun offer( + element: T, + timeout: Long, + unit: TimeUnit, + ) = error("unsupported") override fun take() = error("unsupported") @@ -314,7 +331,10 @@ class TaskFaker : Closeable { override fun drainTo(sink: MutableCollection) = error("unsupported") - override fun drainTo(sink: MutableCollection, maxElements: Int) = error("unsupported") + override fun drainTo( + sink: MutableCollection, + maxElements: Int, + ) = error("unsupported") } /** Returns true if no tasks have been scheduled. This runs the coordinator for confirmation. */ diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http/RecordingProxySelector.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http/RecordingProxySelector.kt index af367abace92..b81d99857a18 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http/RecordingProxySelector.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http/RecordingProxySelector.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3.internal.http import assertk.assertThat @@ -42,7 +43,11 @@ class RecordingProxySelector : ProxySelector() { requestedUris.clear() } - override fun connectFailed(uri: URI, sa: SocketAddress, ioe: IOException) { + override fun connectFailed( + uri: URI, + sa: SocketAddress, + ioe: IOException, + ) { val socketAddress = sa as InetSocketAddress failures.add(format("%s %s:%d %s", uri, socketAddress, socketAddress.port, ioe.message!!)) } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http2/Http2FlowControlConnectionListener.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http2/Http2FlowControlConnectionListener.kt index fe756c3730a6..e31fc9b18bf6 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http2/Http2FlowControlConnectionListener.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http2/Http2FlowControlConnectionListener.kt @@ -21,10 +21,14 @@ import okhttp3.internal.http2.flowcontrol.WindowCounter /** * ConnectionListener that outputs CSV for flow control of client receiving streams. */ -class Http2FlowControlConnectionListener: ConnectionListener(), FlowControlListener { +class Http2FlowControlConnectionListener : ConnectionListener(), FlowControlListener { val start = System.currentTimeMillis() - override fun receivingStreamWindowChanged(streamId: Int, windowCounter: WindowCounter, bufferSize: Long) { + override fun receivingStreamWindowChanged( + streamId: Int, + windowCounter: WindowCounter, + bufferSize: Long, + ) { println("${System.currentTimeMillis() - start},$streamId,${windowCounter.unacknowledged},$bufferSize") } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/okio/LoggingFilesystem.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/okio/LoggingFilesystem.kt index fa095debb24d..684c4c99cb18 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/okio/LoggingFilesystem.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/okio/LoggingFilesystem.kt @@ -26,31 +26,46 @@ class LoggingFilesystem(fileSystem: FileSystem) : ForwardingFileSystem(fileSyste println(line) } - override fun appendingSink(file: Path, mustExist: Boolean): Sink { + override fun appendingSink( + file: Path, + mustExist: Boolean, + ): Sink { log("appendingSink($file)") return super.appendingSink(file, mustExist) } - override fun atomicMove(source: Path, target: Path) { + override fun atomicMove( + source: Path, + target: Path, + ) { log("atomicMove($source, $target)") super.atomicMove(source, target) } - override fun createDirectory(dir: Path, mustCreate: Boolean) { + override fun createDirectory( + dir: Path, + mustCreate: Boolean, + ) { log("createDirectory($dir)") super.createDirectory(dir, mustCreate) } - override fun delete(path: Path, mustExist: Boolean) { + override fun delete( + path: Path, + mustExist: Boolean, + ) { log("delete($path)") super.delete(path, mustExist) } - override fun sink(path: Path, mustCreate: Boolean): Sink { + override fun sink( + path: Path, + mustCreate: Boolean, + ): Sink { log("sink($path)") return super.sink(path, mustCreate) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/testing/PlatformRule.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/testing/PlatformRule.kt index 8b8df5f5e8fb..bbcda679fcfb 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/testing/PlatformRule.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/testing/PlatformRule.kt @@ -19,7 +19,6 @@ import android.os.Build import com.amazon.corretto.crypto.provider.AmazonCorrettoCryptoProvider import com.amazon.corretto.crypto.provider.SelfTestStatus import java.lang.reflect.Method -import java.net.InetAddress import java.security.Security import okhttp3.TestUtil import okhttp3.internal.platform.ConscryptPlatform @@ -57,436 +56,444 @@ import org.opentest4j.TestAbortedException * Also allows a test file to state general platform assumptions, or for individual test. */ @Suppress("unused", "MemberVisibilityCanBePrivate") -open class PlatformRule @JvmOverloads constructor( - val requiredPlatformName: String? = null, - val platform: Platform? = null -) : BeforeEachCallback, AfterEachCallback, InvocationInterceptor { - private val versionChecks = mutableListOf, Matcher>>() - - override fun beforeEach(context: ExtensionContext) { - setupPlatform() - } - - override fun afterEach(context: ExtensionContext) { - resetPlatform() - } +open class PlatformRule + @JvmOverloads + constructor( + val requiredPlatformName: String? = null, + val platform: Platform? = null, + ) : BeforeEachCallback, AfterEachCallback, InvocationInterceptor { + private val versionChecks = mutableListOf, Matcher>>() + + override fun beforeEach(context: ExtensionContext) { + setupPlatform() + } - override fun interceptTestMethod( - invocation: InvocationInterceptor.Invocation, - invocationContext: ReflectiveInvocationContext, - extensionContext: ExtensionContext - ) { - var failed = false - try { - invocation.proceed() - } catch (e: TestAbortedException) { - throw e - } catch (e: Throwable) { - failed = true - rethrowIfNotExpected(e) - } finally { + override fun afterEach(context: ExtensionContext) { resetPlatform() } - if (!failed) { - failIfExpected() - } - } - fun setupPlatform() { - if (requiredPlatformName != null) { - assumeTrue(getPlatformSystemProperty() == requiredPlatformName) + override fun interceptTestMethod( + invocation: InvocationInterceptor.Invocation, + invocationContext: ReflectiveInvocationContext, + extensionContext: ExtensionContext, + ) { + var failed = false + try { + invocation.proceed() + } catch (e: TestAbortedException) { + throw e + } catch (e: Throwable) { + failed = true + rethrowIfNotExpected(e) + } finally { + resetPlatform() + } + if (!failed) { + failIfExpected() + } } - if (platform != null) { - Platform.resetForTests(platform) - } else { - Platform.resetForTests() - } + fun setupPlatform() { + if (requiredPlatformName != null) { + assumeTrue(getPlatformSystemProperty() == requiredPlatformName) + } - if (requiredPlatformName != null) { - System.err.println("Running with ${Platform.get().javaClass.simpleName}") - } - } + if (platform != null) { + Platform.resetForTests(platform) + } else { + Platform.resetForTests() + } - fun resetPlatform() { - if (platform != null) { - Platform.resetForTests() + if (requiredPlatformName != null) { + System.err.println("Running with ${Platform.get().javaClass.simpleName}") + } } - } - - fun expectFailureOnConscryptPlatform() { - expectFailure(platformMatches(CONSCRYPT_PROPERTY)) - } - fun expectFailureOnCorrettoPlatform() { - expectFailure(platformMatches(CORRETTO_PROPERTY)) - } + fun resetPlatform() { + if (platform != null) { + Platform.resetForTests() + } + } - fun expectFailureOnOpenJSSEPlatform() { - expectFailure(platformMatches(OPENJSSE_PROPERTY)) - } + fun expectFailureOnConscryptPlatform() { + expectFailure(platformMatches(CONSCRYPT_PROPERTY)) + } - fun expectFailureFromJdkVersion(majorVersion: Int) { - if (!TestUtil.isGraalVmImage) { - expectFailure(fromMajor(majorVersion)) + fun expectFailureOnCorrettoPlatform() { + expectFailure(platformMatches(CORRETTO_PROPERTY)) } - } - fun expectFailureOnJdkVersion(majorVersion: Int) { - if (!TestUtil.isGraalVmImage) { - expectFailure(onMajor(majorVersion)) + fun expectFailureOnOpenJSSEPlatform() { + expectFailure(platformMatches(OPENJSSE_PROPERTY)) } - } - fun expectFailureOnLoomPlatform() { - expectFailure(platformMatches(LOOM_PROPERTY)) - } + fun expectFailureFromJdkVersion(majorVersion: Int) { + if (!TestUtil.isGraalVmImage) { + expectFailure(fromMajor(majorVersion)) + } + } - private fun expectFailure( - versionMatcher: Matcher, - failureMatcher: Matcher = anything() - ) { - versionChecks.add(Pair(versionMatcher, failureMatcher)) - } + fun expectFailureOnJdkVersion(majorVersion: Int) { + if (!TestUtil.isGraalVmImage) { + expectFailure(onMajor(majorVersion)) + } + } - fun platformMatches(platform: String): Matcher = object : BaseMatcher() { - override fun describeTo(description: Description) { - description.appendText(platform) + fun expectFailureOnLoomPlatform() { + expectFailure(platformMatches(LOOM_PROPERTY)) } - override fun matches(item: Any?): Boolean { - return getPlatformSystemProperty() == platform + private fun expectFailure( + versionMatcher: Matcher, + failureMatcher: Matcher = anything(), + ) { + versionChecks.add(Pair(versionMatcher, failureMatcher)) } - } - fun fromMajor(version: Int): Matcher { - return object : TypeSafeMatcher() { - override fun describeTo(description: Description) { - description.appendText("JDK with version from $version") + fun platformMatches(platform: String): Matcher = + object : BaseMatcher() { + override fun describeTo(description: Description) { + description.appendText(platform) + } + + override fun matches(item: Any?): Boolean { + return getPlatformSystemProperty() == platform + } } - override fun matchesSafely(item: PlatformVersion): Boolean { - return item.majorVersion >= version + fun fromMajor(version: Int): Matcher { + return object : TypeSafeMatcher() { + override fun describeTo(description: Description) { + description.appendText("JDK with version from $version") + } + + override fun matchesSafely(item: PlatformVersion): Boolean { + return item.majorVersion >= version + } } } - } - fun onMajor(version: Int): Matcher { - return object : TypeSafeMatcher() { - override fun describeTo(description: Description) { - description.appendText("JDK with version $version") - } + fun onMajor(version: Int): Matcher { + return object : TypeSafeMatcher() { + override fun describeTo(description: Description) { + description.appendText("JDK with version $version") + } - override fun matchesSafely(item: PlatformVersion): Boolean { - return item.majorVersion == version + override fun matchesSafely(item: PlatformVersion): Boolean { + return item.majorVersion == version + } } } - } - fun rethrowIfNotExpected(e: Throwable) { - versionChecks.forEach { (versionMatcher, failureMatcher) -> - if (versionMatcher.matches(PlatformVersion) && failureMatcher.matches(e)) { - return + fun rethrowIfNotExpected(e: Throwable) { + versionChecks.forEach { (versionMatcher, failureMatcher) -> + if (versionMatcher.matches(PlatformVersion) && failureMatcher.matches(e)) { + return + } } - } - throw e - } + throw e + } - fun failIfExpected() { - versionChecks.forEach { (versionMatcher, failureMatcher) -> - if (versionMatcher.matches(PlatformVersion)) { - val description = StringDescription() - versionMatcher.describeTo(description) - description.appendText(" expected to fail with exception that ") - failureMatcher.describeTo(description) + fun failIfExpected() { + versionChecks.forEach { (versionMatcher, failureMatcher) -> + if (versionMatcher.matches(PlatformVersion)) { + val description = StringDescription() + versionMatcher.describeTo(description) + description.appendText(" expected to fail with exception that ") + failureMatcher.describeTo(description) - fail(description.toString()) + fail(description.toString()) + } } } - } - fun isConscrypt() = getPlatformSystemProperty() == CONSCRYPT_PROPERTY + fun isConscrypt() = getPlatformSystemProperty() == CONSCRYPT_PROPERTY - fun isJdk9() = getPlatformSystemProperty() == JDK9_PROPERTY + fun isJdk9() = getPlatformSystemProperty() == JDK9_PROPERTY - fun isJdk8() = getPlatformSystemProperty() == JDK8_PROPERTY + fun isJdk8() = getPlatformSystemProperty() == JDK8_PROPERTY - fun isJdk8Alpn() = getPlatformSystemProperty() == JDK8_ALPN_PROPERTY + fun isJdk8Alpn() = getPlatformSystemProperty() == JDK8_ALPN_PROPERTY - fun isBouncyCastle() = getPlatformSystemProperty() == BOUNCYCASTLE_PROPERTY + fun isBouncyCastle() = getPlatformSystemProperty() == BOUNCYCASTLE_PROPERTY - fun isOpenJsse() = getPlatformSystemProperty() == OPENJSSE_PROPERTY + fun isOpenJsse() = getPlatformSystemProperty() == OPENJSSE_PROPERTY - fun isLoom() = getPlatformSystemProperty() == LOOM_PROPERTY + fun isLoom() = getPlatformSystemProperty() == LOOM_PROPERTY - fun isGraalVMImage() = TestUtil.isGraalVmImage + fun isGraalVMImage() = TestUtil.isGraalVmImage - fun hasHttp2Support() = !isJdk8() + fun hasHttp2Support() = !isJdk8() - fun assumeConscrypt() { - assumeTrue(getPlatformSystemProperty() == CONSCRYPT_PROPERTY) - } + fun assumeConscrypt() { + assumeTrue(getPlatformSystemProperty() == CONSCRYPT_PROPERTY) + } - fun assumeJdk9() { - assumeTrue(getPlatformSystemProperty() == JDK9_PROPERTY) - } + fun assumeJdk9() { + assumeTrue(getPlatformSystemProperty() == JDK9_PROPERTY) + } - fun assumeOpenJSSE() { - assumeTrue(getPlatformSystemProperty() == OPENJSSE_PROPERTY) - } + fun assumeOpenJSSE() { + assumeTrue(getPlatformSystemProperty() == OPENJSSE_PROPERTY) + } - fun assumeJdk8() { - assumeTrue(getPlatformSystemProperty() == JDK8_PROPERTY) - } + fun assumeJdk8() { + assumeTrue(getPlatformSystemProperty() == JDK8_PROPERTY) + } - fun assumeJdk8Alpn() { - assumeTrue(getPlatformSystemProperty() == JDK8_ALPN_PROPERTY) - } + fun assumeJdk8Alpn() { + assumeTrue(getPlatformSystemProperty() == JDK8_ALPN_PROPERTY) + } - fun assumeCorretto() { - assumeTrue(getPlatformSystemProperty() == CORRETTO_PROPERTY) - } + fun assumeCorretto() { + assumeTrue(getPlatformSystemProperty() == CORRETTO_PROPERTY) + } - fun assumeBouncyCastle() { - assumeTrue(getPlatformSystemProperty() == BOUNCYCASTLE_PROPERTY) - } + fun assumeBouncyCastle() { + assumeTrue(getPlatformSystemProperty() == BOUNCYCASTLE_PROPERTY) + } - fun assumeOpenJsse() { - assumeTrue(getPlatformSystemProperty() == OPENJSSE_PROPERTY) - } + fun assumeOpenJsse() { + assumeTrue(getPlatformSystemProperty() == OPENJSSE_PROPERTY) + } - fun assumeLoom() { - assumeTrue(getPlatformSystemProperty() == LOOM_PROPERTY) - } + fun assumeLoom() { + assumeTrue(getPlatformSystemProperty() == LOOM_PROPERTY) + } - fun assumeHttp2Support() { - assumeTrue(getPlatformSystemProperty() != JDK8_PROPERTY) - } + fun assumeHttp2Support() { + assumeTrue(getPlatformSystemProperty() != JDK8_PROPERTY) + } - fun assumeAndroid() { - assumeTrue(Platform.isAndroid) - } + fun assumeAndroid() { + assumeTrue(Platform.isAndroid) + } - fun assumeGraalVMImage() { - assumeTrue(isGraalVMImage()) - } + fun assumeGraalVMImage() { + assumeTrue(isGraalVMImage()) + } - fun assumeNotConscrypt() { - assumeTrue(getPlatformSystemProperty() != CONSCRYPT_PROPERTY) - } + fun assumeNotConscrypt() { + assumeTrue(getPlatformSystemProperty() != CONSCRYPT_PROPERTY) + } - fun assumeNotJdk9() { - assumeTrue(getPlatformSystemProperty() != JDK9_PROPERTY) - } + fun assumeNotJdk9() { + assumeTrue(getPlatformSystemProperty() != JDK9_PROPERTY) + } - fun assumeNotJdk8() { - assumeTrue(getPlatformSystemProperty() != JDK8_PROPERTY) - } + fun assumeNotJdk8() { + assumeTrue(getPlatformSystemProperty() != JDK8_PROPERTY) + } - fun assumeNotJdk8Alpn() { - assumeTrue(getPlatformSystemProperty() != JDK8_ALPN_PROPERTY) - } + fun assumeNotJdk8Alpn() { + assumeTrue(getPlatformSystemProperty() != JDK8_ALPN_PROPERTY) + } - fun assumeNotOpenJSSE() { - assumeTrue(getPlatformSystemProperty() != OPENJSSE_PROPERTY) - } + fun assumeNotOpenJSSE() { + assumeTrue(getPlatformSystemProperty() != OPENJSSE_PROPERTY) + } - fun assumeNotLoom() { - assumeTrue(getPlatformSystemProperty() != LOOM_PROPERTY) - } + fun assumeNotLoom() { + assumeTrue(getPlatformSystemProperty() != LOOM_PROPERTY) + } - fun assumeNotCorretto() { - assumeTrue(getPlatformSystemProperty() != CORRETTO_PROPERTY) - } + fun assumeNotCorretto() { + assumeTrue(getPlatformSystemProperty() != CORRETTO_PROPERTY) + } - fun assumeNotBouncyCastle() { - // Most failures are with MockWebServer - // org.bouncycastle.tls.TlsFatalAlertReceived: handshake_failure(40) - // at org.bouncycastle.tls.TlsProtocol.handleAlertMessage(TlsProtocol.java:241) - assumeTrue(getPlatformSystemProperty() != BOUNCYCASTLE_PROPERTY) - } + fun assumeNotBouncyCastle() { + // Most failures are with MockWebServer + // org.bouncycastle.tls.TlsFatalAlertReceived: handshake_failure(40) + // at org.bouncycastle.tls.TlsProtocol.handleAlertMessage(TlsProtocol.java:241) + assumeTrue(getPlatformSystemProperty() != BOUNCYCASTLE_PROPERTY) + } - fun assumeNotOpenJsse() { - assumeTrue(getPlatformSystemProperty() != OPENJSSE_PROPERTY) - } + fun assumeNotOpenJsse() { + assumeTrue(getPlatformSystemProperty() != OPENJSSE_PROPERTY) + } - fun assumeNotHttp2Support() { - assumeTrue(getPlatformSystemProperty() == JDK8_PROPERTY) - } + fun assumeNotHttp2Support() { + assumeTrue(getPlatformSystemProperty() == JDK8_PROPERTY) + } - fun assumeJettyBootEnabled() { - assumeTrue(isAlpnBootEnabled()) - } + fun assumeJettyBootEnabled() { + assumeTrue(isAlpnBootEnabled()) + } - fun assumeNotAndroid() { - assumeFalse(Platform.isAndroid) - } + fun assumeNotAndroid() { + assumeFalse(Platform.isAndroid) + } - fun assumeNotGraalVMImage() { - assumeFalse(isGraalVMImage()) - } + fun assumeNotGraalVMImage() { + assumeFalse(isGraalVMImage()) + } - fun assumeJdkVersion(majorVersion: Int) { - assumeNotAndroid() - assumeNotGraalVMImage() - assumeTrue(PlatformVersion.majorVersion == majorVersion) - } + fun assumeJdkVersion(majorVersion: Int) { + assumeNotAndroid() + assumeNotGraalVMImage() + assumeTrue(PlatformVersion.majorVersion == majorVersion) + } - fun androidSdkVersion(): Int? { - return if (Platform.isAndroid) { - Build.VERSION.SDK_INT - } else { - null + fun androidSdkVersion(): Int? { + return if (Platform.isAndroid) { + Build.VERSION.SDK_INT + } else { + null + } } - } - fun localhostHandshakeCertificates(): HandshakeCertificates { - return when { - isBouncyCastle() -> localhostHandshakeCertificatesWithRsa2048 - else -> localhost() + fun localhostHandshakeCertificates(): HandshakeCertificates { + return when { + isBouncyCastle() -> localhostHandshakeCertificatesWithRsa2048 + else -> localhost() + } } - } - val isAndroid: Boolean - get() = Platform.Companion.isAndroid - - companion object { - const val PROPERTY_NAME = "okhttp.platform" - const val CONSCRYPT_PROPERTY = "conscrypt" - const val CORRETTO_PROPERTY = "corretto" - const val JDK9_PROPERTY = "jdk9" - const val JDK8_ALPN_PROPERTY = "jdk8alpn" - const val JDK8_PROPERTY = "jdk8" - const val OPENJSSE_PROPERTY = "openjsse" - const val BOUNCYCASTLE_PROPERTY = "bouncycastle" - const val LOOM_PROPERTY = "loom" - - /** - * For whatever reason our BouncyCastle provider doesn't work with ECDSA keys. Just configure it - * to use RSA-2048 instead. - * - * (We otherwise prefer ECDSA because it's faster.) - */ - private val localhostHandshakeCertificatesWithRsa2048: HandshakeCertificates by lazy { - val heldCertificate = HeldCertificate.Builder() - .commonName("localhost") - .addSubjectAlternativeName("localhost") - .rsa2048() - .build() - return@lazy HandshakeCertificates.Builder() - .heldCertificate(heldCertificate) - .addTrustedCertificate(heldCertificate.certificate) - .build() - } - - init { - val platformSystemProperty = getPlatformSystemProperty() - - if (platformSystemProperty == JDK9_PROPERTY) { - if (System.getProperty("javax.net.debug") == null) { - System.setProperty("javax.net.debug", "") - } - } else if (platformSystemProperty == CONSCRYPT_PROPERTY) { - if (Security.getProviders()[0].name != "Conscrypt") { - if (!Conscrypt.isAvailable()) { - System.err.println("Warning: Conscrypt not available") - } + val isAndroid: Boolean + get() = Platform.Companion.isAndroid + + companion object { + const val PROPERTY_NAME = "okhttp.platform" + const val CONSCRYPT_PROPERTY = "conscrypt" + const val CORRETTO_PROPERTY = "corretto" + const val JDK9_PROPERTY = "jdk9" + const val JDK8_ALPN_PROPERTY = "jdk8alpn" + const val JDK8_PROPERTY = "jdk8" + const val OPENJSSE_PROPERTY = "openjsse" + const val BOUNCYCASTLE_PROPERTY = "bouncycastle" + const val LOOM_PROPERTY = "loom" + + /** + * For whatever reason our BouncyCastle provider doesn't work with ECDSA keys. Just configure it + * to use RSA-2048 instead. + * + * (We otherwise prefer ECDSA because it's faster.) + */ + private val localhostHandshakeCertificatesWithRsa2048: HandshakeCertificates by lazy { + val heldCertificate = + HeldCertificate.Builder() + .commonName("localhost") + .addSubjectAlternativeName("localhost") + .rsa2048() + .build() + return@lazy HandshakeCertificates.Builder() + .heldCertificate(heldCertificate) + .addTrustedCertificate(heldCertificate.certificate) + .build() + } - val provider = Conscrypt.newProviderBuilder() - .provideTrustManager(true) - .build() - Security.insertProviderAt(provider, 1) - } - } else if (platformSystemProperty == JDK8_ALPN_PROPERTY) { - if (!isAlpnBootEnabled()) { - System.err.println("Warning: ALPN Boot not enabled") - } - } else if (platformSystemProperty == JDK8_PROPERTY) { - if (isAlpnBootEnabled()) { - System.err.println("Warning: ALPN Boot enabled unintentionally") - } - } else if (platformSystemProperty == OPENJSSE_PROPERTY && Security.getProviders()[0].name != "OpenJSSE") { - if (!OpenJSSEPlatform.isSupported) { - System.err.println("Warning: OpenJSSE not available") - } + init { + val platformSystemProperty = getPlatformSystemProperty() - if (System.getProperty("javax.net.debug") == null) { - System.setProperty("javax.net.debug", "") - } + if (platformSystemProperty == JDK9_PROPERTY) { + if (System.getProperty("javax.net.debug") == null) { + System.setProperty("javax.net.debug", "") + } + } else if (platformSystemProperty == CONSCRYPT_PROPERTY) { + if (Security.getProviders()[0].name != "Conscrypt") { + if (!Conscrypt.isAvailable()) { + System.err.println("Warning: Conscrypt not available") + } + + val provider = + Conscrypt.newProviderBuilder() + .provideTrustManager(true) + .build() + Security.insertProviderAt(provider, 1) + } + } else if (platformSystemProperty == JDK8_ALPN_PROPERTY) { + if (!isAlpnBootEnabled()) { + System.err.println("Warning: ALPN Boot not enabled") + } + } else if (platformSystemProperty == JDK8_PROPERTY) { + if (isAlpnBootEnabled()) { + System.err.println("Warning: ALPN Boot enabled unintentionally") + } + } else if (platformSystemProperty == OPENJSSE_PROPERTY && Security.getProviders()[0].name != "OpenJSSE") { + if (!OpenJSSEPlatform.isSupported) { + System.err.println("Warning: OpenJSSE not available") + } - Security.insertProviderAt(OpenJSSE(), 1) - } else if (platformSystemProperty == BOUNCYCASTLE_PROPERTY && Security.getProviders()[0].name != "BC") { - Security.insertProviderAt(BouncyCastleProvider(), 1) - Security.insertProviderAt(BouncyCastleJsseProvider(), 2) - } else if (platformSystemProperty == CORRETTO_PROPERTY) { - AmazonCorrettoCryptoProvider.install() + if (System.getProperty("javax.net.debug") == null) { + System.setProperty("javax.net.debug", "") + } - AmazonCorrettoCryptoProvider.INSTANCE.assertHealthy() - } + Security.insertProviderAt(OpenJSSE(), 1) + } else if (platformSystemProperty == BOUNCYCASTLE_PROPERTY && Security.getProviders()[0].name != "BC") { + Security.insertProviderAt(BouncyCastleProvider(), 1) + Security.insertProviderAt(BouncyCastleJsseProvider(), 2) + } else if (platformSystemProperty == CORRETTO_PROPERTY) { + AmazonCorrettoCryptoProvider.install() - Platform.resetForTests() + AmazonCorrettoCryptoProvider.INSTANCE.assertHealthy() + } - System.err.println("Running Tests with ${Platform.get().javaClass.simpleName}") - } + Platform.resetForTests() - @JvmStatic - fun getPlatformSystemProperty(): String { - var property: String? = System.getProperty(PROPERTY_NAME) + System.err.println("Running Tests with ${Platform.get().javaClass.simpleName}") + } - if (property == null) { - property = when (Platform.get()) { - is ConscryptPlatform -> CONSCRYPT_PROPERTY - is OpenJSSEPlatform -> OPENJSSE_PROPERTY - is Jdk8WithJettyBootPlatform -> CONSCRYPT_PROPERTY - is Jdk9Platform -> { - if (isCorrettoInstalled) CORRETTO_PROPERTY else JDK9_PROPERTY - } - else -> JDK8_PROPERTY + @JvmStatic + fun getPlatformSystemProperty(): String { + var property: String? = System.getProperty(PROPERTY_NAME) + + if (property == null) { + property = + when (Platform.get()) { + is ConscryptPlatform -> CONSCRYPT_PROPERTY + is OpenJSSEPlatform -> OPENJSSE_PROPERTY + is Jdk8WithJettyBootPlatform -> CONSCRYPT_PROPERTY + is Jdk9Platform -> { + if (isCorrettoInstalled) CORRETTO_PROPERTY else JDK9_PROPERTY + } + else -> JDK8_PROPERTY + } } - } - return property - } + return property + } - @JvmStatic - fun conscrypt() = PlatformRule(CONSCRYPT_PROPERTY) + @JvmStatic + fun conscrypt() = PlatformRule(CONSCRYPT_PROPERTY) - @JvmStatic - fun openjsse() = PlatformRule(OPENJSSE_PROPERTY) + @JvmStatic + fun openjsse() = PlatformRule(OPENJSSE_PROPERTY) - @JvmStatic - fun jdk9() = PlatformRule(JDK9_PROPERTY) + @JvmStatic + fun jdk9() = PlatformRule(JDK9_PROPERTY) - @JvmStatic - fun jdk8() = PlatformRule(JDK8_PROPERTY) + @JvmStatic + fun jdk8() = PlatformRule(JDK8_PROPERTY) - @JvmStatic - fun jdk8alpn() = PlatformRule(JDK8_ALPN_PROPERTY) + @JvmStatic + fun jdk8alpn() = PlatformRule(JDK8_ALPN_PROPERTY) - @JvmStatic - fun bouncycastle() = PlatformRule(BOUNCYCASTLE_PROPERTY) + @JvmStatic + fun bouncycastle() = PlatformRule(BOUNCYCASTLE_PROPERTY) - @JvmStatic - fun isAlpnBootEnabled(): Boolean = try { - Class.forName("org.eclipse.jetty.alpn.ALPN", true, null) - true - } catch (cnfe: ClassNotFoundException) { - false - } + @JvmStatic + fun isAlpnBootEnabled(): Boolean = + try { + Class.forName("org.eclipse.jetty.alpn.ALPN", true, null) + true + } catch (cnfe: ClassNotFoundException) { + false + } - val isCorrettoSupported: Boolean = try { - // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. - Class.forName("com.amazon.corretto.crypto.provider.AmazonCorrettoCryptoProvider") + val isCorrettoSupported: Boolean = + try { + // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. + Class.forName("com.amazon.corretto.crypto.provider.AmazonCorrettoCryptoProvider") - AmazonCorrettoCryptoProvider.INSTANCE.loadingError == null && - AmazonCorrettoCryptoProvider.INSTANCE.runSelfTests() == SelfTestStatus.PASSED - } catch (e: ClassNotFoundException) { - false - } + AmazonCorrettoCryptoProvider.INSTANCE.loadingError == null && + AmazonCorrettoCryptoProvider.INSTANCE.runSelfTests() == SelfTestStatus.PASSED + } catch (e: ClassNotFoundException) { + false + } - val isCorrettoInstalled: Boolean = - isCorrettoSupported && Security.getProviders() + val isCorrettoInstalled: Boolean = + isCorrettoSupported && Security.getProviders() .first().name == AmazonCorrettoCryptoProvider.PROVIDER_NAME + } } -} diff --git a/okhttp-testing-support/src/test/kotlin/okhttp3/OkHttpClientTestRuleTest.kt b/okhttp-testing-support/src/test/kotlin/okhttp3/OkHttpClientTestRuleTest.kt index f14899122877..3673ca4e201c 100644 --- a/okhttp-testing-support/src/test/kotlin/okhttp3/OkHttpClientTestRuleTest.kt +++ b/okhttp-testing-support/src/test/kotlin/okhttp3/OkHttpClientTestRuleTest.kt @@ -26,19 +26,22 @@ import org.junit.jupiter.api.extension.RegisterExtension class OkHttpClientTestRuleTest { lateinit var extensionContext: ExtensionContext - @RegisterExtension @JvmField val beforeEachCallback = BeforeEachCallback { context -> - this@OkHttpClientTestRuleTest.extensionContext = context - } + @RegisterExtension @JvmField + val beforeEachCallback = + BeforeEachCallback { context -> + this@OkHttpClientTestRuleTest.extensionContext = context + } @Test fun uncaughtException() { val testRule = OkHttpClientTestRule() testRule.beforeEach(extensionContext) - val thread = object : Thread() { - override fun run() { - throw RuntimeException("boom!") + val thread = + object : Thread() { + override fun run() { + throw RuntimeException("boom!") + } } - } thread.start() thread.join() diff --git a/okhttp-testing-support/src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt b/okhttp-testing-support/src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt index 188e1e3db737..15535af42cbc 100644 --- a/okhttp-testing-support/src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt +++ b/okhttp-testing-support/src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt @@ -23,7 +23,8 @@ import org.junit.jupiter.api.extension.RegisterExtension * Sanity test for checking which environment and IDE is picking up. */ class PlatformRuleTest { - @RegisterExtension @JvmField val platform = PlatformRule() + @RegisterExtension @JvmField + val platform = PlatformRule() @Test fun testMode() { diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/Certificates.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/Certificates.kt index 50183a5e7d73..f7ccb003aac4 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/Certificates.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/Certificates.kt @@ -45,9 +45,11 @@ import okio.ByteString.Companion.toByteString fun String.decodeCertificatePem(): X509Certificate { try { val certificateFactory = CertificateFactory.getInstance("X.509") - val certificates = certificateFactory + val certificates = + certificateFactory .generateCertificates( - Buffer().writeUtf8(this).inputStream()) + Buffer().writeUtf8(this).inputStream(), + ) return certificates.single() as X509Certificate } catch (nsee: NoSuchElementException) { diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/HandshakeCertificates.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/HandshakeCertificates.kt index ae80a37cd226..b562d896064f 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/HandshakeCertificates.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/HandshakeCertificates.kt @@ -14,8 +14,10 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3.tls +import java.security.KeyStoreException import java.security.SecureRandom import java.security.cert.X509Certificate import java.util.Collections @@ -31,7 +33,6 @@ import okhttp3.internal.platform.Platform import okhttp3.internal.toImmutableList import okhttp3.tls.internal.TlsUtil.newKeyManager import okhttp3.tls.internal.TlsUtil.newTrustManager -import java.security.KeyStoreException /** * Certificates to identify which peers to trust and also to earn the trust of those peers in kind. @@ -72,21 +73,22 @@ import java.security.KeyStoreException */ class HandshakeCertificates private constructor( @get:JvmName("keyManager") val keyManager: X509KeyManager, - @get:JvmName("trustManager") val trustManager: X509TrustManager + @get:JvmName("trustManager") val trustManager: X509TrustManager, ) { - @JvmName("-deprecated_keyManager") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "keyManager"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "keyManager"), + level = DeprecationLevel.ERROR, + ) fun keyManager(): X509KeyManager = keyManager @JvmName("-deprecated_trustManager") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "trustManager"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "trustManager"), + level = DeprecationLevel.ERROR, + ) fun trustManager(): X509TrustManager = trustManager fun sslSocketFactory(): SSLSocketFactory = sslContext().socketFactory @@ -114,7 +116,7 @@ class HandshakeCertificates private constructor( */ fun heldCertificate( heldCertificate: HeldCertificate, - vararg intermediates: X509Certificate + vararg intermediates: X509Certificate, ) = apply { this.heldCertificate = heldCertificate this.intermediates = arrayOf(*intermediates) // Defensive copy. @@ -124,9 +126,10 @@ class HandshakeCertificates private constructor( * Add a trusted root certificate to use when authenticating a peer. Peers must provide * a chain of certificates whose root is one of these. */ - fun addTrustedCertificate(certificate: X509Certificate) = apply { - this.trustedCertificates += certificate - } + fun addTrustedCertificate(certificate: X509Certificate) = + apply { + this.trustedCertificates += certificate + } /** * Add all of the host platform's trusted root certificates. This set varies by platform @@ -140,10 +143,11 @@ class HandshakeCertificates private constructor( * certificates. Applications that connect to a known set of servers may be able to mitigate * this problem with [certificate pinning][CertificatePinner]. */ - fun addPlatformTrustedCertificates() = apply { - val platformTrustManager = Platform.get().platformTrustManager() - Collections.addAll(trustedCertificates, *platformTrustManager.acceptedIssuers) - } + fun addPlatformTrustedCertificates() = + apply { + val platformTrustManager = Platform.get().platformTrustManager() + Collections.addAll(trustedCertificates, *platformTrustManager.acceptedIssuers) + } /** * Configures this to not authenticate the HTTPS server on to [hostname]. This makes the user @@ -168,9 +172,10 @@ class HandshakeCertificates private constructor( * * @param hostname the exact hostname from the URL for insecure connections. */ - fun addInsecureHost(hostname: String) = apply { - insecureHosts += hostname - } + fun addInsecureHost(hostname: String) = + apply { + insecureHosts += hostname + } fun build(): HandshakeCertificates { val immutableInsecureHosts = insecureHosts.toImmutableList() diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/HeldCertificate.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/HeldCertificate.kt index efca939e6bfb..de22fdf7407b 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/HeldCertificate.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/HeldCertificate.kt @@ -45,8 +45,8 @@ import okhttp3.tls.internal.der.Extension import okhttp3.tls.internal.der.ObjectIdentifiers import okhttp3.tls.internal.der.ObjectIdentifiers.BASIC_CONSTRAINTS import okhttp3.tls.internal.der.ObjectIdentifiers.ORGANIZATIONAL_UNIT_NAME -import okhttp3.tls.internal.der.ObjectIdentifiers.SHA256_WITH_RSA_ENCRYPTION import okhttp3.tls.internal.der.ObjectIdentifiers.SHA256_WITH_ECDSA +import okhttp3.tls.internal.der.ObjectIdentifiers.SHA256_WITH_RSA_ENCRYPTION import okhttp3.tls.internal.der.ObjectIdentifiers.SUBJECT_ALTERNATIVE_NAME import okhttp3.tls.internal.der.TbsCertificate import okhttp3.tls.internal.der.Validity @@ -128,21 +128,22 @@ import okio.ByteString.Companion.toByteString @Suppress("DEPRECATION") class HeldCertificate( @get:JvmName("keyPair") val keyPair: KeyPair, - @get:JvmName("certificate") val certificate: X509Certificate + @get:JvmName("certificate") val certificate: X509Certificate, ) { - @JvmName("-deprecated_certificate") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "certificate"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "certificate"), + level = DeprecationLevel.ERROR, + ) fun certificate(): X509Certificate = certificate @JvmName("-deprecated_keyPair") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "keyPair"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "keyPair"), + level = DeprecationLevel.ERROR, + ) fun keyPair(): KeyPair = keyPair /** @@ -209,7 +210,10 @@ class HeldCertificate( * in the format of [System.currentTimeMillis]. Specify -1L for both values to use the default * interval, 24 hours starting when the certificate is created. */ - fun validityInterval(notBefore: Long, notAfter: Long) = apply { + fun validityInterval( + notBefore: Long, + notAfter: Long, + ) = apply { require(notBefore <= notAfter && notBefore == -1L == (notAfter == -1L)) { "invalid interval: $notBefore..$notAfter" } @@ -221,7 +225,10 @@ class HeldCertificate( * Sets the certificate to be valid immediately and until the specified duration has elapsed. * The precision of this field is seconds; further precision will be truncated. */ - fun duration(duration: Long, unit: TimeUnit) = apply { + fun duration( + duration: Long, + unit: TimeUnit, + ) = apply { val now = System.currentTimeMillis() validityInterval(now, now + unit.toMillis(duration)) } @@ -231,9 +238,10 @@ class HeldCertificate( * a literal IP address, or a hostname pattern. If no subject alternative names are added that * extension will be omitted. */ - fun addSubjectAlternativeName(altName: String) = apply { - altNames += altName - } + fun addSubjectAlternativeName(altName: String) = + apply { + altNames += altName + } /** * Set this certificate's common name (CN). Historically this held the hostname of TLS @@ -242,38 +250,46 @@ class HeldCertificate( * * [rfc_2818]: https://tools.ietf.org/html/rfc2818 */ - fun commonName(cn: String) = apply { - this.commonName = cn - } + fun commonName(cn: String) = + apply { + this.commonName = cn + } /** Sets the certificate's organizational unit (OU). If unset this field will be omitted. */ - fun organizationalUnit(ou: String) = apply { - this.organizationalUnit = ou - } + fun organizationalUnit(ou: String) = + apply { + this.organizationalUnit = ou + } /** Sets this certificate's serial number. If unset the serial number will be 1. */ - fun serialNumber(serialNumber: BigInteger) = apply { - this.serialNumber = serialNumber - } + fun serialNumber(serialNumber: BigInteger) = + apply { + this.serialNumber = serialNumber + } /** Sets this certificate's serial number. If unset the serial number will be 1. */ - fun serialNumber(serialNumber: Long) = apply { - serialNumber(BigInteger.valueOf(serialNumber)) - } + fun serialNumber(serialNumber: Long) = + apply { + serialNumber(BigInteger.valueOf(serialNumber)) + } /** * Sets the public/private key pair used for this certificate. If unset a key pair will be * generated. */ - fun keyPair(keyPair: KeyPair) = apply { - this.keyPair = keyPair - } + fun keyPair(keyPair: KeyPair) = + apply { + this.keyPair = keyPair + } /** * Sets the public/private key pair used for this certificate. If unset a key pair will be * generated. */ - fun keyPair(publicKey: PublicKey, privateKey: PrivateKey) = apply { + fun keyPair( + publicKey: PublicKey, + privateKey: PrivateKey, + ) = apply { keyPair(KeyPair(publicKey, privateKey)) } @@ -281,9 +297,10 @@ class HeldCertificate( * Set the certificate that will issue this certificate. If unset the certificate will be * self-signed. */ - fun signedBy(signedBy: HeldCertificate?) = apply { - this.signedBy = signedBy - } + fun signedBy(signedBy: HeldCertificate?) = + apply { + this.signedBy = signedBy + } /** * Set this certificate to be a signing certificate, with up to `maxIntermediateCas` @@ -294,12 +311,13 @@ class HeldCertificate( * certificates). Set this to 1 so this certificate can sign intermediate certificates that can * themselves sign certificates. Add one for each additional layer of intermediates to permit. */ - fun certificateAuthority(maxIntermediateCas: Int) = apply { - require(maxIntermediateCas >= 0) { - "maxIntermediateCas < 0: $maxIntermediateCas" + fun certificateAuthority(maxIntermediateCas: Int) = + apply { + require(maxIntermediateCas >= 0) { + "maxIntermediateCas < 0: $maxIntermediateCas" + } + this.maxIntermediateCas = maxIntermediateCas } - this.maxIntermediateCas = maxIntermediateCas - } /** * Configure the certificate to generate a 256-bit ECDSA key, which provides about 128 bits of @@ -308,26 +326,29 @@ class HeldCertificate( * This is the default configuration and has been since this API was introduced in OkHttp * 3.11.0. Note that the default may change in future releases. */ - fun ecdsa256() = apply { - keyAlgorithm = "EC" - keySize = 256 - } + fun ecdsa256() = + apply { + keyAlgorithm = "EC" + keySize = 256 + } /** * Configure the certificate to generate a 2048-bit RSA key, which provides about 112 bits of * security. RSA keys are interoperable with very old clients that don't support ECDSA. */ - fun rsa2048() = apply { - keyAlgorithm = "RSA" - keySize = 2048 - } + fun rsa2048() = + apply { + keyAlgorithm = "RSA" + keySize = 2048 + } fun build(): HeldCertificate { // Subject keys & identity. val subjectKeyPair = keyPair ?: generateKeyPair() - val subjectPublicKeyInfo = CertificateAdapters.subjectPublicKeyInfo.fromDer( - subjectKeyPair.public.encoded.toByteString() - ) + val subjectPublicKeyInfo = + CertificateAdapters.subjectPublicKeyInfo.fromDer( + subjectKeyPair.public.encoded.toByteString(), + ) val subject: List> = subject() // Issuer/signer keys & identity. May be the subject if it is self-signed. @@ -335,9 +356,10 @@ class HeldCertificate( val issuer: List> if (signedBy != null) { issuerKeyPair = signedBy!!.keyPair - issuer = CertificateAdapters.rdnSequence.fromDer( - signedBy!!.certificate.subjectX500Principal.encoded.toByteString() - ) + issuer = + CertificateAdapters.rdnSequence.fromDer( + signedBy!!.certificate.subjectX500Principal.encoded.toByteString(), + ) } else { issuerKeyPair = subjectKeyPair issuer = subject @@ -345,7 +367,8 @@ class HeldCertificate( val signatureAlgorithm = signatureAlgorithm(issuerKeyPair) // Subset of certificate data that's covered by the signature. - val tbsCertificate = TbsCertificate( + val tbsCertificate = + TbsCertificate( // v3: version = 2L, serialNumber = serialNumber ?: BigInteger.ONE, @@ -356,25 +379,28 @@ class HeldCertificate( subjectPublicKeyInfo = subjectPublicKeyInfo, issuerUniqueID = null, subjectUniqueID = null, - extensions = extensions() - ) + extensions = extensions(), + ) // Signature. - val signature = Signature.getInstance(tbsCertificate.signatureAlgorithmName).run { - initSign(issuerKeyPair.private) - update(CertificateAdapters.tbsCertificate.toDer(tbsCertificate).toByteArray()) - sign().toByteString() - } + val signature = + Signature.getInstance(tbsCertificate.signatureAlgorithmName).run { + initSign(issuerKeyPair.private) + update(CertificateAdapters.tbsCertificate.toDer(tbsCertificate).toByteArray()) + sign().toByteString() + } // Complete signed certificate. - val certificate = Certificate( + val certificate = + Certificate( tbsCertificate = tbsCertificate, signatureAlgorithm = signatureAlgorithm, - signatureValue = BitString( + signatureValue = + BitString( byteString = signature, - unusedBitsCount = 0 - ) - ) + unusedBitsCount = 0, + ), + ) return HeldCertificate(subjectKeyPair, certificate.toX509Certificate()) } @@ -383,16 +409,22 @@ class HeldCertificate( val result = mutableListOf>() if (organizationalUnit != null) { - result += listOf(AttributeTypeAndValue( - type = ORGANIZATIONAL_UNIT_NAME, - value = organizationalUnit - )) + result += + listOf( + AttributeTypeAndValue( + type = ORGANIZATIONAL_UNIT_NAME, + value = organizationalUnit, + ), + ) } - result += listOf(AttributeTypeAndValue( - type = ObjectIdentifiers.COMMON_NAME, - value = commonName ?: UUID.randomUUID().toString() - )) + result += + listOf( + AttributeTypeAndValue( + type = ObjectIdentifiers.COMMON_NAME, + value = commonName ?: UUID.randomUUID().toString(), + ), + ) return result } @@ -401,8 +433,8 @@ class HeldCertificate( val notBefore = if (notBefore != -1L) notBefore else System.currentTimeMillis() val notAfter = if (notAfter != -1L) notAfter else notBefore + DEFAULT_DURATION_MILLIS return Validity( - notBefore = notBefore, - notAfter = notAfter + notBefore = notBefore, + notAfter = notAfter, ) } @@ -410,32 +442,36 @@ class HeldCertificate( val result = mutableListOf() if (maxIntermediateCas != -1) { - result += Extension( + result += + Extension( id = BASIC_CONSTRAINTS, critical = true, - value = BasicConstraints( + value = + BasicConstraints( ca = true, - maxIntermediateCas = maxIntermediateCas.toLong() - ) - ) + maxIntermediateCas = maxIntermediateCas.toLong(), + ), + ) } if (altNames.isNotEmpty()) { - val extensionValue = altNames.map { - when { - it.canParseAsIpAddress() -> { - generalNameIpAddress to InetAddress.getByName(it).address.toByteString() - } - else -> { - generalNameDnsName to it + val extensionValue = + altNames.map { + when { + it.canParseAsIpAddress() -> { + generalNameIpAddress to InetAddress.getByName(it).address.toByteString() + } + else -> { + generalNameDnsName to it + } } } - } - result += Extension( + result += + Extension( id = SUBJECT_ALTERNATIVE_NAME, critical = true, - value = extensionValue - ) + value = extensionValue, + ) } return result @@ -443,14 +479,16 @@ class HeldCertificate( private fun signatureAlgorithm(signedByKeyPair: KeyPair): AlgorithmIdentifier { return when (signedByKeyPair.private) { - is RSAPrivateKey -> AlgorithmIdentifier( + is RSAPrivateKey -> + AlgorithmIdentifier( algorithm = SHA256_WITH_RSA_ENCRYPTION, - parameters = null - ) - else -> AlgorithmIdentifier( + parameters = null, + ) + else -> + AlgorithmIdentifier( algorithm = SHA256_WITH_ECDSA, - parameters = ByteString.EMPTY - ) + parameters = ByteString.EMPTY, + ) } } @@ -526,18 +564,23 @@ class HeldCertificate( return decode(certificatePem, pkcs8Base64) } - private fun decode(certificatePem: String, pkcs8Base64Text: String): HeldCertificate { + private fun decode( + certificatePem: String, + pkcs8Base64Text: String, + ): HeldCertificate { val certificate = certificatePem.decodeCertificatePem() - val pkcs8Bytes = pkcs8Base64Text.decodeBase64() + val pkcs8Bytes = + pkcs8Base64Text.decodeBase64() ?: throw IllegalArgumentException("failed to decode private key") // The private key doesn't tell us its type but it's okay because the certificate knows! - val keyType = when (certificate.publicKey) { - is ECPublicKey -> "EC" - is RSAPublicKey -> "RSA" - else -> throw IllegalArgumentException("unexpected key type: ${certificate.publicKey}") - } + val keyType = + when (certificate.publicKey) { + is ECPublicKey -> "EC" + is RSAPublicKey -> "RSA" + else -> throw IllegalArgumentException("unexpected key type: ${certificate.publicKey}") + } val privateKey = decodePkcs8(pkcs8Bytes, keyType) @@ -545,7 +588,10 @@ class HeldCertificate( return HeldCertificate(keyPair, certificate) } - private fun decodePkcs8(data: ByteString, keyAlgorithm: String): PrivateKey { + private fun decodePkcs8( + data: ByteString, + keyAlgorithm: String, + ): PrivateKey { try { val keyFactory = KeyFactory.getInstance(keyAlgorithm) return keyFactory.generatePrivate(PKCS8EncodedKeySpec(data.toByteArray())) diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/InsecureAndroidTrustManager.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/InsecureAndroidTrustManager.kt index c689b5696464..216712835d24 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/InsecureAndroidTrustManager.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/InsecureAndroidTrustManager.kt @@ -25,25 +25,31 @@ import javax.net.ssl.X509TrustManager /** This extends [X509TrustManager] for Android to disable verification for a set of hosts. */ internal class InsecureAndroidTrustManager( private val delegate: X509TrustManager, - private val insecureHosts: List + private val insecureHosts: List, ) : X509TrustManager { - private val checkServerTrustedMethod: Method? = try { - delegate::class.java.getMethod("checkServerTrusted", - Array::class.java, String::class.java, String::class.java) - } catch (_: NoSuchMethodException) { - null - } + private val checkServerTrustedMethod: Method? = + try { + delegate::class.java.getMethod( + "checkServerTrusted", + Array::class.java, + String::class.java, + String::class.java, + ) + } catch (_: NoSuchMethodException) { + null + } /** Android method to clean and sort certificates, called via reflection. */ @Suppress("unused", "UNCHECKED_CAST") fun checkServerTrusted( chain: Array, authType: String, - host: String + host: String, ): List { if (host in insecureHosts) return listOf() try { - val method = checkServerTrustedMethod + val method = + checkServerTrustedMethod ?: throw CertificateException("Failed to call checkServerTrusted") return method.invoke(delegate, chain, authType, host) as List } catch (e: InvocationTargetException) { @@ -53,9 +59,13 @@ internal class InsecureAndroidTrustManager( override fun getAcceptedIssuers(): Array = delegate.acceptedIssuers - override fun checkClientTrusted(chain: Array, authType: String?) = - throw CertificateException("Unsupported operation") + override fun checkClientTrusted( + chain: Array, + authType: String?, + ) = throw CertificateException("Unsupported operation") - override fun checkServerTrusted(chain: Array, authType: String) = - throw CertificateException("Unsupported operation") + override fun checkServerTrusted( + chain: Array, + authType: String, + ) = throw CertificateException("Unsupported operation") } diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/InsecureExtendedTrustManager.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/InsecureExtendedTrustManager.kt index 38b9caf9648b..9b2e27edd398 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/InsecureExtendedTrustManager.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/InsecureExtendedTrustManager.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3.tls.internal import java.net.Socket @@ -33,14 +34,14 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement @IgnoreJRERequirement internal class InsecureExtendedTrustManager( private val delegate: X509ExtendedTrustManager, - private val insecureHosts: List + private val insecureHosts: List, ) : X509ExtendedTrustManager() { override fun getAcceptedIssuers(): Array = delegate.acceptedIssuers override fun checkServerTrusted( chain: Array, authType: String, - socket: Socket + socket: Socket, ) { if (socket.peerName() !in insecureHosts) { delegate.checkServerTrusted(chain, authType, socket) @@ -50,28 +51,32 @@ internal class InsecureExtendedTrustManager( override fun checkServerTrusted( chain: Array, authType: String, - engine: SSLEngine + engine: SSLEngine, ) { if (engine.peerHost !in insecureHosts) { delegate.checkServerTrusted(chain, authType, engine) } } - override fun checkServerTrusted(chain: Array, authType: String) = - throw CertificateException("Unsupported operation") + override fun checkServerTrusted( + chain: Array, + authType: String, + ) = throw CertificateException("Unsupported operation") - override fun checkClientTrusted(chain: Array, authType: String?) = - throw CertificateException("Unsupported operation") + override fun checkClientTrusted( + chain: Array, + authType: String?, + ) = throw CertificateException("Unsupported operation") override fun checkClientTrusted( chain: Array, authType: String, - engine: SSLEngine? + engine: SSLEngine?, ) = throw CertificateException("Unsupported operation") override fun checkClientTrusted( chain: Array, authType: String, - socket: Socket? + socket: Socket?, ) = throw CertificateException("Unsupported operation") } diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/TlsUtil.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/TlsUtil.kt index 496d11a33ac5..ad76e91bbf51 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/TlsUtil.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/TlsUtil.kt @@ -16,7 +16,6 @@ package okhttp3.tls.internal import java.io.InputStream -import java.net.InetAddress import java.security.KeyStore import java.security.cert.Certificate import java.security.cert.X509Certificate @@ -35,15 +34,16 @@ object TlsUtil { private val localhost: HandshakeCertificates by lazy { // Generate a self-signed cert for the server to serve and the client to trust. - val heldCertificate = HeldCertificate.Builder() + val heldCertificate = + HeldCertificate.Builder() .commonName("localhost") .addSubjectAlternativeName("localhost") .addSubjectAlternativeName("localhost.localdomain") .build() return@lazy HandshakeCertificates.Builder() - .heldCertificate(heldCertificate) - .addTrustedCertificate(heldCertificate.certificate) - .build() + .heldCertificate(heldCertificate) + .addTrustedCertificate(heldCertificate.certificate) + .build() } /** Returns an SSL client for this host's localhost address. */ @@ -55,7 +55,7 @@ object TlsUtil { fun newTrustManager( keyStoreType: String?, trustedCertificates: List, - insecureHosts: List + insecureHosts: List, ): X509TrustManager { val trustStore = newEmptyKeyStore(keyStoreType) for (i in trustedCertificates.indices) { @@ -86,7 +86,7 @@ object TlsUtil { fun newKeyManager( keyStoreType: String?, heldCertificate: HeldCertificate?, - vararg intermediates: X509Certificate + vararg intermediates: X509Certificate, ): X509KeyManager { val keyStore = newEmptyKeyStore(keyStoreType) if (heldCertificate != null) { diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Adapters.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Adapters.kt index 4aa724e9ee4a..b0ec0cd75788 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Adapters.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Adapters.kt @@ -28,86 +28,134 @@ import okio.ByteString * Built-in adapters for reading standard ASN.1 types. */ internal object Adapters { - val BOOLEAN = BasicDerAdapter( + val BOOLEAN = + BasicDerAdapter( name = "BOOLEAN", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 1L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): Boolean = reader.readBoolean() - override fun encode(writer: DerWriter, value: Boolean) = writer.writeBoolean(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): Boolean = reader.readBoolean() + + override fun encode( + writer: DerWriter, + value: Boolean, + ) = writer.writeBoolean(value) + }, + ) - val INTEGER_AS_LONG = BasicDerAdapter( + val INTEGER_AS_LONG = + BasicDerAdapter( name = "INTEGER", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 2L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): Long = reader.readLong() - override fun encode(writer: DerWriter, value: Long) = writer.writeLong(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): Long = reader.readLong() + + override fun encode( + writer: DerWriter, + value: Long, + ) = writer.writeLong(value) + }, + ) - val INTEGER_AS_BIG_INTEGER = BasicDerAdapter( + val INTEGER_AS_BIG_INTEGER = + BasicDerAdapter( name = "INTEGER", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 2L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): BigInteger = reader.readBigInteger() - override fun encode(writer: DerWriter, value: BigInteger) = writer.writeBigInteger(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): BigInteger = reader.readBigInteger() + + override fun encode( + writer: DerWriter, + value: BigInteger, + ) = writer.writeBigInteger(value) + }, + ) - val BIT_STRING = BasicDerAdapter( + val BIT_STRING = + BasicDerAdapter( name = "BIT STRING", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 3L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): BitString = reader.readBitString() - override fun encode(writer: DerWriter, value: BitString) = writer.writeBitString(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): BitString = reader.readBitString() + + override fun encode( + writer: DerWriter, + value: BitString, + ) = writer.writeBitString(value) + }, + ) - val OCTET_STRING = BasicDerAdapter( + val OCTET_STRING = + BasicDerAdapter( name = "OCTET STRING", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 4L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): ByteString = reader.readOctetString() - override fun encode(writer: DerWriter, value: ByteString) = writer.writeOctetString(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): ByteString = reader.readOctetString() + + override fun encode( + writer: DerWriter, + value: ByteString, + ) = writer.writeOctetString(value) + }, + ) - val NULL = BasicDerAdapter( + val NULL = + BasicDerAdapter( name = "NULL", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 5L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): Unit? = null - override fun encode(writer: DerWriter, value: Unit?) { - } - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): Unit? = null + + override fun encode( + writer: DerWriter, + value: Unit?, + ) { + } + }, + ) - val OBJECT_IDENTIFIER = BasicDerAdapter( + val OBJECT_IDENTIFIER = + BasicDerAdapter( name = "OBJECT IDENTIFIER", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 6L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): String = reader.readObjectIdentifier() - override fun encode(writer: DerWriter, value: String) = writer.writeObjectIdentifier(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): String = reader.readObjectIdentifier() + + override fun encode( + writer: DerWriter, + value: String, + ) = writer.writeObjectIdentifier(value) + }, + ) - val UTF8_STRING = BasicDerAdapter( + val UTF8_STRING = + BasicDerAdapter( name = "UTF8", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 12L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): String = reader.readUtf8String() - override fun encode(writer: DerWriter, value: String) = writer.writeUtf8(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): String = reader.readUtf8String() + + override fun encode( + writer: DerWriter, + value: String, + ) = writer.writeUtf8(value) + }, + ) /** * Permits alphanumerics, spaces, and these: @@ -118,15 +166,21 @@ internal object Adapters { * * TODO(jwilson): constrain to printable string characters. */ - val PRINTABLE_STRING = BasicDerAdapter( + val PRINTABLE_STRING = + BasicDerAdapter( name = "PRINTABLE STRING", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 19L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): String = reader.readUtf8String() - override fun encode(writer: DerWriter, value: String) = writer.writeUtf8(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): String = reader.readUtf8String() + + override fun encode( + writer: DerWriter, + value: String, + ) = writer.writeUtf8(value) + }, + ) /** * Based on International Alphabet No. 5. Note that there are bytes that IA5 and US-ASCII @@ -134,42 +188,55 @@ internal object Adapters { * * TODO(jwilson): constrain to IA5 characters. */ - val IA5_STRING = BasicDerAdapter( + val IA5_STRING = + BasicDerAdapter( name = "IA5 STRING", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 22L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): String = reader.readUtf8String() - override fun encode(writer: DerWriter, value: String) = writer.writeUtf8(value) - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): String = reader.readUtf8String() + + override fun encode( + writer: DerWriter, + value: String, + ) = writer.writeUtf8(value) + }, + ) /** * A timestamp like "191216030210Z" or "191215190210-0800" for 2019-12-15T19:02:10-08:00. The * cutoff of the 2-digit year is 1950-01-01T00:00:00Z. */ - val UTC_TIME = BasicDerAdapter( + val UTC_TIME = + BasicDerAdapter( name = "UTC TIME", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 23L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): Long { - val string = reader.readUtf8String() - return parseUtcTime(string) - } - override fun encode(writer: DerWriter, value: Long) { - val string = formatUtcTime(value) - return writer.writeUtf8(string) - } - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): Long { + val string = reader.readUtf8String() + return parseUtcTime(string) + } + + override fun encode( + writer: DerWriter, + value: Long, + ) { + val string = formatUtcTime(value) + return writer.writeUtf8(string) + } + }, + ) internal fun parseUtcTime(string: String): Long { val utc = TimeZone.getTimeZone("GMT") - val dateFormat = SimpleDateFormat("yyMMddHHmmss'Z'").apply { - timeZone = utc - set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z. - } + val dateFormat = + SimpleDateFormat("yyMMddHHmmss'Z'").apply { + timeZone = utc + set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z. + } try { val parsed = dateFormat.parse(string) @@ -181,10 +248,11 @@ internal object Adapters { internal fun formatUtcTime(date: Long): String { val utc = TimeZone.getTimeZone("GMT") - val dateFormat = SimpleDateFormat("yyMMddHHmmss'Z'").apply { - timeZone = utc - set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z. - } + val dateFormat = + SimpleDateFormat("yyMMddHHmmss'Z'").apply { + timeZone = utc + set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z. + } return dateFormat.format(date) } @@ -193,52 +261,63 @@ internal object Adapters { * A timestamp like "191216030210Z" or "20191215190210-0800" for 2019-12-15T19:02:10-08:00. This * is the same as [UTC_TIME] with the exception of the 4-digit year. */ - val GENERALIZED_TIME = BasicDerAdapter( + val GENERALIZED_TIME = + BasicDerAdapter( name = "GENERALIZED TIME", tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = 24L, - codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): Long { - val string = reader.readUtf8String() - return parseGeneralizedTime(string) - } - override fun encode(writer: DerWriter, value: Long) { - val string = formatGeneralizedTime(value) - return writer.writeUtf8(string) - } - } - ) + codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): Long { + val string = reader.readUtf8String() + return parseGeneralizedTime(string) + } + + override fun encode( + writer: DerWriter, + value: Long, + ) { + val string = formatGeneralizedTime(value) + return writer.writeUtf8(string) + } + }, + ) /** Decodes any value without interpretation as [AnyValue]. */ - val ANY_VALUE = object : DerAdapter { - override fun matches(header: DerHeader): Boolean = true + val ANY_VALUE = + object : DerAdapter { + override fun matches(header: DerHeader): Boolean = true - override fun fromDer(reader: DerReader): AnyValue { - reader.read("ANY") { header -> - val bytes = reader.readUnknown() - return AnyValue( + override fun fromDer(reader: DerReader): AnyValue { + reader.read("ANY") { header -> + val bytes = reader.readUnknown() + return AnyValue( tagClass = header.tagClass, tag = header.tag, constructed = header.constructed, length = header.length, - bytes = bytes - ) + bytes = bytes, + ) + } } - } - override fun toDer(writer: DerWriter, value: AnyValue) { - writer.write("ANY", value.tagClass, value.tag) { - writer.writeOctetString(value.bytes) - writer.constructed = value.constructed + override fun toDer( + writer: DerWriter, + value: AnyValue, + ) { + writer.write("ANY", value.tagClass, value.tag) { + writer.writeOctetString(value.bytes) + writer.constructed = value.constructed + } } } - } internal fun parseGeneralizedTime(string: String): Long { val utc = TimeZone.getTimeZone("GMT") - val dateFormat = SimpleDateFormat("yyyyMMddHHmmss'Z'").apply { - timeZone = utc - } + val dateFormat = + SimpleDateFormat("yyyyMMddHHmmss'Z'").apply { + timeZone = utc + } try { val parsed = dateFormat.parse(string) @@ -250,9 +329,10 @@ internal object Adapters { internal fun formatGeneralizedTime(date: Long): String { val utc = TimeZone.getTimeZone("GMT") - val dateFormat = SimpleDateFormat("yyyyMMddHHmmss'Z'").apply { - timeZone = utc - } + val dateFormat = + SimpleDateFormat("yyyyMMddHHmmss'Z'").apply { + timeZone = utc + } return dateFormat.format(date) } @@ -271,42 +351,46 @@ internal object Adapters { name: String, vararg members: DerAdapter<*>, decompose: (T) -> List<*>, - construct: (List<*>) -> T + construct: (List<*>) -> T, ): BasicDerAdapter { - val codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): T { - return reader.withTypeHint { - val list = mutableListOf() - - while (list.size < members.size) { - val member = members[list.size] - list += member.fromDer(reader) - } + val codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): T { + return reader.withTypeHint { + val list = mutableListOf() + + while (list.size < members.size) { + val member = members[list.size] + list += member.fromDer(reader) + } - if (reader.hasNext()) { - throw ProtocolException("unexpected ${reader.peekHeader()} at $reader") - } + if (reader.hasNext()) { + throw ProtocolException("unexpected ${reader.peekHeader()} at $reader") + } - return@withTypeHint construct(list) + return@withTypeHint construct(list) + } } - } - override fun encode(writer: DerWriter, value: T) { - val list = decompose(value) - writer.withTypeHint { - for (i in list.indices) { - val adapter = members[i] as DerAdapter - adapter.toDer(writer, list[i]) + override fun encode( + writer: DerWriter, + value: T, + ) { + val list = decompose(value) + writer.withTypeHint { + for (i in list.indices) { + val adapter = members[i] as DerAdapter + adapter.toDer(writer, list[i]) + } } } } - } return BasicDerAdapter( - name = name, - tagClass = DerHeader.TAG_CLASS_UNIVERSAL, - tag = 16L, - codec = codec + name = name, + tagClass = DerHeader.TAG_CLASS_UNIVERSAL, + tag = 16L, + codec = codec, ) } @@ -316,17 +400,23 @@ internal object Adapters { override fun matches(header: DerHeader): Boolean = true override fun fromDer(reader: DerReader): Pair, Any?> { - val peekedHeader = reader.peekHeader() + val peekedHeader = + reader.peekHeader() ?: throw ProtocolException("expected a value at $reader") - val choice = choices.firstOrNull { it.matches(peekedHeader) } + val choice = + choices.firstOrNull { it.matches(peekedHeader) } ?: throw ProtocolException( - "expected a matching choice but was $peekedHeader at $reader") + "expected a matching choice but was $peekedHeader at $reader", + ) return choice to choice.fromDer(reader) } - override fun toDer(writer: DerWriter, value: Pair, Any?>) { + override fun toDer( + writer: DerWriter, + value: Pair, Any?>, + ) { val (adapter, v) = value (adapter as DerAdapter).toDer(writer, v) } @@ -344,13 +434,14 @@ internal object Adapters { * * This may optionally wrap the contents in a tag. */ - fun usingTypeHint( - chooser: (Any?) -> DerAdapter<*>? - ): DerAdapter { + fun usingTypeHint(chooser: (Any?) -> DerAdapter<*>?): DerAdapter { return object : DerAdapter { override fun matches(header: DerHeader): Boolean = true - override fun toDer(writer: DerWriter, value: Any?) { + override fun toDer( + writer: DerWriter, + value: Any?, + ) { // If we don't understand this hint, encode the body as a byte string. The byte string // will include a tag and length header as a prefix. val adapter = chooser(writer.typeHint) as DerAdapter? @@ -375,7 +466,8 @@ internal object Adapters { * might be too few for values like UTF_STRING and OBJECT_IDENTIFIER that share a Kotlin class but * have very different ASN.1 interpretations. */ - private val defaultAnyChoices = listOf( + private val defaultAnyChoices = + listOf( Boolean::class to BOOLEAN, BigInteger::class to INTEGER_AS_BIG_INTEGER, BitString::class to BIT_STRING, @@ -387,18 +479,21 @@ internal object Adapters { Nothing::class to IA5_STRING, Nothing::class to UTC_TIME, Long::class to GENERALIZED_TIME, - AnyValue::class to ANY_VALUE - ) + AnyValue::class to ANY_VALUE, + ) fun any( vararg choices: Pair, DerAdapter<*>> = defaultAnyChoices.toTypedArray(), isOptional: Boolean = false, - optionalValue: Any? = null + optionalValue: Any? = null, ): DerAdapter { return object : DerAdapter { override fun matches(header: DerHeader): Boolean = true - override fun toDer(writer: DerWriter, value: Any?) { + override fun toDer( + writer: DerWriter, + value: Any?, + ) { when { isOptional && value == optionalValue -> { // Write nothing. @@ -418,7 +513,8 @@ internal object Adapters { override fun fromDer(reader: DerReader): Any? { if (isOptional && !reader.hasNext()) return optionalValue - val peekedHeader = reader.peekHeader() + val peekedHeader = + reader.peekHeader() ?: throw ProtocolException("expected a value at $reader") for ((_, adapter) in choices) { if (adapter.matches(peekedHeader)) { diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/AnyValue.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/AnyValue.kt index 08d87e5e0f0e..393946f9b5ef 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/AnyValue.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/AnyValue.kt @@ -26,7 +26,7 @@ internal data class AnyValue( var tag: Long, var constructed: Boolean = false, var length: Long = -1L, - val bytes: ByteString + val bytes: ByteString, ) { // Avoid Long.hashCode(long) which isn't available on Android 5. override fun hashCode(): Int { diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/BasicDerAdapter.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/BasicDerAdapter.kt index 6cdcd975688c..cf90b0aa369e 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/BasicDerAdapter.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/BasicDerAdapter.kt @@ -25,26 +25,19 @@ import java.net.ProtocolException */ internal data class BasicDerAdapter( private val name: String, - /** The tag class this adapter expects, or -1 to match any tag class. */ val tagClass: Int, - /** The tag this adapter expects, or -1 to match any tag. */ val tag: Long, - /** Encode and decode the value once tags are handled. */ private val codec: Codec, - /** True if the default value should be used if this value is absent during decoding. */ val isOptional: Boolean = false, - /** The value to return if this value is absent. Undefined unless this is optional. */ val defaultValue: T? = null, - /** True to set the encoded or decoded value as the type hint for the current SEQUENCE. */ - private val typeHint: Boolean = false + private val typeHint: Boolean = false, ) : DerAdapter { - init { require(tagClass >= 0) require(tag >= 0) @@ -59,9 +52,10 @@ internal data class BasicDerAdapter( throw ProtocolException("expected $this but was $peekedHeader at $reader") } - val result = reader.read(name) { - codec.decode(reader) - } + val result = + reader.read(name) { + codec.decode(reader) + } if (typeHint) { reader.typeHint = result @@ -70,7 +64,10 @@ internal data class BasicDerAdapter( return result } - override fun toDer(writer: DerWriter, value: T) { + override fun toDer( + writer: DerWriter, + value: T, + ) { if (typeHint) { writer.typeHint = value } @@ -108,7 +105,7 @@ internal data class BasicDerAdapter( */ fun withTag( tagClass: Int = DerHeader.TAG_CLASS_CONTEXT_SPECIFIC, - tag: Long + tag: Long, ): BasicDerAdapter = copy(tagClass = tagClass, tag = tag) /** Returns a copy of this adapter that doesn't encode values equal to [defaultValue]. */ @@ -138,6 +135,10 @@ internal data class BasicDerAdapter( /** Reads and writes values without knowledge of the enclosing tag, length, or defaults. */ interface Codec { fun decode(reader: DerReader): T - fun encode(writer: DerWriter, value: T) + + fun encode( + writer: DerWriter, + value: T, + ) } } diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/BitString.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/BitString.kt index f89a51640144..1fc406d9dea8 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/BitString.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/BitString.kt @@ -22,9 +22,8 @@ import okio.ByteString */ internal data class BitString( val byteString: ByteString, - /** 0-7 unused bits in the last byte. */ - val unusedBitsCount: Int + val unusedBitsCount: Int, ) { // Avoid Long.hashCode(long) which isn't available on Android 5. override fun hashCode(): Int { diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Certificate.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Certificate.kt index 36255a96197d..4e69cc7b8e94 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Certificate.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Certificate.kt @@ -29,22 +29,22 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement internal data class Certificate( val tbsCertificate: TbsCertificate, val signatureAlgorithm: AlgorithmIdentifier, - val signatureValue: BitString + val signatureValue: BitString, ) { val commonName: Any? get() { return tbsCertificate.subject - .flatten() - .firstOrNull { it.type == ObjectIdentifiers.COMMON_NAME } - ?.value + .flatten() + .firstOrNull { it.type == ObjectIdentifiers.COMMON_NAME } + ?.value } val organizationalUnitName: Any? get() { return tbsCertificate.subject - .flatten() - .firstOrNull { it.type == ObjectIdentifiers.ORGANIZATIONAL_UNIT_NAME } - ?.value + .flatten() + .firstOrNull { it.type == ObjectIdentifiers.ORGANIZATIONAL_UNIT_NAME } + ?.value } val subjectAlternativeNames: Extension? @@ -100,7 +100,7 @@ internal data class TbsCertificate( val subjectPublicKeyInfo: SubjectPublicKeyInfo, val issuerUniqueID: BitString?, val subjectUniqueID: BitString?, - val extensions: List + val extensions: List, ) { /** * Returns the standard name of this certificate's signature algorithm as specified by @@ -136,18 +136,18 @@ internal data class AlgorithmIdentifier( /** An OID string like "1.2.840.113549.1.1.11" for sha256WithRSAEncryption. */ val algorithm: String, /** Parameters of a type implied by [algorithm]. */ - val parameters: Any? + val parameters: Any?, ) internal data class AttributeTypeAndValue( /** An OID string like "2.5.4.11" for organizationalUnitName. */ val type: String, - val value: Any? + val value: Any?, ) internal data class Validity( val notBefore: Long, - val notAfter: Long + val notAfter: Long, ) { // Avoid Long.hashCode(long) which isn't available on Android 5. override fun hashCode(): Int { @@ -160,14 +160,14 @@ internal data class Validity( internal data class SubjectPublicKeyInfo( val algorithm: AlgorithmIdentifier, - val subjectPublicKey: BitString + val subjectPublicKey: BitString, ) @IgnoreJRERequirement // As of AGP 3.4.1, D8 desugars API 24 hashCode methods. internal data class Extension( val id: String, val critical: Boolean, - val value: Any? + val value: Any?, ) @IgnoreJRERequirement // As of AGP 3.4.1, D8 desugars API 24 hashCode methods. @@ -175,7 +175,7 @@ internal data class BasicConstraints( /** True if this certificate can be used as a Certificate Authority (CA). */ val ca: Boolean, /** The maximum number of intermediate CAs between this and leaf certificates. */ - val maxIntermediateCas: Long? + val maxIntermediateCas: Long?, ) /** A private key. Note that this class doesn't support attributes or an embedded public key. */ @@ -183,7 +183,7 @@ internal data class PrivateKeyInfo( // v1(0), v2(1). val version: Long, val algorithmIdentifier: AlgorithmIdentifier, - val privateKey: ByteString + val privateKey: ByteString, ) { // Avoid Long.hashCode(long) which isn't available on Android 5. override fun hashCode(): Int { diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/CertificateAdapters.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/CertificateAdapters.kt index fbd4f669f381..2573cfe10be2 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/CertificateAdapters.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/CertificateAdapters.kt @@ -40,37 +40,42 @@ internal object CertificateAdapters { * > 2049 as UTCTime; certificate validity dates in 2050 or later MUST be encoded as * > GeneralizedTime. */ - internal val time: DerAdapter = object : DerAdapter { - override fun matches(header: DerHeader): Boolean { - return Adapters.UTC_TIME.matches(header) || Adapters.GENERALIZED_TIME.matches(header) - } + internal val time: DerAdapter = + object : DerAdapter { + override fun matches(header: DerHeader): Boolean { + return Adapters.UTC_TIME.matches(header) || Adapters.GENERALIZED_TIME.matches(header) + } - override fun fromDer(reader: DerReader): Long { - val peekHeader = reader.peekHeader() - ?: throw ProtocolException("expected time but was exhausted at $reader") + override fun fromDer(reader: DerReader): Long { + val peekHeader = + reader.peekHeader() + ?: throw ProtocolException("expected time but was exhausted at $reader") - return when { - peekHeader.tagClass == Adapters.UTC_TIME.tagClass && + return when { + peekHeader.tagClass == Adapters.UTC_TIME.tagClass && peekHeader.tag == Adapters.UTC_TIME.tag -> { - Adapters.UTC_TIME.fromDer(reader) - } - peekHeader.tagClass == Adapters.GENERALIZED_TIME.tagClass && + Adapters.UTC_TIME.fromDer(reader) + } + peekHeader.tagClass == Adapters.GENERALIZED_TIME.tagClass && peekHeader.tag == Adapters.GENERALIZED_TIME.tag -> { - Adapters.GENERALIZED_TIME.fromDer(reader) + Adapters.GENERALIZED_TIME.fromDer(reader) + } + else -> throw ProtocolException("expected time but was $peekHeader at $reader") } - else -> throw ProtocolException("expected time but was $peekHeader at $reader") } - } - override fun toDer(writer: DerWriter, value: Long) { - // [1950-01-01T00:00:00..2050-01-01T00:00:00Z) - if (value in -631_152_000_000L until 2_524_608_000_000L) { - Adapters.UTC_TIME.toDer(writer, value) - } else { - Adapters.GENERALIZED_TIME.toDer(writer, value) + override fun toDer( + writer: DerWriter, + value: Long, + ) { + // [1950-01-01T00:00:00..2050-01-01T00:00:00Z) + if (value in -631_152_000_000L until 2_524_608_000_000L) { + Adapters.UTC_TIME.toDer(writer, value) + } else { + Adapters.GENERALIZED_TIME.toDer(writer, value) + } } } - } /** * ``` @@ -80,36 +85,38 @@ internal object CertificateAdapters { * } * ``` */ - private val validity: BasicDerAdapter = Adapters.sequence( + private val validity: BasicDerAdapter = + Adapters.sequence( "Validity", time, time, decompose = { listOf( - it.notBefore, - it.notAfter + it.notBefore, + it.notAfter, ) }, construct = { Validity( - notBefore = it[0] as Long, - notAfter = it[1] as Long + notBefore = it[0] as Long, + notAfter = it[1] as Long, ) - } - ) + }, + ) /** The type of the parameters depends on the algorithm that precedes it. */ - private val algorithmParameters: DerAdapter = Adapters.usingTypeHint { typeHint -> - when (typeHint) { - // This type is pretty strange. The spec says that for certain algorithms we must encode null - // when it is present, and for others we must omit it! - // https://tools.ietf.org/html/rfc4055#section-2.1 - ObjectIdentifiers.SHA256_WITH_RSA_ENCRYPTION -> Adapters.NULL - ObjectIdentifiers.RSA_ENCRYPTION -> Adapters.NULL - ObjectIdentifiers.EC_PUBLIC_KEY -> Adapters.OBJECT_IDENTIFIER - else -> null + private val algorithmParameters: DerAdapter = + Adapters.usingTypeHint { typeHint -> + when (typeHint) { + // This type is pretty strange. The spec says that for certain algorithms we must encode null + // when it is present, and for others we must omit it! + // https://tools.ietf.org/html/rfc4055#section-2.1 + ObjectIdentifiers.SHA256_WITH_RSA_ENCRYPTION -> Adapters.NULL + ObjectIdentifiers.RSA_ENCRYPTION -> Adapters.NULL + ObjectIdentifiers.EC_PUBLIC_KEY -> Adapters.OBJECT_IDENTIFIER + else -> null + } } - } /** * ``` @@ -119,23 +126,24 @@ internal object CertificateAdapters { * } * ``` */ - internal val algorithmIdentifier: BasicDerAdapter = Adapters.sequence( + internal val algorithmIdentifier: BasicDerAdapter = + Adapters.sequence( "AlgorithmIdentifier", Adapters.OBJECT_IDENTIFIER.asTypeHint(), algorithmParameters, decompose = { listOf( - it.algorithm, - it.parameters + it.algorithm, + it.parameters, ) }, construct = { AlgorithmIdentifier( - algorithm = it[0] as String, - parameters = it[1] + algorithm = it[0] as String, + parameters = it[1], ) - } - ) + }, + ) /** * ``` @@ -145,23 +153,24 @@ internal object CertificateAdapters { * } * ``` */ - private val basicConstraints: BasicDerAdapter = Adapters.sequence( + private val basicConstraints: BasicDerAdapter = + Adapters.sequence( "BasicConstraints", Adapters.BOOLEAN.optional(defaultValue = false), Adapters.INTEGER_AS_LONG.optional(), decompose = { listOf( - it.ca, - it.maxIntermediateCas + it.ca, + it.maxIntermediateCas, ) }, construct = { BasicConstraints( - ca = it[0] as Boolean, - maxIntermediateCas = it[1] as Long? + ca = it[0] as Boolean, + maxIntermediateCas = it[1] as Long?, ) - } - ) + }, + ) /** * Note that only a subset of available choices are implemented. @@ -184,11 +193,12 @@ internal object CertificateAdapters { */ internal val generalNameDnsName = Adapters.IA5_STRING.withTag(tag = 2L) internal val generalNameIpAddress = Adapters.OCTET_STRING.withTag(tag = 7L) - internal val generalName: DerAdapter, Any?>> = Adapters.choice( + internal val generalName: DerAdapter, Any?>> = + Adapters.choice( generalNameDnsName, generalNameIpAddress, - Adapters.ANY_VALUE - ) + Adapters.ANY_VALUE, + ) /** * ``` @@ -204,17 +214,18 @@ internal object CertificateAdapters { * This uses the preceding extension ID to select which adapter to use for the extension value * that follows. */ - private val extensionValue: BasicDerAdapter = Adapters.usingTypeHint { typeHint -> - when (typeHint) { - ObjectIdentifiers.SUBJECT_ALTERNATIVE_NAME -> subjectAlternativeName - ObjectIdentifiers.BASIC_CONSTRAINTS -> basicConstraints - else -> null - } - }.withExplicitBox( + private val extensionValue: BasicDerAdapter = + Adapters.usingTypeHint { typeHint -> + when (typeHint) { + ObjectIdentifiers.SUBJECT_ALTERNATIVE_NAME -> subjectAlternativeName + ObjectIdentifiers.BASIC_CONSTRAINTS -> basicConstraints + else -> null + } + }.withExplicitBox( tagClass = Adapters.OCTET_STRING.tagClass, tag = Adapters.OCTET_STRING.tag, - forceConstructed = false - ) + forceConstructed = false, + ) /** * ``` @@ -228,26 +239,27 @@ internal object CertificateAdapters { * } * ``` */ - internal val extension: BasicDerAdapter = Adapters.sequence( + internal val extension: BasicDerAdapter = + Adapters.sequence( "Extension", Adapters.OBJECT_IDENTIFIER.asTypeHint(), Adapters.BOOLEAN.optional(defaultValue = false), extensionValue, decompose = { listOf( - it.id, - it.critical, - it.value + it.id, + it.critical, + it.value, ) }, construct = { Extension( - id = it[0] as String, - critical = it[1] as Boolean, - value = it[2] + id = it[0] as String, + critical = it[1] as Boolean, + value = it[2], ) - } - ) + }, + ) /** * ``` @@ -261,27 +273,28 @@ internal object CertificateAdapters { * AttributeValue ::= ANY -- DEFINED BY AttributeType * ``` */ - private val attributeTypeAndValue: BasicDerAdapter = Adapters.sequence( + private val attributeTypeAndValue: BasicDerAdapter = + Adapters.sequence( "AttributeTypeAndValue", Adapters.OBJECT_IDENTIFIER, Adapters.any( - String::class to Adapters.UTF8_STRING, - Nothing::class to Adapters.PRINTABLE_STRING, - AnyValue::class to Adapters.ANY_VALUE + String::class to Adapters.UTF8_STRING, + Nothing::class to Adapters.PRINTABLE_STRING, + AnyValue::class to Adapters.ANY_VALUE, ), decompose = { listOf( - it.type, - it.value + it.type, + it.value, ) }, construct = { AttributeTypeAndValue( - type = it[0] as String, - value = it[1] + type = it[0] as String, + value = it[1], ) - } - ) + }, + ) /** * ``` @@ -301,9 +314,10 @@ internal object CertificateAdapters { * } * ``` */ - internal val name: DerAdapter, Any?>> = Adapters.choice( - rdnSequence - ) + internal val name: DerAdapter, Any?>> = + Adapters.choice( + rdnSequence, + ) /** * ``` @@ -313,23 +327,24 @@ internal object CertificateAdapters { * } * ``` */ - internal val subjectPublicKeyInfo: BasicDerAdapter = Adapters.sequence( + internal val subjectPublicKeyInfo: BasicDerAdapter = + Adapters.sequence( "SubjectPublicKeyInfo", algorithmIdentifier, Adapters.BIT_STRING, decompose = { listOf( - it.algorithm, - it.subjectPublicKey + it.algorithm, + it.subjectPublicKey, ) }, construct = { SubjectPublicKeyInfo( - algorithm = it[0] as AlgorithmIdentifier, - subjectPublicKey = it[1] as BitString + algorithm = it[0] as AlgorithmIdentifier, + subjectPublicKey = it[1] as BitString, ) - } - ) + }, + ) /** * ``` @@ -347,7 +362,8 @@ internal object CertificateAdapters { * } * ``` */ - internal val tbsCertificate: BasicDerAdapter = Adapters.sequence( + internal val tbsCertificate: BasicDerAdapter = + Adapters.sequence( "TBSCertificate", Adapters.INTEGER_AS_LONG .withExplicitBox(tag = 0L) @@ -364,33 +380,33 @@ internal object CertificateAdapters { extension.asSequenceOf().withExplicitBox(tag = 3).optional(defaultValue = listOf()), decompose = { listOf( - it.version, - it.serialNumber, - it.signature, - rdnSequence to it.issuer, - it.validity, - rdnSequence to it.subject, - it.subjectPublicKeyInfo, - it.issuerUniqueID, - it.subjectUniqueID, - it.extensions + it.version, + it.serialNumber, + it.signature, + rdnSequence to it.issuer, + it.validity, + rdnSequence to it.subject, + it.subjectPublicKeyInfo, + it.issuerUniqueID, + it.subjectUniqueID, + it.extensions, ) }, construct = { TbsCertificate( - version = it[0] as Long, - serialNumber = it[1] as BigInteger, - signature = it[2] as AlgorithmIdentifier, - issuer = (it[3] as Pair<*, *>).second as List>, - validity = it[4] as Validity, - subject = (it[5] as Pair<*, *>).second as List>, - subjectPublicKeyInfo = it[6] as SubjectPublicKeyInfo, - issuerUniqueID = it[7] as BitString?, - subjectUniqueID = it[8] as BitString?, - extensions = it[9] as List + version = it[0] as Long, + serialNumber = it[1] as BigInteger, + signature = it[2] as AlgorithmIdentifier, + issuer = (it[3] as Pair<*, *>).second as List>, + validity = it[4] as Validity, + subject = (it[5] as Pair<*, *>).second as List>, + subjectPublicKeyInfo = it[6] as SubjectPublicKeyInfo, + issuerUniqueID = it[7] as BitString?, + subjectUniqueID = it[8] as BitString?, + extensions = it[9] as List, ) - } - ) + }, + ) /** * ``` @@ -401,26 +417,27 @@ internal object CertificateAdapters { * } * ``` */ - internal val certificate: BasicDerAdapter = Adapters.sequence( + internal val certificate: BasicDerAdapter = + Adapters.sequence( "Certificate", tbsCertificate, algorithmIdentifier, Adapters.BIT_STRING, decompose = { listOf( - it.tbsCertificate, - it.signatureAlgorithm, - it.signatureValue + it.tbsCertificate, + it.signatureAlgorithm, + it.signatureValue, ) }, construct = { Certificate( - tbsCertificate = it[0] as TbsCertificate, - signatureAlgorithm = it[1] as AlgorithmIdentifier, - signatureValue = it[2] as BitString + tbsCertificate = it[0] as TbsCertificate, + signatureAlgorithm = it[1] as AlgorithmIdentifier, + signatureValue = it[2] as BitString, ) - } - ) + }, + ) /** * ``` @@ -443,24 +460,25 @@ internal object CertificateAdapters { * PrivateKeyInfo ::= OneAsymmetricKey * ``` */ - internal val privateKeyInfo: BasicDerAdapter = Adapters.sequence( + internal val privateKeyInfo: BasicDerAdapter = + Adapters.sequence( "PrivateKeyInfo", Adapters.INTEGER_AS_LONG, algorithmIdentifier, Adapters.OCTET_STRING, decompose = { listOf( - it.version, - it.algorithmIdentifier, - it.privateKey + it.version, + it.algorithmIdentifier, + it.privateKey, ) }, construct = { PrivateKeyInfo( - version = it[0] as Long, - algorithmIdentifier = it[1] as AlgorithmIdentifier, - privateKey = it[2] as ByteString + version = it[0] as Long, + algorithmIdentifier = it[1] as AlgorithmIdentifier, + privateKey = it[2] as ByteString, ) - } - ) + }, + ) } diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerAdapter.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerAdapter.kt index 440f52b4aadd..f1ccc1b5731d 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerAdapter.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerAdapter.kt @@ -50,7 +50,10 @@ internal interface DerAdapter { * * If this does write a value, it will write a tag and a length and a full value. */ - fun toDer(writer: DerWriter, value: T) + fun toDer( + writer: DerWriter, + value: T, + ) fun toDer(value: T): ByteString { val buffer = Buffer() @@ -77,23 +80,28 @@ internal interface DerAdapter { fun withExplicitBox( tagClass: Int = DerHeader.TAG_CLASS_CONTEXT_SPECIFIC, tag: Long, - forceConstructed: Boolean? = null + forceConstructed: Boolean? = null, ): BasicDerAdapter { - val codec = object : BasicDerAdapter.Codec { - override fun decode(reader: DerReader): T = fromDer(reader) - override fun encode(writer: DerWriter, value: T) { - toDer(writer, value) - if (forceConstructed != null) { - writer.constructed = forceConstructed + val codec = + object : BasicDerAdapter.Codec { + override fun decode(reader: DerReader): T = fromDer(reader) + + override fun encode( + writer: DerWriter, + value: T, + ) { + toDer(writer, value) + if (forceConstructed != null) { + writer.constructed = forceConstructed + } } } - } return BasicDerAdapter( - name = "EXPLICIT", - tagClass = tagClass, - tag = tag, - codec = codec + name = "EXPLICIT", + tagClass = tagClass, + tag = tag, + codec = codec, ) } @@ -101,23 +109,27 @@ internal interface DerAdapter { fun asSequenceOf( name: String = "SEQUENCE OF", tagClass: Int = DerHeader.TAG_CLASS_UNIVERSAL, - tag: Long = 16L + tag: Long = 16L, ): BasicDerAdapter> { - val codec = object : BasicDerAdapter.Codec> { - override fun encode(writer: DerWriter, value: List) { - for (v in value) { - toDer(writer, v) + val codec = + object : BasicDerAdapter.Codec> { + override fun encode( + writer: DerWriter, + value: List, + ) { + for (v in value) { + toDer(writer, v) + } } - } - override fun decode(reader: DerReader): List { - val result = mutableListOf() - while (reader.hasNext()) { - result += fromDer(reader) + override fun decode(reader: DerReader): List { + val result = mutableListOf() + while (reader.hasNext()) { + result += fromDer(reader) + } + return result } - return result } - } return BasicDerAdapter(name, tagClass, tag, codec) } @@ -125,9 +137,9 @@ internal interface DerAdapter { /** Returns an adapter that returns a set of values of this type. */ fun asSetOf(): BasicDerAdapter> { return asSequenceOf( - name = "SET OF", - tagClass = DerHeader.TAG_CLASS_UNIVERSAL, - tag = 17L + name = "SET OF", + tagClass = DerHeader.TAG_CLASS_UNIVERSAL, + tag = 17L, ) } } diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerHeader.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerHeader.kt index feec4c84c81f..8bfc76106532 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerHeader.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerHeader.kt @@ -32,10 +32,8 @@ internal data class DerHeader( * ``` */ var tagClass: Int, - /** Identifies which member in the ASN.1 schema the field holds. */ var tag: Long, - /** * If the constructed bit is set it indicates that the value is composed of other values that have * their own headers. @@ -48,9 +46,8 @@ internal data class DerHeader( * ``` */ var constructed: Boolean, - /** Length of the message in bytes, or -1L if its length is unknown at the time of encoding. */ - var length: Long + var length: Long, ) { val isEndOfData: Boolean get() = tagClass == TAG_CLASS_UNIVERSAL && tag == TAG_END_OF_CONTENTS diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerReader.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerReader.kt index b51a19dca44a..49c397aef09f 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerReader.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerReader.kt @@ -112,43 +112,45 @@ internal class DerReader(source: Source) { val tagAndClass = source.readByte().toInt() and 0xff val tagClass = tagAndClass and 0b1100_0000 val constructed = (tagAndClass and 0b0010_0000) == 0b0010_0000 - val tag = when (val tag0 = tagAndClass and 0b0001_1111) { - 0b0001_1111 -> readVariableLengthLong() - else -> tag0.toLong() - } + val tag = + when (val tag0 = tagAndClass and 0b0001_1111) { + 0b0001_1111 -> readVariableLengthLong() + else -> tag0.toLong() + } // Read the length. val length0 = source.readByte().toInt() and 0xff - val length = when { - length0 == 0b1000_0000 -> { - throw ProtocolException("indefinite length not permitted for DER") - } - (length0 and 0b1000_0000) == 0b1000_0000 -> { - // Length specified over multiple bytes. - val lengthBytes = length0 and 0b0111_1111 - if (lengthBytes > 8) { - throw ProtocolException("length encoded with more than 8 bytes is not supported") + val length = + when { + length0 == 0b1000_0000 -> { + throw ProtocolException("indefinite length not permitted for DER") } - - var lengthBits = source.readByte().toLong() and 0xff - if (lengthBits == 0L || lengthBytes == 1 && lengthBits and 0b1000_0000 == 0L) { - throw ProtocolException("invalid encoding for length") + (length0 and 0b1000_0000) == 0b1000_0000 -> { + // Length specified over multiple bytes. + val lengthBytes = length0 and 0b0111_1111 + if (lengthBytes > 8) { + throw ProtocolException("length encoded with more than 8 bytes is not supported") + } + + var lengthBits = source.readByte().toLong() and 0xff + if (lengthBits == 0L || lengthBytes == 1 && lengthBits and 0b1000_0000 == 0L) { + throw ProtocolException("invalid encoding for length") + } + + for (i in 1 until lengthBytes) { + lengthBits = lengthBits shl 8 + lengthBits += source.readByte().toInt() and 0xff + } + + if (lengthBits < 0) throw ProtocolException("length > Long.MAX_VALUE") + + lengthBits } - - for (i in 1 until lengthBytes) { - lengthBits = lengthBits shl 8 - lengthBits += source.readByte().toInt() and 0xff + else -> { + // Length is 127 or fewer bytes. + (length0 and 0b0111_1111).toLong() } - - if (lengthBits < 0) throw ProtocolException("length > Long.MAX_VALUE") - - lengthBits } - else -> { - // Length is 127 or fewer bytes. - (length0 and 0b0111_1111).toLong() - } - } // Note that this may be be an encoded "end of data" header. return DerHeader(tagClass, tag, constructed, length) @@ -158,7 +160,10 @@ internal class DerReader(source: Source) { * Consume a header and execute [block], which should consume the entire value described by the * header. It is an error to not consume a full value in [block]. */ - internal inline fun read(name: String?, block: (DerHeader) -> T): T { + internal inline fun read( + name: String?, + block: (DerHeader) -> T, + ): T { if (!hasNext()) throw ProtocolException("expected a value") val header = peekedHeader!! @@ -319,19 +324,23 @@ internal class DerReader(source: Source) { * show up in ASN.1 streams to also indicate the end of SEQUENCE, SET or other constructed * value. */ - private val END_OF_DATA = DerHeader( + private val END_OF_DATA = + DerHeader( tagClass = DerHeader.TAG_CLASS_UNIVERSAL, tag = DerHeader.TAG_END_OF_CONTENTS, constructed = false, - length = -1L - ) + length = -1L, + ) } /** A source that keeps track of how many bytes it's consumed. */ private class CountingSource(source: Source) : ForwardingSource(source) { var bytesRead = 0L - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { val result = delegate.read(sink, byteCount) if (result == -1L) return -1L bytesRead += result diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerWriter.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerWriter.kt index 7db879bfa535..375b4ca0f90d 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerWriter.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/DerWriter.kt @@ -46,7 +46,12 @@ internal class DerWriter(sink: BufferedSink) { */ var constructed = false - fun write(name: String, tagClass: Int, tag: Long, block: (BufferedSink) -> Unit) { + fun write( + name: String, + tagClass: Int, + tag: Long, + block: (BufferedSink) -> Unit, + ) { val constructedBit: Int val content = Buffer() @@ -118,11 +123,12 @@ internal class DerWriter(sink: BufferedSink) { fun writeLong(v: Long) { val sink = sink() - val lengthBitCount: Int = if (v < 0L) { - 65 - java.lang.Long.numberOfLeadingZeros(v xor -1L) - } else { - 65 - java.lang.Long.numberOfLeadingZeros(v) - } + val lengthBitCount: Int = + if (v < 0L) { + 65 - java.lang.Long.numberOfLeadingZeros(v xor -1L) + } else { + 65 - java.lang.Long.numberOfLeadingZeros(v) + } val lengthByteCount = (lengthBitCount + 7) / 8 for (shift in (lengthByteCount - 1) * 8 downTo 0 step 8) { @@ -160,7 +166,8 @@ internal class DerWriter(sink: BufferedSink) { fun writeRelativeObjectIdentifier(s: String) { // Add a leading dot so each subidentifier has a dot prefix. - val utf8 = Buffer() + val utf8 = + Buffer() .writeByte('.'.code.toByte().toInt()) .writeUtf8(s) diff --git a/okhttp-tls/src/test/java/okhttp3/tls/CertificatesTest.kt b/okhttp-tls/src/test/java/okhttp3/tls/CertificatesTest.kt index e6f2078cb3d6..b0dfe4fe368c 100644 --- a/okhttp-tls/src/test/java/okhttp3/tls/CertificatesTest.kt +++ b/okhttp-tls/src/test/java/okhttp3/tls/CertificatesTest.kt @@ -20,7 +20,8 @@ import org.junit.jupiter.api.Test class CertificatesTest { @Test fun testRoundtrip() { - val certificateString = """ + val certificateString = + """ -----BEGIN CERTIFICATE----- MIIBmjCCAQOgAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhjYXNo LmFwcDAeFw03MDAxMDEwMDAwMDBaFw03MDAxMDEwMDAwMDFaMBMxETAPBgNVBAMT diff --git a/okhttp-tls/src/test/java/okhttp3/tls/HandshakeCertificatesTest.kt b/okhttp-tls/src/test/java/okhttp3/tls/HandshakeCertificatesTest.kt index e2479d924994..26f4146aa6ce 100644 --- a/okhttp-tls/src/test/java/okhttp3/tls/HandshakeCertificatesTest.kt +++ b/okhttp-tls/src/test/java/okhttp3/tls/HandshakeCertificatesTest.kt @@ -59,34 +59,42 @@ class HandshakeCertificatesTest { platform.assumeNotConscrypt() platform.assumeNotBouncyCastle() - val clientRoot = HeldCertificate.Builder() - .certificateAuthority(1) - .build() - val clientIntermediate = HeldCertificate.Builder() - .certificateAuthority(0) - .signedBy(clientRoot) - .build() - val clientCertificate = HeldCertificate.Builder() - .signedBy(clientIntermediate) - .build() - val serverRoot = HeldCertificate.Builder() - .certificateAuthority(1) - .build() - val serverIntermediate = HeldCertificate.Builder() - .certificateAuthority(0) - .signedBy(serverRoot) - .build() - val serverCertificate = HeldCertificate.Builder() - .signedBy(serverIntermediate) - .build() - val server = HandshakeCertificates.Builder() - .addTrustedCertificate(clientRoot.certificate) - .heldCertificate(serverCertificate, serverIntermediate.certificate) - .build() - val client = HandshakeCertificates.Builder() - .addTrustedCertificate(serverRoot.certificate) - .heldCertificate(clientCertificate, clientIntermediate.certificate) - .build() + val clientRoot = + HeldCertificate.Builder() + .certificateAuthority(1) + .build() + val clientIntermediate = + HeldCertificate.Builder() + .certificateAuthority(0) + .signedBy(clientRoot) + .build() + val clientCertificate = + HeldCertificate.Builder() + .signedBy(clientIntermediate) + .build() + val serverRoot = + HeldCertificate.Builder() + .certificateAuthority(1) + .build() + val serverIntermediate = + HeldCertificate.Builder() + .certificateAuthority(0) + .signedBy(serverRoot) + .build() + val serverCertificate = + HeldCertificate.Builder() + .signedBy(serverIntermediate) + .build() + val server = + HandshakeCertificates.Builder() + .addTrustedCertificate(clientRoot.certificate) + .heldCertificate(serverCertificate, serverIntermediate.certificate) + .build() + val client = + HandshakeCertificates.Builder() + .addTrustedCertificate(serverRoot.certificate) + .heldCertificate(clientCertificate, clientIntermediate.certificate) + .build() val serverAddress = startTlsServer() val serverHandshakeFuture = doServerHandshake(server) val clientHandshakeFuture = doClientHandshake(client, serverAddress) @@ -103,36 +111,42 @@ class HandshakeCertificatesTest { } @Test fun keyManager() { - val root = HeldCertificate.Builder() - .certificateAuthority(1) - .build() - val intermediate = HeldCertificate.Builder() - .certificateAuthority(0) - .signedBy(root) - .build() - val certificate = HeldCertificate.Builder() - .signedBy(intermediate) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(root.certificate) // BouncyCastle requires at least one - .heldCertificate(certificate, intermediate.certificate) - .build() + val root = + HeldCertificate.Builder() + .certificateAuthority(1) + .build() + val intermediate = + HeldCertificate.Builder() + .certificateAuthority(0) + .signedBy(root) + .build() + val certificate = + HeldCertificate.Builder() + .signedBy(intermediate) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(root.certificate) // BouncyCastle requires at least one + .heldCertificate(certificate, intermediate.certificate) + .build() assertPrivateKeysEquals( certificate.keyPair.private, - handshakeCertificates.keyManager.getPrivateKey("private") + handshakeCertificates.keyManager.getPrivateKey("private"), ) assertThat(handshakeCertificates.keyManager.getCertificateChain("private").toList()) .isEqualTo(listOf(certificate.certificate, intermediate.certificate)) } @Test fun platformTrustedCertificates() { - val handshakeCertificates = HandshakeCertificates.Builder() - .addPlatformTrustedCertificates() - .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addPlatformTrustedCertificates() + .build() val acceptedIssuers = handshakeCertificates.trustManager.acceptedIssuers - val names = acceptedIssuers - .map { it.subjectDN.name } - .toSet() + val names = + acceptedIssuers + .map { it.subjectDN.name } + .toSet() // It's safe to assume all platforms will have a major Internet certificate issuer. assertThat(names).matchesPredicate { strings -> @@ -151,12 +165,13 @@ class HandshakeCertificatesTest { private fun doServerHandshake(server: HandshakeCertificates): Future { return executorService.submit { serverSocket!!.accept().use { rawSocket -> - val sslSocket = server.sslSocketFactory().createSocket( - rawSocket, - rawSocket.inetAddress.hostAddress, - rawSocket.port, - true - ) as SSLSocket + val sslSocket = + server.sslSocketFactory().createSocket( + rawSocket, + rawSocket.inetAddress.hostAddress, + rawSocket.port, + true, + ) as SSLSocket sslSocket.use { sslSocket.useClientMode = false sslSocket.wantClientAuth = true @@ -168,17 +183,19 @@ class HandshakeCertificatesTest { } private fun doClientHandshake( - client: HandshakeCertificates, serverAddress: InetSocketAddress + client: HandshakeCertificates, + serverAddress: InetSocketAddress, ): Future { return executorService.submit { SocketFactory.getDefault().createSocket().use { rawSocket -> rawSocket.connect(serverAddress) - val sslSocket = client.sslSocketFactory().createSocket( - rawSocket, - rawSocket.inetAddress.hostAddress, - rawSocket.port, - true - ) as SSLSocket + val sslSocket = + client.sslSocketFactory().createSocket( + rawSocket, + rawSocket.inetAddress.hostAddress, + rawSocket.port, + true, + ) as SSLSocket sslSocket.use { sslSocket.startHandshake() return@submit sslSocket.session.handshake() @@ -187,7 +204,10 @@ class HandshakeCertificatesTest { } } - private fun assertPrivateKeysEquals(expected: PrivateKey, actual: PrivateKey) { + private fun assertPrivateKeysEquals( + expected: PrivateKey, + actual: PrivateKey, + ) { assertThat(actual.encoded.toByteString()).isEqualTo(expected.encoded.toByteString()) } } diff --git a/okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.kt b/okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.kt index 55c7a458f00a..b17f800daf8a 100644 --- a/okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.kt +++ b/okhttp-tls/src/test/java/okhttp3/tls/HeldCertificateTest.kt @@ -59,9 +59,10 @@ class HeldCertificateTest { @Test fun customInterval() { // 5 seconds starting on 1970-01-01. - val heldCertificate = HeldCertificate.Builder() - .validityInterval(5000L, 10000L) - .build() + val heldCertificate = + HeldCertificate.Builder() + .validityInterval(5000L, 10000L) + .build() val certificate = heldCertificate.certificate assertThat(certificate.notBefore.time).isEqualTo(5000L) assertThat(certificate.notAfter.time).isEqualTo(10000L) @@ -70,9 +71,10 @@ class HeldCertificateTest { @Test fun customDuration() { val now = System.currentTimeMillis() - val heldCertificate = HeldCertificate.Builder() - .duration(5, TimeUnit.SECONDS) - .build() + val heldCertificate = + HeldCertificate.Builder() + .duration(5, TimeUnit.SECONDS) + .build() val certificate = heldCertificate.certificate val deltaMillis = 1000.0 val durationMillis = 5000L @@ -84,35 +86,38 @@ class HeldCertificateTest { @Test fun subjectAlternativeNames() { - val heldCertificate = HeldCertificate.Builder() - .addSubjectAlternativeName("1.1.1.1") - .addSubjectAlternativeName("cash.app") - .build() + val heldCertificate = + HeldCertificate.Builder() + .addSubjectAlternativeName("1.1.1.1") + .addSubjectAlternativeName("cash.app") + .build() val certificate = heldCertificate.certificate assertThat(certificate.subjectAlternativeNames.toList()).containsExactly( listOf(GeneralName.iPAddress, "1.1.1.1"), - listOf(GeneralName.dNSName, "cash.app") + listOf(GeneralName.dNSName, "cash.app"), ) } @Test fun commonName() { - val heldCertificate = HeldCertificate.Builder() - .commonName("cash.app") - .build() + val heldCertificate = + HeldCertificate.Builder() + .commonName("cash.app") + .build() val certificate = heldCertificate.certificate assertThat(certificate.getSubjectX500Principal().name).isEqualTo("CN=cash.app") } @Test fun organizationalUnit() { - val heldCertificate = HeldCertificate.Builder() - .commonName("cash.app") - .organizationalUnit("cash") - .build() + val heldCertificate = + HeldCertificate.Builder() + .commonName("cash.app") + .organizationalUnit("cash") + .build() val certificate = heldCertificate.certificate assertThat(certificate.getSubjectX500Principal().name).isEqualTo( - "CN=cash.app,OU=cash" + "CN=cash.app,OU=cash", ) } @@ -120,32 +125,41 @@ class HeldCertificateTest { @Test fun pems() { val keyFactory = KeyFactory.getInstance("RSA") - val publicKeyBytes = ("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCApFHhtrLan28q+oMolZuaTfWBA0V5aM" + - "Ivq32BsloQu6LlvX1wJ4YEoUCjDlPOtpht7XLbUmBnbIzN89XK4UJVM6Sqp3K88Km8z7gMrdrfTom/274wL25fICR+" + - "yDEQ5fUVYBmJAKXZF1aoI0mIoEx0xFsQhIJ637v2MxJDupd61wIDAQAB") - .decodeBase64()!! - val publicKey = keyFactory.generatePublic( - X509EncodedKeySpec(publicKeyBytes.toByteArray()) - ) - val privateKeyBytes = ("MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAICkUeG2stqfbyr6gyiVm" + - "5pN9YEDRXlowi+rfYGyWhC7ouW9fXAnhgShQKMOU862mG3tcttSYGdsjM3z1crhQlUzpKqncrzwqbzPuAyt2t9Oib/" + - "bvjAvbl8gJH7IMRDl9RVgGYkApdkXVqgjSYigTHTEWxCEgnrfu/YzEkO6l3rXAgMBAAECgYB99mhnB6piADOuddXv6" + - "26NzUBTr4xbsYRTgSxHzwf50oFTTBSDuW+1IOBVyTWu94SSPyt0LllPbC8Di3sQSTnVGpSqAvEXknBMzIc0UO74Rn9" + - "p3gZjEenPt1l77fIBa2nK06/rdsJCoE/1P1JSfM9w7LU1RsTmseYMLeJl5F79gQJBAO/BbAKqg1yzK7VijygvBoUrr" + - "+rt2lbmKgcUQ/rxu8IIQk0M/xgJqSkXDXuOnboGM7sQSKfJAZUtT7xozvLzV7ECQQCJW59w7NIM0qZ/gIX2gcNZr1B" + - "/V3zcGlolTDciRm+fnKGNt2EEDKnVL3swzbEfTCa48IT0QKgZJqpXZERa26UHAkBLXmiP5f5pk8F3wcXzAeVw06z3k" + - "1IB41Tu6MX+CyPU+TeudRlz+wV8b0zDvK+EnRKCCbptVFj1Bkt8lQ4JfcnhAkAk2Y3Gz+HySrkcT7Cg12M/NkdUQnZ" + - "e3jr88pt/+IGNwomc6Wt/mJ4fcWONTkGMcfOZff1NQeNXDAZ6941XCsIVAkASOg02PlVHLidU7mIE65swMM5/RNhS4" + - "aFjez/MwxFNOHaxc9VgCwYPXCLOtdf7AVovdyG0XWgbUXH+NyxKwboE").decodeBase64()!! - val privateKey = keyFactory.generatePrivate( - PKCS8EncodedKeySpec(privateKeyBytes.toByteArray()) - ) - val heldCertificate = HeldCertificate.Builder() - .keyPair(publicKey, privateKey) - .commonName("cash.app") - .validityInterval(0L, 1000L) - .rsa2048() - .build() + val publicKeyBytes = + ( + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCApFHhtrLan28q+oMolZuaTfWBA0V5aM" + + "Ivq32BsloQu6LlvX1wJ4YEoUCjDlPOtpht7XLbUmBnbIzN89XK4UJVM6Sqp3K88Km8z7gMrdrfTom/274wL25fICR+" + + "yDEQ5fUVYBmJAKXZF1aoI0mIoEx0xFsQhIJ637v2MxJDupd61wIDAQAB" + ) + .decodeBase64()!! + val publicKey = + keyFactory.generatePublic( + X509EncodedKeySpec(publicKeyBytes.toByteArray()), + ) + val privateKeyBytes = + ( + "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAICkUeG2stqfbyr6gyiVm" + + "5pN9YEDRXlowi+rfYGyWhC7ouW9fXAnhgShQKMOU862mG3tcttSYGdsjM3z1crhQlUzpKqncrzwqbzPuAyt2t9Oib/" + + "bvjAvbl8gJH7IMRDl9RVgGYkApdkXVqgjSYigTHTEWxCEgnrfu/YzEkO6l3rXAgMBAAECgYB99mhnB6piADOuddXv6" + + "26NzUBTr4xbsYRTgSxHzwf50oFTTBSDuW+1IOBVyTWu94SSPyt0LllPbC8Di3sQSTnVGpSqAvEXknBMzIc0UO74Rn9" + + "p3gZjEenPt1l77fIBa2nK06/rdsJCoE/1P1JSfM9w7LU1RsTmseYMLeJl5F79gQJBAO/BbAKqg1yzK7VijygvBoUrr" + + "+rt2lbmKgcUQ/rxu8IIQk0M/xgJqSkXDXuOnboGM7sQSKfJAZUtT7xozvLzV7ECQQCJW59w7NIM0qZ/gIX2gcNZr1B" + + "/V3zcGlolTDciRm+fnKGNt2EEDKnVL3swzbEfTCa48IT0QKgZJqpXZERa26UHAkBLXmiP5f5pk8F3wcXzAeVw06z3k" + + "1IB41Tu6MX+CyPU+TeudRlz+wV8b0zDvK+EnRKCCbptVFj1Bkt8lQ4JfcnhAkAk2Y3Gz+HySrkcT7Cg12M/NkdUQnZ" + + "e3jr88pt/+IGNwomc6Wt/mJ4fcWONTkGMcfOZff1NQeNXDAZ6941XCsIVAkASOg02PlVHLidU7mIE65swMM5/RNhS4" + + "aFjez/MwxFNOHaxc9VgCwYPXCLOtdf7AVovdyG0XWgbUXH+NyxKwboE" + ).decodeBase64()!! + val privateKey = + keyFactory.generatePrivate( + PKCS8EncodedKeySpec(privateKeyBytes.toByteArray()), + ) + val heldCertificate = + HeldCertificate.Builder() + .keyPair(publicKey, privateKey) + .commonName("cash.app") + .validityInterval(0L, 1000L) + .rsa2048() + .build() assertThat( """ |-----BEGIN CERTIFICATE----- @@ -159,7 +173,8 @@ class HeldCertificateTest { |+OEfl3zhm0PUqcbckMzhJtqIa7NkDSjNm71BKd843pIhGcEri69DcL/cR8T+eMex |hadh7aGM9OjeL8gznLeq27Ly6Dj7Vkp5OmOrSKfn |-----END CERTIFICATE----- - |""".trimMargin() + | + """.trimMargin(), ).isEqualTo(heldCertificate.certificatePem()) assertThat( """ @@ -178,7 +193,8 @@ class HeldCertificateTest { |TUHjVwwGeveNVwrCFQJAEjoNNj5VRy4nVO5iBOubMDDOf0TYUuGhY3s/zMMRTTh2 |sXPVYAsGD1wizrXX+wFaL3chtF1oG1Fx/jcsSsG6BA== |-----END RSA PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin(), ).isEqualTo(heldCertificate.privateKeyPkcs1Pem()) assertThat( """ @@ -198,36 +214,41 @@ class HeldCertificateTest { |LidU7mIE65swMM5/RNhS4aFjez/MwxFNOHaxc9VgCwYPXCLOtdf7AVovdyG0XWgb |UXH+NyxKwboE |-----END PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin(), ).isEqualTo(heldCertificate.privateKeyPkcs8Pem()) } @Test fun ecdsaSignedByRsa() { - val root = HeldCertificate.Builder() - .certificateAuthority(0) - .rsa2048() - .build() - val leaf = HeldCertificate.Builder() - .certificateAuthority(0) - .ecdsa256() - .signedBy(root) - .build() + val root = + HeldCertificate.Builder() + .certificateAuthority(0) + .rsa2048() + .build() + val leaf = + HeldCertificate.Builder() + .certificateAuthority(0) + .ecdsa256() + .signedBy(root) + .build() assertThat(root.certificate.sigAlgName).isEqualTo("SHA256WITHRSA", ignoreCase = true) assertThat(leaf.certificate.sigAlgName).isEqualTo("SHA256WITHRSA", ignoreCase = true) } @Test fun rsaSignedByEcdsa() { - val root = HeldCertificate.Builder() - .certificateAuthority(0) - .ecdsa256() - .build() - val leaf = HeldCertificate.Builder() - .certificateAuthority(0) - .rsa2048() - .signedBy(root) - .build() + val root = + HeldCertificate.Builder() + .certificateAuthority(0) + .ecdsa256() + .build() + val leaf = + HeldCertificate.Builder() + .certificateAuthority(0) + .rsa2048() + .signedBy(root) + .build() assertThat(root.certificate.sigAlgName).isEqualTo("SHA256WITHECDSA", ignoreCase = true) assertThat(leaf.certificate.sigAlgName).isEqualTo("SHA256WITHECDSA", ignoreCase = true) } @@ -245,7 +266,8 @@ class HeldCertificateTest { // .organizationalUnit("engineering") // .ecdsa256() // .build(); - val certificatePem = """ + val certificatePem = + """ |-----BEGIN CERTIFICATE----- |MIIBYTCCAQegAwIBAgIBKjAKBggqhkjOPQQDAjApMRQwEgYDVQQLEwtlbmdpbmVl |cmluZzERMA8GA1UEAxMIY2FzaC5hcHAwHhcNNzAwMTAxMDAwMDA1WhcNNzAwMTAx @@ -256,19 +278,24 @@ class HeldCertificateTest { |AiAyHHg1N6YDDQiY920+cnI5XSZwEGhAtb9PYWO8bLmkcQIhAI2CfEZf3V/obmdT |yyaoEufLKVXhrTQhRfodTeigi4RX |-----END CERTIFICATE----- - |""".trimMargin() - val pkcs8Pem = """ + | + """.trimMargin() + val pkcs8Pem = + """ |-----BEGIN PRIVATE KEY----- |MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCA7ODT0xhGSNn4ESj6J |lu/GJQZoU9lDrCPeUcQ28tzOWw== |-----END PRIVATE KEY----- - |""".trimMargin() - val bcPkcs8Pem = """ + | + """.trimMargin() + val bcPkcs8Pem = + """ |-----BEGIN PRIVATE KEY----- |ME0CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEMzAxAgEBBCA7ODT0xhGSNn4ESj6J |lu/GJQZoU9lDrCPeUcQ28tzOW6AKBggqhkjOPQMBBw== |-----END PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin() val heldCertificate = decode(certificatePem + pkcs8Pem) assertThat(heldCertificate.certificatePem()).isEqualTo(certificatePem) @@ -283,7 +310,7 @@ class HeldCertificateTest { assertThat(certificate.notAfter.time).isEqualTo(10000L) assertThat(certificate.subjectAlternativeNames.toList()).containsExactly( listOf(GeneralName.iPAddress, "1.1.1.1"), - listOf(GeneralName.dNSName, "cash.app") + listOf(GeneralName.dNSName, "cash.app"), ) assertThat(certificate.getSubjectX500Principal().name) .isEqualTo("CN=cash.app,OU=engineering") @@ -302,7 +329,8 @@ class HeldCertificateTest { // -newkey rsa:512 \ // -keyout privateKey.key \ // -out certificate.crt - val certificatePem = """ + val certificatePem = + """ |-----BEGIN CERTIFICATE----- |MIIBFzCBwgIJAIVAqagcVN7/MA0GCSqGSIb3DQEBBAUAMBMxETAPBgNVBAMMCGNh |c2guYXBwMB4XDTE5MDkwNzAyMjg0NFoXDTE5MDkwODAyMjg0NFowEzERMA8GA1UE @@ -311,8 +339,10 @@ class HeldCertificateTest { |zIdrLQIDAQABMA0GCSqGSIb3DQEBBAUAA0EAO1UpwhrkW3Ho1nZK/taoUQOoqz/n |HFVMtyEkm5gBDgz8nJXwb3zbegclQyH+kVou02S8zC5WWzEtd0R8S0LsTA== |-----END CERTIFICATE----- - |""".trimMargin() - val pkcs8Pem = """ + | + """.trimMargin() + val pkcs8Pem = + """ |-----BEGIN PRIVATE KEY----- |MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA8qAeoubm4mBTD9/J |ujLQkfk/fuJt/T5pVQ1vUEqxfcMw0zYgszQ5C2MiIl7M6JkTRKU01q9hVFCR83wX @@ -323,7 +353,8 @@ class HeldCertificateTest { |DK/S8UkjYY/tIq4nVRJsD+LvlkLrwnkCIECcz4yF4HQgv+Tbzj/gGSBl1VIliTcB |Rc5RUQ0mZJQF |-----END PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin() val heldCertificate = decode(pkcs8Pem + certificatePem) assertThat(heldCertificate.certificatePem()).isEqualTo(certificatePem) assertThat(heldCertificate.privateKeyPkcs8Pem()).isEqualTo(pkcs8Pem) @@ -345,7 +376,8 @@ class HeldCertificateTest { // .organizationalUnit("engineering") // .rsa2048() // .build(); - val certificatePem = """ + val certificatePem = + """ |-----BEGIN CERTIFICATE----- |MIIC7TCCAdWgAwIBAgIBKjANBgkqhkiG9w0BAQsFADApMRQwEgYDVQQLEwtlbmdp |bmVlcmluZzERMA8GA1UEAxMIY2FzaC5hcHAwHhcNNzAwMTAxMDAwMDA1WhcNNzAw @@ -364,8 +396,10 @@ class HeldCertificateTest { |sZQW31gO2arPmfNotkQdFdNL12c9YZKkJGhyK6NcpffD2l6O9NS5SRD5RnkvBxQw |fX5DamL8je/YKSLQ4wgUA/5iVKlCiJGQi6fYIJ0kxayO |-----END CERTIFICATE----- - |""".trimMargin() - val pkcs8Pem = """ + | + """.trimMargin() + val pkcs8Pem = + """ |-----BEGIN PRIVATE KEY----- |MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCaU+vrUPL0APGI |SXIuRX4xRrigXmGKx+GRPnWDWvGJwOm23Vpq/eZxQx6PbSUB1+QZzAwge20RpNAp @@ -394,7 +428,8 @@ class HeldCertificateTest { |+dMHl5I/urMesjKKWiKZHdbWVIjJDv25r3jrN9VLr4q6AD9r1Su5G0o2j0N5ujVg |SzpFHp+ZzhL/SANa8EqlcF6ItQ== |-----END PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin() val heldCertificate = decode(pkcs8Pem + certificatePem) assertThat(heldCertificate.certificatePem()).isEqualTo(certificatePem) assertThat(heldCertificate.privateKeyPkcs8Pem()).isEqualTo(pkcs8Pem) @@ -403,7 +438,7 @@ class HeldCertificateTest { assertThat(certificate.notAfter.time).isEqualTo(10000L) assertThat(certificate.subjectAlternativeNames.toList()).containsExactly( listOf(GeneralName.iPAddress, "1.1.1.1"), - listOf(GeneralName.dNSName, "cash.app") + listOf(GeneralName.dNSName, "cash.app"), ) assertThat(certificate.getSubjectX500Principal().name) .isEqualTo("CN=cash.app,OU=engineering") @@ -411,7 +446,8 @@ class HeldCertificateTest { @Test fun decodeWrongNumber() { - val certificatePem = """ + val certificatePem = + """ |-----BEGIN CERTIFICATE----- |MIIBYTCCAQegAwIBAgIBKjAKBggqhkjOPQQDAjApMRQwEgYDVQQLEwtlbmdpbmVl |cmluZzERMA8GA1UEAxMIY2FzaC5hcHAwHhcNNzAwMTAxMDAwMDA1WhcNNzAwMTAx @@ -422,13 +458,16 @@ class HeldCertificateTest { |AiAyHHg1N6YDDQiY920+cnI5XSZwEGhAtb9PYWO8bLmkcQIhAI2CfEZf3V/obmdT |yyaoEufLKVXhrTQhRfodTeigi4RX |-----END CERTIFICATE----- - |""".trimMargin() - val pkcs8Pem = """ + | + """.trimMargin() + val pkcs8Pem = + """ |-----BEGIN PRIVATE KEY----- |MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCA7ODT0xhGSNn4ESj6J |lu/GJQZoU9lDrCPeUcQ28tzOWw== |-----END PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin() try { decode(certificatePem) fail() @@ -466,7 +505,8 @@ class HeldCertificateTest { |-----BEGIN RSA PRIVATE KEY----- |sXPVYAsGD1wizrXX+wFaL3chtF1oG1Fx/jcsSsG6BA== |-----END RSA PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin(), ) fail() } catch (expected: IllegalArgumentException) { @@ -486,7 +526,8 @@ class HeldCertificateTest { |MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCA7ODT0xhGSNn4ESj6J |lu/GJQZoU9lDrCPeUcQ28tzOWw== |-----END PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin(), ) fail() } catch (expected: IllegalArgumentException) { @@ -510,7 +551,8 @@ class HeldCertificateTest { |-----BEGIN PRIVATE KEY----- |MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCA7ODT0xhGSNn4ESj6J |-----END PRIVATE KEY----- - |""".trimMargin() + | + """.trimMargin(), ) fail() } catch (expected: IllegalArgumentException) { diff --git a/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerCertificatesTest.kt b/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerCertificatesTest.kt index c4e0cce03dfe..221280684dec 100644 --- a/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerCertificatesTest.kt +++ b/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerCertificatesTest.kt @@ -63,578 +63,668 @@ internal class DerCertificatesTest { @Test fun `decode simple certificate`() { - val certificateBase64 = """ - |MIIBmjCCAQOgAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhjYXNo - |LmFwcDAeFw03MDAxMDEwMDAwMDBaFw03MDAxMDEwMDAwMDFaMBMxETAPBgNVBAMT - |CGNhc2guYXBwMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCApFHhtrLan28q - |+oMolZuaTfWBA0V5aMIvq32BsloQu6LlvX1wJ4YEoUCjDlPOtpht7XLbUmBnbIzN - |89XK4UJVM6Sqp3K88Km8z7gMrdrfTom/274wL25fICR+yDEQ5fUVYBmJAKXZF1ao - |I0mIoEx0xFsQhIJ637v2MxJDupd61wIDAQABMA0GCSqGSIb3DQEBCwUAA4GBADam - |UVwKh5Ry7es3OxtY3IgQunPUoLc0Gw71gl9Z+7t2FJ5VkcI5gWfutmdxZ2bDXCI8 - |8V0vxo1pHXnbBrnxhS/Z3TBerw8RyQqcaWOdp+pBXyIWmR+jHk9cHZCqQveTIBsY - |jaA9VEhgdaVhxBsT2qzUNDsXlOzGsliznDfoqETb - |""".trimMargin() + val certificateBase64 = + """ + |MIIBmjCCAQOgAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhjYXNo + |LmFwcDAeFw03MDAxMDEwMDAwMDBaFw03MDAxMDEwMDAwMDFaMBMxETAPBgNVBAMT + |CGNhc2guYXBwMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCApFHhtrLan28q + |+oMolZuaTfWBA0V5aMIvq32BsloQu6LlvX1wJ4YEoUCjDlPOtpht7XLbUmBnbIzN + |89XK4UJVM6Sqp3K88Km8z7gMrdrfTom/274wL25fICR+yDEQ5fUVYBmJAKXZF1ao + |I0mIoEx0xFsQhIJ637v2MxJDupd61wIDAQABMA0GCSqGSIb3DQEBCwUAA4GBADam + |UVwKh5Ry7es3OxtY3IgQunPUoLc0Gw71gl9Z+7t2FJ5VkcI5gWfutmdxZ2bDXCI8 + |8V0vxo1pHXnbBrnxhS/Z3TBerw8RyQqcaWOdp+pBXyIWmR+jHk9cHZCqQveTIBsY + |jaA9VEhgdaVhxBsT2qzUNDsXlOzGsliznDfoqETb + | + """.trimMargin() val certificateByteString = certificateBase64.decodeBase64()!! - val certificatePem = """ - |-----BEGIN CERTIFICATE----- - |$certificateBase64 - |-----END CERTIFICATE----- - |""".trimMargin() + val certificatePem = + """ + |-----BEGIN CERTIFICATE----- + |$certificateBase64 + |-----END CERTIFICATE----- + | + """.trimMargin() val javaCertificate = certificatePem.decodeCertificatePem() - val okHttpCertificate = CertificateAdapters.certificate + val okHttpCertificate = + CertificateAdapters.certificate .fromDer(certificateByteString) assertThat(okHttpCertificate.signatureValue.byteString) - .isEqualTo(javaCertificate.signature.toByteString()) - - val publicKeyBytes = ("3081890281810080a451e1b6b2da9f6f2afa8328959b9a4df58103457968c22fab7d81" + - "b25a10bba2e5bd7d70278604a140a30e53ceb6986ded72db5260676c8ccdf3d5cae1425533a4aaa772bcf0a9" + - "bccfb80caddadf4e89bfdbbe302f6e5f20247ec83110e5f51560198900a5d91756a8234988a04c74c45b1084" + - "827adfbbf6331243ba977ad70203010001").decodeHex() - val signatureBytes = ("36a6515c0a879472edeb373b1b58dc8810ba73d4a0b7341b0ef5825f59fbbb76149e55" + - "91c2398167eeb667716766c35c223cf15d2fc68d691d79db06b9f1852fd9dd305eaf0f11c90a9c69639da7ea" + - "415f2216991fa31e4f5c1d90aa42f793201b188da03d54486075a561c41b13daacd4343b1794ecc6b258b39c" + - "37e8a844db").decodeHex() + .isEqualTo(javaCertificate.signature.toByteString()) + + val publicKeyBytes = + ( + "3081890281810080a451e1b6b2da9f6f2afa8328959b9a4df58103457968c22fab7d81" + + "b25a10bba2e5bd7d70278604a140a30e53ceb6986ded72db5260676c8ccdf3d5cae1425533a4aaa772bcf0a9" + + "bccfb80caddadf4e89bfdbbe302f6e5f20247ec83110e5f51560198900a5d91756a8234988a04c74c45b1084" + + "827adfbbf6331243ba977ad70203010001" + ).decodeHex() + val signatureBytes = + ( + "36a6515c0a879472edeb373b1b58dc8810ba73d4a0b7341b0ef5825f59fbbb76149e55" + + "91c2398167eeb667716766c35c223cf15d2fc68d691d79db06b9f1852fd9dd305eaf0f11c90a9c69639da7ea" + + "415f2216991fa31e4f5c1d90aa42f793201b188da03d54486075a561c41b13daacd4343b1794ecc6b258b39c" + + "37e8a844db" + ).decodeHex() assertThat(okHttpCertificate).isEqualTo( - Certificate( - tbsCertificate = TbsCertificate( - // v3. - version = 2L, - serialNumber = BigInteger.ONE, - signature = AlgorithmIdentifier( - algorithm = SHA256_WITH_RSA_ENCRYPTION, - parameters = null - ), - issuer = listOf( - listOf( - AttributeTypeAndValue( - type = COMMON_NAME, - value = "cash.app" - ) - ) - ), - validity = Validity( - notBefore = 0L, - notAfter = 1000L + Certificate( + tbsCertificate = + TbsCertificate( + // v3. + version = 2L, + serialNumber = BigInteger.ONE, + signature = + AlgorithmIdentifier( + algorithm = SHA256_WITH_RSA_ENCRYPTION, + parameters = null, + ), + issuer = + listOf( + listOf( + AttributeTypeAndValue( + type = COMMON_NAME, + value = "cash.app", + ), ), - subject = listOf( - listOf( - AttributeTypeAndValue( - type = COMMON_NAME, - value = "cash.app" - ) - ) + ), + validity = + Validity( + notBefore = 0L, + notAfter = 1000L, + ), + subject = + listOf( + listOf( + AttributeTypeAndValue( + type = COMMON_NAME, + value = "cash.app", + ), ), - subjectPublicKeyInfo = SubjectPublicKeyInfo( - algorithm = AlgorithmIdentifier( - algorithm = RSA_ENCRYPTION, - parameters = null - ), - subjectPublicKey = BitString( - byteString = publicKeyBytes, - unusedBitsCount = 0 - ) - ), - issuerUniqueID = null, - subjectUniqueID = null, - extensions = listOf() - ), - signatureAlgorithm = AlgorithmIdentifier( - algorithm = SHA256_WITH_RSA_ENCRYPTION, - parameters = null - ), - signatureValue = BitString( - byteString = signatureBytes, - unusedBitsCount = 0 - ) - ) + ), + subjectPublicKeyInfo = + SubjectPublicKeyInfo( + algorithm = + AlgorithmIdentifier( + algorithm = RSA_ENCRYPTION, + parameters = null, + ), + subjectPublicKey = + BitString( + byteString = publicKeyBytes, + unusedBitsCount = 0, + ), + ), + issuerUniqueID = null, + subjectUniqueID = null, + extensions = listOf(), + ), + signatureAlgorithm = + AlgorithmIdentifier( + algorithm = SHA256_WITH_RSA_ENCRYPTION, + parameters = null, + ), + signatureValue = + BitString( + byteString = signatureBytes, + unusedBitsCount = 0, + ), + ), ) } @Test fun `decode CA certificate`() { - val certificateBase64 = """ - |MIIE/zCCA+egAwIBAgIEUdNARDANBgkqhkiG9w0BAQsFADCBsDELMAkGA1UEBhMC - |VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 - |Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW - |KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl - |cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE0MDkyMjE3MTQ1N1oXDTI0MDkyMzAx - |MzE1M1owgb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgw - |JgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQL - |EzAoYykgMjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9u - |bHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 - |eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoS2ctueDGvi - |mekwAad26jK4lUEaydphTlhyz/72gnm/c2EGCqUn2LNf00VOHHLWTjLycooP94MZ - |0GqAgABFHrDH55q/ElcnHKNoLwqHvWprDl5l8xx31dSFjXAhtLMy54ui1YY5ArG4 - |0kfO5MlJxDun3vtUfVe+8OhuwnmyOgtV4lCYFjITXC94VsHClLPyWuQnmp8k18bs - |0JslguPMwsRFxYyXegZrKhGfqQpuSDtv29QRGUL3jwe/9VNfnD70FyzmaaxOMkxi - |d+q36OW7NLwZi66cUee3frVTsTMi5W3PcDwa+uKbZ7aD9I2lr2JMTeBYrGQ0EgP4 - |to2UYySkcQIDAQABo4IBDzCCAQswDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI - |MAYBAf8CAQEwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz - |cC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1 - |c3QubmV0L3Jvb3RjYTEuY3JsMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUF - |BwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NQUzAdBgNVHQ4EFgQUanImetAe - |733nO2lR1GyNn5ASZqswHwYDVR0jBBgwFoAUaJDkZ6SmU4DHhmak8fdLQ/uEvW0w - |DQYJKoZIhvcNAQELBQADggEBAGkzg/woem99751V68U+ep11s8zDODbZNKIoaBjq - |HmnTvefQd9q4AINOSs9v0fHBIj905PeYSZ6btp7h25h3LVY0sag82f3Azce/BQPU - |AsXx5cbaCKUTx2IjEdFhMB1ghEXveajGJpOkt800uGnFE/aRs8lFc3a2kvZ2Clvh - |A0e36SlMkTIjN0qcNdh4/R0f5IOJJICtt/nP5F2l1HHEhVtwH9s/HAHrGkUmMRTM - |Zb9n3srMM2XlQZHXN75BGpad5oqXnafOrE6aPb0BoGrZTyIAi0TVaWJ7LuvMuueS - |fWlnPfy4fN5Bh9Bp6roKGHoalUOzeXEodm2h+1dK7E3IDhA= - |""".trimMargin() + val certificateBase64 = + """ + |MIIE/zCCA+egAwIBAgIEUdNARDANBgkqhkiG9w0BAQsFADCBsDELMAkGA1UEBhMC + |VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 + |Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW + |KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl + |cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE0MDkyMjE3MTQ1N1oXDTI0MDkyMzAx + |MzE1M1owgb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgw + |JgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQL + |EzAoYykgMjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9u + |bHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 + |eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoS2ctueDGvi + |mekwAad26jK4lUEaydphTlhyz/72gnm/c2EGCqUn2LNf00VOHHLWTjLycooP94MZ + |0GqAgABFHrDH55q/ElcnHKNoLwqHvWprDl5l8xx31dSFjXAhtLMy54ui1YY5ArG4 + |0kfO5MlJxDun3vtUfVe+8OhuwnmyOgtV4lCYFjITXC94VsHClLPyWuQnmp8k18bs + |0JslguPMwsRFxYyXegZrKhGfqQpuSDtv29QRGUL3jwe/9VNfnD70FyzmaaxOMkxi + |d+q36OW7NLwZi66cUee3frVTsTMi5W3PcDwa+uKbZ7aD9I2lr2JMTeBYrGQ0EgP4 + |to2UYySkcQIDAQABo4IBDzCCAQswDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI + |MAYBAf8CAQEwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz + |cC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1 + |c3QubmV0L3Jvb3RjYTEuY3JsMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUF + |BwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NQUzAdBgNVHQ4EFgQUanImetAe + |733nO2lR1GyNn5ASZqswHwYDVR0jBBgwFoAUaJDkZ6SmU4DHhmak8fdLQ/uEvW0w + |DQYJKoZIhvcNAQELBQADggEBAGkzg/woem99751V68U+ep11s8zDODbZNKIoaBjq + |HmnTvefQd9q4AINOSs9v0fHBIj905PeYSZ6btp7h25h3LVY0sag82f3Azce/BQPU + |AsXx5cbaCKUTx2IjEdFhMB1ghEXveajGJpOkt800uGnFE/aRs8lFc3a2kvZ2Clvh + |A0e36SlMkTIjN0qcNdh4/R0f5IOJJICtt/nP5F2l1HHEhVtwH9s/HAHrGkUmMRTM + |Zb9n3srMM2XlQZHXN75BGpad5oqXnafOrE6aPb0BoGrZTyIAi0TVaWJ7LuvMuueS + |fWlnPfy4fN5Bh9Bp6roKGHoalUOzeXEodm2h+1dK7E3IDhA= + | + """.trimMargin() val certificateByteString = certificateBase64.decodeBase64()!! - val certificatePem = """ - |-----BEGIN CERTIFICATE----- - |$certificateBase64 - |-----END CERTIFICATE----- - |""".trimMargin() + val certificatePem = + """ + |-----BEGIN CERTIFICATE----- + |$certificateBase64 + |-----END CERTIFICATE----- + | + """.trimMargin() val javaCertificate = certificatePem.decodeCertificatePem() - val okHttpCertificate = CertificateAdapters.certificate + val okHttpCertificate = + CertificateAdapters.certificate .fromDer(certificateByteString) - val publicKeyBytes = ("3082010a0282010100ba84b672db9e0c6be299e93001a776ea32b895411ac9da614e58" + - "72cffef68279bf7361060aa527d8b35fd3454e1c72d64e32f2728a0ff78319d06a808000451eb0c7e79abf12" + - "57271ca3682f0a87bd6a6b0e5e65f31c77d5d4858d7021b4b332e78ba2d5863902b1b8d247cee4c949c43ba7" + - "defb547d57bef0e86ec279b23a0b55e250981632135c2f7856c1c294b3f25ae4279a9f24d7c6ecd09b2582e3" + - "ccc2c445c58c977a066b2a119fa90a6e483b6fdbd4111942f78f07bff5535f9c3ef4172ce669ac4e324c6277" + - "eab7e8e5bb34bc198bae9c51e7b77eb553b13322e56dcf703c1afae29b67b683f48da5af624c4de058ac6434" + - "1203f8b68d946324a4710203010001").decodeHex() - val signatureBytes = ("693383fc287a6f7def9d55ebc53e7a9d75b3ccc33836d934a2286818ea1e69d3bde7d0" + - "77dab800834e4acf6fd1f1c1223f74e4f798499e9bb69ee1db98772d5634b1a83cd9fdc0cdc7bf0503d402c5" + - "f1e5c6da08a513c7622311d161301d608445ef79a8c62693a4b7cd34b869c513f691b3c9457376b692f6760a" + - "5be10347b7e9294c913223374a9c35d878fd1d1fe483892480adb7f9cfe45da5d471c4855b701fdb3f1c01eb" + - "1a45263114cc65bf67decacc3365e54191d737be411a969de68a979da7ceac4e9a3dbd01a06ad94f22008b44" + - "d569627b2eebccbae7927d69673dfcb87cde4187d069eaba0a187a1a9543b3797128766da1fb574aec4dc80e" + - "10").decodeHex() + val publicKeyBytes = + ( + "3082010a0282010100ba84b672db9e0c6be299e93001a776ea32b895411ac9da614e58" + + "72cffef68279bf7361060aa527d8b35fd3454e1c72d64e32f2728a0ff78319d06a808000451eb0c7e79abf12" + + "57271ca3682f0a87bd6a6b0e5e65f31c77d5d4858d7021b4b332e78ba2d5863902b1b8d247cee4c949c43ba7" + + "defb547d57bef0e86ec279b23a0b55e250981632135c2f7856c1c294b3f25ae4279a9f24d7c6ecd09b2582e3" + + "ccc2c445c58c977a066b2a119fa90a6e483b6fdbd4111942f78f07bff5535f9c3ef4172ce669ac4e324c6277" + + "eab7e8e5bb34bc198bae9c51e7b77eb553b13322e56dcf703c1afae29b67b683f48da5af624c4de058ac6434" + + "1203f8b68d946324a4710203010001" + ).decodeHex() + val signatureBytes = + ( + "693383fc287a6f7def9d55ebc53e7a9d75b3ccc33836d934a2286818ea1e69d3bde7d0" + + "77dab800834e4acf6fd1f1c1223f74e4f798499e9bb69ee1db98772d5634b1a83cd9fdc0cdc7bf0503d402c5" + + "f1e5c6da08a513c7622311d161301d608445ef79a8c62693a4b7cd34b869c513f691b3c9457376b692f6760a" + + "5be10347b7e9294c913223374a9c35d878fd1d1fe483892480adb7f9cfe45da5d471c4855b701fdb3f1c01eb" + + "1a45263114cc65bf67decacc3365e54191d737be411a969de68a979da7ceac4e9a3dbd01a06ad94f22008b44" + + "d569627b2eebccbae7927d69673dfcb87cde4187d069eaba0a187a1a9543b3797128766da1fb574aec4dc80e" + + "10" + ).decodeHex() assertThat(okHttpCertificate.signatureValue.byteString) - .isEqualTo(javaCertificate.signature.toByteString()) + .isEqualTo(javaCertificate.signature.toByteString()) assertThat(okHttpCertificate).isEqualTo( - Certificate( - tbsCertificate = TbsCertificate( - // v3. - version = 2L, - serialNumber = BigInteger("1372799044"), - signature = AlgorithmIdentifier( - algorithm = SHA256_WITH_RSA_ENCRYPTION, - parameters = null - ), - issuer = listOf( - listOf( - AttributeTypeAndValue( - type = countryName, - value = "US" - ) - ), - listOf( - AttributeTypeAndValue( - type = organizationName, - value = "Entrust, Inc." - ) - ), - listOf( - AttributeTypeAndValue( - type = ORGANIZATIONAL_UNIT_NAME, - value = "www.entrust.net/CPS is incorporated by reference" - ) - ), - listOf( - AttributeTypeAndValue( - type = ORGANIZATIONAL_UNIT_NAME, - value = "(c) 2006 Entrust, Inc." - ) - ), - listOf( - AttributeTypeAndValue( - type = COMMON_NAME, - value = "Entrust Root Certification Authority" - ) - ) + Certificate( + tbsCertificate = + TbsCertificate( + // v3. + version = 2L, + serialNumber = BigInteger("1372799044"), + signature = + AlgorithmIdentifier( + algorithm = SHA256_WITH_RSA_ENCRYPTION, + parameters = null, + ), + issuer = + listOf( + listOf( + AttributeTypeAndValue( + type = countryName, + value = "US", + ), ), - validity = Validity( - notBefore = 1411406097000L, - notAfter = 1727055113000L + listOf( + AttributeTypeAndValue( + type = organizationName, + value = "Entrust, Inc.", + ), ), - subject = listOf( - listOf( - AttributeTypeAndValue( - type = countryName, - value = "US" - ) - ), - listOf( - AttributeTypeAndValue( - type = organizationName, - value = "Entrust, Inc." - ) - ), - listOf( - AttributeTypeAndValue( - type = ORGANIZATIONAL_UNIT_NAME, - value = "See www.entrust.net/legal-terms" - ) - ), - listOf( - AttributeTypeAndValue( - type = ORGANIZATIONAL_UNIT_NAME, - value = "(c) 2009 Entrust, Inc. - for authorized use only" - ) - ), - listOf( - AttributeTypeAndValue( - type = COMMON_NAME, - value = "Entrust Root Certification Authority - G2" - ) - ) + listOf( + AttributeTypeAndValue( + type = ORGANIZATIONAL_UNIT_NAME, + value = "www.entrust.net/CPS is incorporated by reference", + ), ), - subjectPublicKeyInfo = SubjectPublicKeyInfo( - algorithm = AlgorithmIdentifier( - algorithm = RSA_ENCRYPTION, - parameters = null - ), - subjectPublicKey = BitString( - byteString = publicKeyBytes, - unusedBitsCount = 0 - ) + listOf( + AttributeTypeAndValue( + type = ORGANIZATIONAL_UNIT_NAME, + value = "(c) 2006 Entrust, Inc.", + ), ), - issuerUniqueID = null, - subjectUniqueID = null, - extensions = listOf( - Extension( - id = keyUsage, - critical = true, - value = "03020106".decodeHex() - ), - Extension( - id = BASIC_CONSTRAINTS, - critical = true, - value = BasicConstraints( - ca = true, - maxIntermediateCas = 1L - ) - ), - Extension( - id = authorityInfoAccess, - critical = false, - value = ("3025302306082b060105050730018617687474703a2f2f6f6373702e656" + - "e74727573742e6e6574").decodeHex() - ), - Extension( - id = crlDistributionPoints, - critical = false, - value = ("302a3028a026a0248622687474703a2f2f63726c2e656e74727573742e6" + - "e65742f726f6f746361312e63726c").decodeHex() - ), - Extension( - id = certificatePolicies, - critical = false, - value = ("303230300604551d20003028302606082b06010505070201161a6874747" + - "03a2f2f7777772e656e74727573742e6e65742f435053").decodeHex() - ), - Extension( - id = subjectKeyIdentifier, - critical = false, - value = "04146a72267ad01eef7de73b6951d46c8d9f901266ab".decodeHex() + listOf( + AttributeTypeAndValue( + type = COMMON_NAME, + value = "Entrust Root Certification Authority", + ), + ), + ), + validity = + Validity( + notBefore = 1411406097000L, + notAfter = 1727055113000L, + ), + subject = + listOf( + listOf( + AttributeTypeAndValue( + type = countryName, + value = "US", + ), + ), + listOf( + AttributeTypeAndValue( + type = organizationName, + value = "Entrust, Inc.", + ), + ), + listOf( + AttributeTypeAndValue( + type = ORGANIZATIONAL_UNIT_NAME, + value = "See www.entrust.net/legal-terms", + ), + ), + listOf( + AttributeTypeAndValue( + type = ORGANIZATIONAL_UNIT_NAME, + value = "(c) 2009 Entrust, Inc. - for authorized use only", + ), + ), + listOf( + AttributeTypeAndValue( + type = COMMON_NAME, + value = "Entrust Root Certification Authority - G2", + ), + ), + ), + subjectPublicKeyInfo = + SubjectPublicKeyInfo( + algorithm = + AlgorithmIdentifier( + algorithm = RSA_ENCRYPTION, + parameters = null, + ), + subjectPublicKey = + BitString( + byteString = publicKeyBytes, + unusedBitsCount = 0, + ), + ), + issuerUniqueID = null, + subjectUniqueID = null, + extensions = + listOf( + Extension( + id = keyUsage, + critical = true, + value = "03020106".decodeHex(), + ), + Extension( + id = BASIC_CONSTRAINTS, + critical = true, + value = + BasicConstraints( + ca = true, + maxIntermediateCas = 1L, ), - Extension( - id = authorityKeyIdentifier, - critical = false, - value = "301680146890e467a4a65380c78666a4f1f74b43fb84bd6d".decodeHex() - ) - ) - ), - signatureAlgorithm = AlgorithmIdentifier( - algorithm = SHA256_WITH_RSA_ENCRYPTION, - parameters = null - ), - signatureValue = BitString( - byteString = signatureBytes, - unusedBitsCount = 0 - ) - ) + ), + Extension( + id = authorityInfoAccess, + critical = false, + value = + ( + "3025302306082b060105050730018617687474703a2f2f6f6373702e656" + + "e74727573742e6e6574" + ).decodeHex(), + ), + Extension( + id = crlDistributionPoints, + critical = false, + value = + ( + "302a3028a026a0248622687474703a2f2f63726c2e656e74727573742e6" + + "e65742f726f6f746361312e63726c" + ).decodeHex(), + ), + Extension( + id = certificatePolicies, + critical = false, + value = + ( + "303230300604551d20003028302606082b06010505070201161a6874747" + + "03a2f2f7777772e656e74727573742e6e65742f435053" + ).decodeHex(), + ), + Extension( + id = subjectKeyIdentifier, + critical = false, + value = "04146a72267ad01eef7de73b6951d46c8d9f901266ab".decodeHex(), + ), + Extension( + id = authorityKeyIdentifier, + critical = false, + value = "301680146890e467a4a65380c78666a4f1f74b43fb84bd6d".decodeHex(), + ), + ), + ), + signatureAlgorithm = + AlgorithmIdentifier( + algorithm = SHA256_WITH_RSA_ENCRYPTION, + parameters = null, + ), + signatureValue = + BitString( + byteString = signatureBytes, + unusedBitsCount = 0, + ), + ), ) } @Test fun `decode typical certificate`() { - val certificateBase64 = """ - |MIIHHTCCBgWgAwIBAgIRAL5oALmpH7l6AAAAAFTRMh0wDQYJKoZIhvcNAQELBQAw - |gboxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL - |Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg - |MjAxNCBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLjAs - |BgNVBAMTJUVudHJ1c3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBMMU0wHhcN - |MjAwNDEzMTMyNTQ5WhcNMjEwNDEyMTM1NTQ5WjCBxTELMAkGA1UEBhMCVVMxEzAR - |BgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgsr - |BgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVsYXdhcmUxFTATBgNV - |BAoTDFNxdWFyZSwgSW5jLjEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24x - |EDAOBgNVBAUTBzQ2OTk4NTUxETAPBgNVBAMTCGNhc2guYXBwMIIBIjANBgkqhkiG - |9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqv2iSwWvb6ys/Ru4LtSz0R4wDaxklrFIGqdJ - |rxxYdAdLQjyjHyJsfkNQdt2u4JYPRKaRTVYR9VIIeWUx/IjhZhsGPstPMjYT3cN1 - |VsphSDtrRVuxYlmkrvHar0HoadNr1MHd96Ach3g1QJlV8uyUJ7JXpPCNJ8EMiH52 - |n8bVzpjDjXwoYg3oOYvceteA0GJ5VWYACDgfmkeoaN1Cx31O9qcSiUk5AY8HfAnP - |h20VcrnPo2dJmm7fkUKohIxrMjtpwi5esWhCBZJk50FveKrgdeSe4XxNL7uJPD89 - |SJtKmX7jxoNQSY3mrPssLdadwltUOhzc4Lcmoj4Ob24JxuVw8QIDAQABo4IDDzCC - |AwswIQYDVR0RBBowGIIIY2FzaC5hcHCCDHd3dy5jYXNoLmFwcDCCAX8GCisGAQQB - |1nkCBAIEggFvBIIBawFpAHcAVhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ - |0N0AAAFxc9MmmwAABAMASDBGAiEAqeWK3uWt9LX1p3l0gPgNxYBB142oqtRMnMBB - |anTKy2ICIQDrRj7PRsVyXf1QRxgE5MZl6K6XkBKbaXBlAqPpb8z2hQB3AId1v+dZ - |fPiMQ5lfvfNu/1aNR1Y2/0q1YMG06v9eoIMPAAABcXPTJq0AAAQDAEgwRgIhANRS - |wAmVQLXhhxbbUTSKIA6P0Q6EmNABCNSJjSK5Q0ItAiEA88hnegYqVaykbbsQSSI0 - |gP/+Odnm/Thso6HEJFXvYGcAdQB9PvL4j/+IVWgkwsDKnlKJeSvFDngJfy5ql2iZ - |fiLw1wAAAXFz0yazAAAEAwBGMEQCIH4RLAKbk+DbFdHeQO3bmqelXutLSM6MlN34 - |7XEzHpMeAiB4KB48OcjmQ7kBwrxsRwqg7TrQG/F/DyB9wPilq1QacDAOBgNVHQ8B - |Af8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMGgGCCsGAQUF - |BwEBBFwwWjAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMwYI - |KwYBBQUHMAKGJ2h0dHA6Ly9haWEuZW50cnVzdC5uZXQvbDFtLWNoYWluMjU2LmNl - |cjAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1c3QubmV0L2xldmVs - |MW0uY3JsMEoGA1UdIARDMEEwNgYKYIZIAYb6bAoBAjAoMCYGCCsGAQUFBwIBFhpo - |dHRwOi8vd3d3LmVudHJ1c3QubmV0L3JwYTAHBgVngQwBATAfBgNVHSMEGDAWgBTD - |99C1KjCtrw2RIXA5VN28iXDHOjAdBgNVHQ4EFgQUdf0kwt9ZJZnjLzNz4YwEUN0b - |h7YwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEAYLX6TSuQqSAEu37pJ+au - |9IlRiAEhtdybxr3mhuII0zImejhLuo2knO2SD59avCDBPivITsSvh2aewOUmeKj1 - |GYI7v16xCOCTQz3k31sCAX2L7DozHtbrY4wG7hUSA9dSv/aYJEtebkwim3lgHwv3 - |NHA3iiW3raH1DPJThQmxFJrnT1zL0LQbM1nRQMXaBVfQEEhIYnrU672x6D/cya6r - |5UwWye3TOZCH0Lh+YaZqtuKx9lEIEXaxjD3jpGlwRLuE/fI6fXg+0kMvaqNVLmpN - |aJT7WeHs5bkf0dU7rtDefr0iKeqIxrlURPgbeWZF8GAkpdNaCwWMDAFO8DG04K+t - |Aw== - |""".trimMargin() + val certificateBase64 = + """ + |MIIHHTCCBgWgAwIBAgIRAL5oALmpH7l6AAAAAFTRMh0wDQYJKoZIhvcNAQELBQAw + |gboxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL + |Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg + |MjAxNCBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLjAs + |BgNVBAMTJUVudHJ1c3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBMMU0wHhcN + |MjAwNDEzMTMyNTQ5WhcNMjEwNDEyMTM1NTQ5WjCBxTELMAkGA1UEBhMCVVMxEzAR + |BgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgsr + |BgEEAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVsYXdhcmUxFTATBgNV + |BAoTDFNxdWFyZSwgSW5jLjEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24x + |EDAOBgNVBAUTBzQ2OTk4NTUxETAPBgNVBAMTCGNhc2guYXBwMIIBIjANBgkqhkiG + |9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqv2iSwWvb6ys/Ru4LtSz0R4wDaxklrFIGqdJ + |rxxYdAdLQjyjHyJsfkNQdt2u4JYPRKaRTVYR9VIIeWUx/IjhZhsGPstPMjYT3cN1 + |VsphSDtrRVuxYlmkrvHar0HoadNr1MHd96Ach3g1QJlV8uyUJ7JXpPCNJ8EMiH52 + |n8bVzpjDjXwoYg3oOYvceteA0GJ5VWYACDgfmkeoaN1Cx31O9qcSiUk5AY8HfAnP + |h20VcrnPo2dJmm7fkUKohIxrMjtpwi5esWhCBZJk50FveKrgdeSe4XxNL7uJPD89 + |SJtKmX7jxoNQSY3mrPssLdadwltUOhzc4Lcmoj4Ob24JxuVw8QIDAQABo4IDDzCC + |AwswIQYDVR0RBBowGIIIY2FzaC5hcHCCDHd3dy5jYXNoLmFwcDCCAX8GCisGAQQB + |1nkCBAIEggFvBIIBawFpAHcAVhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ + |0N0AAAFxc9MmmwAABAMASDBGAiEAqeWK3uWt9LX1p3l0gPgNxYBB142oqtRMnMBB + |anTKy2ICIQDrRj7PRsVyXf1QRxgE5MZl6K6XkBKbaXBlAqPpb8z2hQB3AId1v+dZ + |fPiMQ5lfvfNu/1aNR1Y2/0q1YMG06v9eoIMPAAABcXPTJq0AAAQDAEgwRgIhANRS + |wAmVQLXhhxbbUTSKIA6P0Q6EmNABCNSJjSK5Q0ItAiEA88hnegYqVaykbbsQSSI0 + |gP/+Odnm/Thso6HEJFXvYGcAdQB9PvL4j/+IVWgkwsDKnlKJeSvFDngJfy5ql2iZ + |fiLw1wAAAXFz0yazAAAEAwBGMEQCIH4RLAKbk+DbFdHeQO3bmqelXutLSM6MlN34 + |7XEzHpMeAiB4KB48OcjmQ7kBwrxsRwqg7TrQG/F/DyB9wPilq1QacDAOBgNVHQ8B + |Af8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMGgGCCsGAQUF + |BwEBBFwwWjAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMwYI + |KwYBBQUHMAKGJ2h0dHA6Ly9haWEuZW50cnVzdC5uZXQvbDFtLWNoYWluMjU2LmNl + |cjAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1c3QubmV0L2xldmVs + |MW0uY3JsMEoGA1UdIARDMEEwNgYKYIZIAYb6bAoBAjAoMCYGCCsGAQUFBwIBFhpo + |dHRwOi8vd3d3LmVudHJ1c3QubmV0L3JwYTAHBgVngQwBATAfBgNVHSMEGDAWgBTD + |99C1KjCtrw2RIXA5VN28iXDHOjAdBgNVHQ4EFgQUdf0kwt9ZJZnjLzNz4YwEUN0b + |h7YwCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEAYLX6TSuQqSAEu37pJ+au + |9IlRiAEhtdybxr3mhuII0zImejhLuo2knO2SD59avCDBPivITsSvh2aewOUmeKj1 + |GYI7v16xCOCTQz3k31sCAX2L7DozHtbrY4wG7hUSA9dSv/aYJEtebkwim3lgHwv3 + |NHA3iiW3raH1DPJThQmxFJrnT1zL0LQbM1nRQMXaBVfQEEhIYnrU672x6D/cya6r + |5UwWye3TOZCH0Lh+YaZqtuKx9lEIEXaxjD3jpGlwRLuE/fI6fXg+0kMvaqNVLmpN + |aJT7WeHs5bkf0dU7rtDefr0iKeqIxrlURPgbeWZF8GAkpdNaCwWMDAFO8DG04K+t + |Aw== + | + """.trimMargin() val certificateByteString = certificateBase64.decodeBase64()!! - val certificatePem = """ - |-----BEGIN CERTIFICATE----- - |$certificateBase64 - |-----END CERTIFICATE----- - |""".trimMargin() + val certificatePem = + """ + |-----BEGIN CERTIFICATE----- + |$certificateBase64 + |-----END CERTIFICATE----- + | + """.trimMargin() val javaCertificate = certificatePem.decodeCertificatePem() - val okHttpCertificate = CertificateAdapters.certificate + val okHttpCertificate = + CertificateAdapters.certificate .fromDer(certificateByteString) - val publicKeyBytes = ("3082010a0282010100aafda24b05af6facacfd1bb82ed4b3d11e300dac6496b1481aa7" + - "49af1c5874074b423ca31f226c7e435076ddaee0960f44a6914d5611f55208796531fc88e1661b063ecb4f32" + - "3613ddc37556ca61483b6b455bb16259a4aef1daaf41e869d36bd4c1ddf7a01c877835409955f2ec9427b257" + - "a4f08d27c10c887e769fc6d5ce98c38d7c28620de8398bdc7ad780d0627955660008381f9a47a868dd42c77d" + - "4ef6a712894939018f077c09cf876d1572b9cfa367499a6edf9142a8848c6b323b69c22e5eb16842059264e7" + - "416f78aae075e49ee17c4d2fbb893c3f3d489b4a997ee3c68350498de6acfb2c2dd69dc25b543a1cdce0b726" + - "a23e0e6f6e09c6e570f10203010001").decodeHex() - val signatureBytes = ("60b5fa4d2b90a92004bb7ee927e6aef48951880121b5dc9bc6bde686e208d332267a38" + - "4bba8da49ced920f9f5abc20c13e2bc84ec4af87669ec0e52678a8f519823bbf5eb108e093433de4df5b0201" + - "7d8bec3a331ed6eb638c06ee151203d752bff698244b5e6e4c229b79601f0bf73470378a25b7ada1f50cf253" + - "8509b1149ae74f5ccbd0b41b3359d140c5da0557d0104848627ad4ebbdb1e83fdcc9aeabe54c16c9edd33990" + - "87d0b87e61a66ab6e2b1f651081176b18c3de3a4697044bb84fdf23a7d783ed2432f6aa3552e6a4d6894fb59" + - "e1ece5b91fd1d53baed0de7ebd2229ea88c6b95444f81b796645f06024a5d35a0b058c0c014ef031b4e0afad" + - "03").decodeHex() + val publicKeyBytes = + ( + "3082010a0282010100aafda24b05af6facacfd1bb82ed4b3d11e300dac6496b1481aa7" + + "49af1c5874074b423ca31f226c7e435076ddaee0960f44a6914d5611f55208796531fc88e1661b063ecb4f32" + + "3613ddc37556ca61483b6b455bb16259a4aef1daaf41e869d36bd4c1ddf7a01c877835409955f2ec9427b257" + + "a4f08d27c10c887e769fc6d5ce98c38d7c28620de8398bdc7ad780d0627955660008381f9a47a868dd42c77d" + + "4ef6a712894939018f077c09cf876d1572b9cfa367499a6edf9142a8848c6b323b69c22e5eb16842059264e7" + + "416f78aae075e49ee17c4d2fbb893c3f3d489b4a997ee3c68350498de6acfb2c2dd69dc25b543a1cdce0b726" + + "a23e0e6f6e09c6e570f10203010001" + ).decodeHex() + val signatureBytes = + ( + "60b5fa4d2b90a92004bb7ee927e6aef48951880121b5dc9bc6bde686e208d332267a38" + + "4bba8da49ced920f9f5abc20c13e2bc84ec4af87669ec0e52678a8f519823bbf5eb108e093433de4df5b0201" + + "7d8bec3a331ed6eb638c06ee151203d752bff698244b5e6e4c229b79601f0bf73470378a25b7ada1f50cf253" + + "8509b1149ae74f5ccbd0b41b3359d140c5da0557d0104848627ad4ebbdb1e83fdcc9aeabe54c16c9edd33990" + + "87d0b87e61a66ab6e2b1f651081176b18c3de3a4697044bb84fdf23a7d783ed2432f6aa3552e6a4d6894fb59" + + "e1ece5b91fd1d53baed0de7ebd2229ea88c6b95444f81b796645f06024a5d35a0b058c0c014ef031b4e0afad" + + "03" + ).decodeHex() assertThat(okHttpCertificate.signatureValue.byteString) - .isEqualTo(javaCertificate.signature.toByteString()) + .isEqualTo(javaCertificate.signature.toByteString()) assertThat(okHttpCertificate).isEqualTo( - Certificate( - tbsCertificate = TbsCertificate( - // v3. - version = 2L, - serialNumber = BigInteger("253093332781973022312510445874391888413"), - signature = AlgorithmIdentifier( - algorithm = SHA256_WITH_RSA_ENCRYPTION, - parameters = null - ), - issuer = listOf( - listOf( - AttributeTypeAndValue( - type = countryName, - value = "US" - ) - ), - listOf( - AttributeTypeAndValue( - type = organizationName, - value = "Entrust, Inc." - ) - ), - listOf( - AttributeTypeAndValue( - type = ORGANIZATIONAL_UNIT_NAME, - value = "See www.entrust.net/legal-terms" - ) - ), - listOf( - AttributeTypeAndValue( - type = ORGANIZATIONAL_UNIT_NAME, - value = "(c) 2014 Entrust, Inc. - for authorized use only" - ) - ), - listOf( - AttributeTypeAndValue( - type = COMMON_NAME, - value = "Entrust Certification Authority - L1M" - ) - ) + Certificate( + tbsCertificate = + TbsCertificate( + // v3. + version = 2L, + serialNumber = BigInteger("253093332781973022312510445874391888413"), + signature = + AlgorithmIdentifier( + algorithm = SHA256_WITH_RSA_ENCRYPTION, + parameters = null, + ), + issuer = + listOf( + listOf( + AttributeTypeAndValue( + type = countryName, + value = "US", + ), ), - validity = Validity( - notBefore = 1586784349000L, - notAfter = 1618235749000L + listOf( + AttributeTypeAndValue( + type = organizationName, + value = "Entrust, Inc.", + ), ), - subject = listOf( - listOf( - AttributeTypeAndValue( - type = countryName, - value = "US" - ) - ), - listOf( - AttributeTypeAndValue( - type = stateOrProvinceName, - value = "California" - ) - ), - listOf( - AttributeTypeAndValue( - type = localityName, - value = "San Francisco" - ) - ), - listOf( - AttributeTypeAndValue( - type = country, - value = "US" - ) - ), - listOf( - AttributeTypeAndValue( - type = stateOrProvince, - value = "Delaware" - ) - ), - listOf( - AttributeTypeAndValue( - type = organizationName, - value = "Square, Inc." - ) - ), - listOf( - AttributeTypeAndValue( - type = businessCategory, - value = "Private Organization" - ) - ), + listOf( + AttributeTypeAndValue( + type = ORGANIZATIONAL_UNIT_NAME, + value = "See www.entrust.net/legal-terms", + ), + ), + listOf( + AttributeTypeAndValue( + type = ORGANIZATIONAL_UNIT_NAME, + value = "(c) 2014 Entrust, Inc. - for authorized use only", + ), + ), + listOf( + AttributeTypeAndValue( + type = COMMON_NAME, + value = "Entrust Certification Authority - L1M", + ), + ), + ), + validity = + Validity( + notBefore = 1586784349000L, + notAfter = 1618235749000L, + ), + subject = + listOf( + listOf( + AttributeTypeAndValue( + type = countryName, + value = "US", + ), + ), + listOf( + AttributeTypeAndValue( + type = stateOrProvinceName, + value = "California", + ), + ), + listOf( + AttributeTypeAndValue( + type = localityName, + value = "San Francisco", + ), + ), + listOf( + AttributeTypeAndValue( + type = country, + value = "US", + ), + ), + listOf( + AttributeTypeAndValue( + type = stateOrProvince, + value = "Delaware", + ), + ), + listOf( + AttributeTypeAndValue( + type = organizationName, + value = "Square, Inc.", + ), + ), + listOf( + AttributeTypeAndValue( + type = businessCategory, + value = "Private Organization", + ), + ), + listOf( + AttributeTypeAndValue( + type = serialNumber, + value = "4699855", + ), + ), + listOf( + AttributeTypeAndValue( + type = COMMON_NAME, + value = "cash.app", + ), + ), + ), + subjectPublicKeyInfo = + SubjectPublicKeyInfo( + algorithm = + AlgorithmIdentifier( + algorithm = RSA_ENCRYPTION, + parameters = null, + ), + subjectPublicKey = + BitString( + byteString = publicKeyBytes, + unusedBitsCount = 0, + ), + ), + issuerUniqueID = null, + subjectUniqueID = null, + extensions = + listOf( + Extension( + id = SUBJECT_ALTERNATIVE_NAME, + critical = false, + value = listOf( - AttributeTypeAndValue( - type = serialNumber, - value = "4699855" - ) + CertificateAdapters.generalNameDnsName to "cash.app", + CertificateAdapters.generalNameDnsName to "www.cash.app", ), - listOf( - AttributeTypeAndValue( - type = COMMON_NAME, - value = "cash.app" - ) - ) ), - subjectPublicKeyInfo = SubjectPublicKeyInfo( - algorithm = AlgorithmIdentifier( - algorithm = RSA_ENCRYPTION, - parameters = null - ), - subjectPublicKey = BitString( - byteString = publicKeyBytes, - unusedBitsCount = 0 + Extension( + id = certificateTransparencySignedCertificateTimestamps, + critical = false, + value = + ( + "0482016b01690077005614069a2fd7c2ecd3f5e1bd44b23ec74676b9bc9" + + "9115cc0ef949855d689d0dd0000017173d3269b0000040300483046022100a9e58ad" + + "ee5adf4b5f5a7797480f80dc58041d78da8aad44c9cc0416a74cacb62022100eb463" + + "ecf46c5725dfd50471804e4c665e8ae9790129b69706502a3e96fccf685007700877" + + "5bfe7597cf88c43995fbdf36eff568d475636ff4ab560c1b4eaff5ea0830f0000017" + + "173d326ad0000040300483046022100d452c0099540b5e18716db51348a200e8fd10" + + "e8498d00108d4898d22b943422d022100f3c8677a062a55aca46dbb1049223480fff" + + "e39d9e6fd386ca3a1c42455ef60670075007d3ef2f88fff88556824c2c0ca9e52897" + + "92bc50e78097f2e6a9768997e22f0d70000017173d326b3000004030046304402207" + + "e112c029b93e0db15d1de40eddb9aa7a55eeb4b48ce8c94ddf8ed71331e931e02207" + + "8281e3c39c8e643b901c2bc6c470aa0ed3ad01bf17f0f207dc0f8a5ab541a70" ) + .decodeHex(), ), - issuerUniqueID = null, - subjectUniqueID = null, - extensions = listOf( - Extension( - id = SUBJECT_ALTERNATIVE_NAME, - critical = false, - value = listOf( - CertificateAdapters.generalNameDnsName to "cash.app", - CertificateAdapters.generalNameDnsName to "www.cash.app" - ) - ), - Extension( - id = certificateTransparencySignedCertificateTimestamps, - critical = false, - value = ("0482016b01690077005614069a2fd7c2ecd3f5e1bd44b23ec74676b9bc9" + - "9115cc0ef949855d689d0dd0000017173d3269b0000040300483046022100a9e58ad" + - "ee5adf4b5f5a7797480f80dc58041d78da8aad44c9cc0416a74cacb62022100eb463" + - "ecf46c5725dfd50471804e4c665e8ae9790129b69706502a3e96fccf685007700877" + - "5bfe7597cf88c43995fbdf36eff568d475636ff4ab560c1b4eaff5ea0830f0000017" + - "173d326ad0000040300483046022100d452c0099540b5e18716db51348a200e8fd10" + - "e8498d00108d4898d22b943422d022100f3c8677a062a55aca46dbb1049223480fff" + - "e39d9e6fd386ca3a1c42455ef60670075007d3ef2f88fff88556824c2c0ca9e52897" + - "92bc50e78097f2e6a9768997e22f0d70000017173d326b3000004030046304402207" + - "e112c029b93e0db15d1de40eddb9aa7a55eeb4b48ce8c94ddf8ed71331e931e02207" + - "8281e3c39c8e643b901c2bc6c470aa0ed3ad01bf17f0f207dc0f8a5ab541a70") - .decodeHex() - ), - Extension( - id = keyUsage, - critical = true, - value = "030205a0".decodeHex() - ), - Extension( - id = extendedKeyUsage, - critical = false, - value = "301406082b0601050507030106082b06010505070302".decodeHex() - ), - Extension( - id = authorityInfoAccess, - critical = false, - value = ("305a302306082b060105050730018617687474703a2f2f6f6373702e656" + - "e74727573742e6e6574303306082b060105050730028627687474703a2f2f6169612" + - "e656e74727573742e6e65742f6c316d2d636861696e3235362e636572").decodeHex() - ), - Extension( - id = crlDistributionPoints, - critical = false, - value = ("302a3028a026a0248622687474703a2f2f63726c2e656e74727573742e6" + - "e65742f6c6576656c316d2e63726c").decodeHex() - ), - Extension( - id = certificatePolicies, - critical = false, - value = ("30413036060a6086480186fa6c0a01023028302606082b0601050507020" + - "1161a687474703a2f2f7777772e656e74727573742e6e65742f72706130070605678" + - "10c0101").decodeHex() - ), - Extension( - id = authorityKeyIdentifier, - critical = false, - value = ("30168014c3f7d0b52a30adaf0d9121703954ddbc8970c73a").decodeHex() - ), - Extension( - id = subjectKeyIdentifier, - critical = false, - value = "041475fd24c2df592599e32f3373e18c0450dd1b87b6".decodeHex() + Extension( + id = keyUsage, + critical = true, + value = "030205a0".decodeHex(), + ), + Extension( + id = extendedKeyUsage, + critical = false, + value = "301406082b0601050507030106082b06010505070302".decodeHex(), + ), + Extension( + id = authorityInfoAccess, + critical = false, + value = + ( + "305a302306082b060105050730018617687474703a2f2f6f6373702e656" + + "e74727573742e6e6574303306082b060105050730028627687474703a2f2f6169612" + + "e656e74727573742e6e65742f6c316d2d636861696e3235362e636572" + ).decodeHex(), + ), + Extension( + id = crlDistributionPoints, + critical = false, + value = + ( + "302a3028a026a0248622687474703a2f2f63726c2e656e74727573742e6" + + "e65742f6c6576656c316d2e63726c" + ).decodeHex(), + ), + Extension( + id = certificatePolicies, + critical = false, + value = + ( + "30413036060a6086480186fa6c0a01023028302606082b0601050507020" + + "1161a687474703a2f2f7777772e656e74727573742e6e65742f72706130070605678" + + "10c0101" + ).decodeHex(), + ), + Extension( + id = authorityKeyIdentifier, + critical = false, + value = ("30168014c3f7d0b52a30adaf0d9121703954ddbc8970c73a").decodeHex(), + ), + Extension( + id = subjectKeyIdentifier, + critical = false, + value = "041475fd24c2df592599e32f3373e18c0450dd1b87b6".decodeHex(), + ), + Extension( + id = BASIC_CONSTRAINTS, + critical = false, + value = + BasicConstraints( + ca = false, + maxIntermediateCas = null, ), - Extension( - id = BASIC_CONSTRAINTS, - critical = false, - value = BasicConstraints( - ca = false, - maxIntermediateCas = null - ) - ) - ) - ), - signatureAlgorithm = AlgorithmIdentifier( - algorithm = SHA256_WITH_RSA_ENCRYPTION, - parameters = null - ), - signatureValue = BitString( - byteString = signatureBytes, - unusedBitsCount = 0 - ) - ) + ), + ), + ), + signatureAlgorithm = + AlgorithmIdentifier( + algorithm = SHA256_WITH_RSA_ENCRYPTION, + parameters = null, + ), + signatureValue = + BitString( + byteString = signatureBytes, + unusedBitsCount = 0, + ), + ), ) } @Test fun `certificate attributes`() { - val certificate = HeldCertificate.Builder() + val certificate = + HeldCertificate.Builder() .certificateAuthority(3) .commonName("Jurassic Park") .organizationalUnit("Gene Research") @@ -646,31 +736,38 @@ internal class DerCertificatesTest { val certificateByteString = certificate.certificate.encoded.toByteString() - val okHttpCertificate = CertificateAdapters.certificate + val okHttpCertificate = + CertificateAdapters.certificate .fromDer(certificateByteString) - assertThat(okHttpCertificate.basicConstraints).isEqualTo(Extension( + assertThat(okHttpCertificate.basicConstraints).isEqualTo( + Extension( id = BASIC_CONSTRAINTS, critical = true, - value = BasicConstraints(true, 3) - )) + value = BasicConstraints(true, 3), + ), + ) assertThat(okHttpCertificate.commonName).isEqualTo("Jurassic Park") assertThat(okHttpCertificate.organizationalUnitName).isEqualTo("Gene Research") - assertThat(okHttpCertificate.subjectAlternativeNames).isEqualTo(Extension( + assertThat(okHttpCertificate.subjectAlternativeNames).isEqualTo( + Extension( id = SUBJECT_ALTERNATIVE_NAME, critical = true, - value = listOf( + value = + listOf( CertificateAdapters.generalNameDnsName to "*.example.com", - CertificateAdapters.generalNameDnsName to "www.example.org" - ) - )) + CertificateAdapters.generalNameDnsName to "www.example.org", + ), + ), + ) assertThat(okHttpCertificate.tbsCertificate.validity).isEqualTo(Validity(-1000L, 2000L)) assertThat(okHttpCertificate.tbsCertificate.serialNumber).isEqualTo(BigInteger("17")) } @Test fun `missing subject alternative names`() { - val certificate = HeldCertificate.Builder() + val certificate = + HeldCertificate.Builder() .certificateAuthority(3) .commonName("Jurassic Park") .organizationalUnit("Gene Research") @@ -680,7 +777,8 @@ internal class DerCertificatesTest { val certificateByteString = certificate.certificate.encoded.toByteString() - val okHttpCertificate = CertificateAdapters.certificate + val okHttpCertificate = + CertificateAdapters.certificate .fromDer(certificateByteString) assertThat(okHttpCertificate.commonName).isEqualTo("Jurassic Park") @@ -689,39 +787,48 @@ internal class DerCertificatesTest { @Test fun `public key`() { - val publicKeyBytes = ("MIGJAoGBAICkUeG2stqfbyr6gyiVm5pN9YEDRXlowi+rfYGyWhC7ouW9fXAnhgShQKMOU8" + - "62mG3tcttSYGdsjM3z1crhQlUzpKqncrzwqbzPuAyt2t9Oib/bvjAvbl8gJH7IMRDl9RVgGYkApdkXVqgjSYigTH" + - "TEWxCEgnrfu/YzEkO6l3rXAgMBAAE=").decodeBase64()!! - val privateKeyBytes = ("MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAICkUeG2stqfbyr6gyiVm" + - "5pN9YEDRXlowi+rfYGyWhC7ouW9fXAnhgShQKMOU862mG3tcttSYGdsjM3z1crhQlUzpKqncrzwqbzPuAyt2t9Oi" + - "b/bvjAvbl8gJH7IMRDl9RVgGYkApdkXVqgjSYigTHTEWxCEgnrfu/YzEkO6l3rXAgMBAAECgYB99mhnB6piADOud" + - "dXv626NzUBTr4xbsYRTgSxHzwf50oFTTBSDuW+1IOBVyTWu94SSPyt0LllPbC8Di3sQSTnVGpSqAvEXknBMzIc0U" + - "O74Rn9p3gZjEenPt1l77fIBa2nK06/rdsJCoE/1P1JSfM9w7LU1RsTmseYMLeJl5F79gQJBAO/BbAKqg1yzK7Vij" + - "ygvBoUrr+rt2lbmKgcUQ/rxu8IIQk0M/xgJqSkXDXuOnboGM7sQSKfJAZUtT7xozvLzV7ECQQCJW59w7NIM0qZ/g" + - "IX2gcNZr1B/V3zcGlolTDciRm+fnKGNt2EEDKnVL3swzbEfTCa48IT0QKgZJqpXZERa26UHAkBLXmiP5f5pk8F3w" + - "cXzAeVw06z3k1IB41Tu6MX+CyPU+TeudRlz+wV8b0zDvK+EnRKCCbptVFj1Bkt8lQ4JfcnhAkAk2Y3Gz+HySrkcT" + - "7Cg12M/NkdUQnZe3jr88pt/+IGNwomc6Wt/mJ4fcWONTkGMcfOZff1NQeNXDAZ6941XCsIVAkASOg02PlVHLidU7" + - "mIE65swMM5/RNhS4aFjez/MwxFNOHaxc9VgCwYPXCLOtdf7AVovdyG0XWgbUXH+NyxKwboE").decodeBase64()!! - - val x509PublicKey = encodeKey( + val publicKeyBytes = + ( + "MIGJAoGBAICkUeG2stqfbyr6gyiVm5pN9YEDRXlowi+rfYGyWhC7ouW9fXAnhgShQKMOU8" + + "62mG3tcttSYGdsjM3z1crhQlUzpKqncrzwqbzPuAyt2t9Oib/bvjAvbl8gJH7IMRDl9RVgGYkApdkXVqgjSYigTH" + + "TEWxCEgnrfu/YzEkO6l3rXAgMBAAE=" + ).decodeBase64()!! + val privateKeyBytes = + ( + "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAICkUeG2stqfbyr6gyiVm" + + "5pN9YEDRXlowi+rfYGyWhC7ouW9fXAnhgShQKMOU862mG3tcttSYGdsjM3z1crhQlUzpKqncrzwqbzPuAyt2t9Oi" + + "b/bvjAvbl8gJH7IMRDl9RVgGYkApdkXVqgjSYigTHTEWxCEgnrfu/YzEkO6l3rXAgMBAAECgYB99mhnB6piADOud" + + "dXv626NzUBTr4xbsYRTgSxHzwf50oFTTBSDuW+1IOBVyTWu94SSPyt0LllPbC8Di3sQSTnVGpSqAvEXknBMzIc0U" + + "O74Rn9p3gZjEenPt1l77fIBa2nK06/rdsJCoE/1P1JSfM9w7LU1RsTmseYMLeJl5F79gQJBAO/BbAKqg1yzK7Vij" + + "ygvBoUrr+rt2lbmKgcUQ/rxu8IIQk0M/xgJqSkXDXuOnboGM7sQSKfJAZUtT7xozvLzV7ECQQCJW59w7NIM0qZ/g" + + "IX2gcNZr1B/V3zcGlolTDciRm+fnKGNt2EEDKnVL3swzbEfTCa48IT0QKgZJqpXZERa26UHAkBLXmiP5f5pk8F3w" + + "cXzAeVw06z3k1IB41Tu6MX+CyPU+TeudRlz+wV8b0zDvK+EnRKCCbptVFj1Bkt8lQ4JfcnhAkAk2Y3Gz+HySrkcT" + + "7Cg12M/NkdUQnZe3jr88pt/+IGNwomc6Wt/mJ4fcWONTkGMcfOZff1NQeNXDAZ6941XCsIVAkASOg02PlVHLidU7" + + "mIE65swMM5/RNhS4aFjez/MwxFNOHaxc9VgCwYPXCLOtdf7AVovdyG0XWgbUXH+NyxKwboE" + ).decodeBase64()!! + + val x509PublicKey = + encodeKey( algorithm = RSA_ENCRYPTION, - publicKeyBytes = publicKeyBytes - ) + publicKeyBytes = publicKeyBytes, + ) val keyFactory = KeyFactory.getInstance("RSA") val publicKey = keyFactory.generatePublic(X509EncodedKeySpec(x509PublicKey.toByteArray())) val privateKey = keyFactory.generatePrivate(PKCS8EncodedKeySpec(privateKeyBytes.toByteArray())) - val certificate = HeldCertificate.Builder() + val certificate = + HeldCertificate.Builder() .keyPair(publicKey, privateKey) .build() val certificateByteString = certificate.certificate.encoded.toByteString() - val okHttpCertificate = CertificateAdapters.certificate + val okHttpCertificate = + CertificateAdapters.certificate .fromDer(certificateByteString) assertThat(okHttpCertificate.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey) - .isEqualTo(BitString(publicKeyBytes, 0)) + .isEqualTo(BitString(publicKeyBytes, 0)) } @Test fun `time before 2050 uses UTC_TIME`() { @@ -767,13 +874,16 @@ internal class DerCertificatesTest { @Test fun `reencode golden EC certificate`() { - val certificateByteString = ("MIIBkjCCATmgAwIBAgIBETAKBggqhkjOPQQDAjAwMRYwFAYDVQQLDA1HZW5lIFJ" + - "lc2VhcmNoMRYwFAYDVQQDDA1KdXJhc3NpYyBQYXJrMB4XDTY5MTIzMTIzNTk1OVoXDTcwMDEwMTAwMDAwMlowMDE" + - "WMBQGA1UECwwNR2VuZSBSZXNlYXJjaDEWMBQGA1UEAwwNSnVyYXNzaWMgUGFyazBZMBMGByqGSM49AgEGCCqGSM4" + - "9AwEHA0IABKzhiMzpN+BkUSPLIKItu6O2iao2Pd7dxrvPdIs4xv9/2tPCVgUxevZ27qRcqZOnSd31ZP6B04vkXag" + - "/awy2/iujRDBCMBIGA1UdEwEB/wQIMAYBAf8CAQMwLAYDVR0RAQH/BCIwIIINKi5leGFtcGxlLmNvbYIPd3d3LmV" + - "4YW1wbGUub3JnMAoGCCqGSM49BAMCA0cAMEQCIHzutN/uzViLBXZ0slMqO5oz7ghgBgDbgo2ZyroVeQ/KAiB6Vqo" + - "QXETXce4IZyv3mwGWYePlXU2yMXtezbNluXqUxQ==").decodeBase64()!! + val certificateByteString = + ( + "MIIBkjCCATmgAwIBAgIBETAKBggqhkjOPQQDAjAwMRYwFAYDVQQLDA1HZW5lIFJ" + + "lc2VhcmNoMRYwFAYDVQQDDA1KdXJhc3NpYyBQYXJrMB4XDTY5MTIzMTIzNTk1OVoXDTcwMDEwMTAwMDAwMlowMDE" + + "WMBQGA1UECwwNR2VuZSBSZXNlYXJjaDEWMBQGA1UEAwwNSnVyYXNzaWMgUGFyazBZMBMGByqGSM49AgEGCCqGSM4" + + "9AwEHA0IABKzhiMzpN+BkUSPLIKItu6O2iao2Pd7dxrvPdIs4xv9/2tPCVgUxevZ27qRcqZOnSd31ZP6B04vkXag" + + "/awy2/iujRDBCMBIGA1UdEwEB/wQIMAYBAf8CAQMwLAYDVR0RAQH/BCIwIIINKi5leGFtcGxlLmNvbYIPd3d3LmV" + + "4YW1wbGUub3JnMAoGCCqGSM49BAMCA0cAMEQCIHzutN/uzViLBXZ0slMqO5oz7ghgBgDbgo2ZyroVeQ/KAiB6Vqo" + + "QXETXce4IZyv3mwGWYePlXU2yMXtezbNluXqUxQ==" + ).decodeBase64()!! val decoded = CertificateAdapters.certificate.fromDer(certificateByteString) val encoded = CertificateAdapters.certificate.toDer(decoded) @@ -783,19 +893,22 @@ internal class DerCertificatesTest { @Test fun `reencode golden RSA certificate`() { - val certificateByteString = ("MIIDHzCCAgegAwIBAgIBETANBgkqhkiG9w0BAQsFADAwMRYwFAYDVQQLDA1HZW5" + - "lIFJlc2VhcmNoMRYwFAYDVQQDDA1KdXJhc3NpYyBQYXJrMB4XDTY5MTIzMTIzNTk1OVoXDTcwMDEwMTAwMDAwMlo" + - "wMDEWMBQGA1UECwwNR2VuZSBSZXNlYXJjaDEWMBQGA1UEAwwNSnVyYXNzaWMgUGFyazCCASIwDQYJKoZIhvcNAQE" + - "BBQADggEPADCCAQoCggEBAMfROxfCzmxIX5bDSZt6hstXALVeiywFFzTLW5UI0eKSDCliojmiKBcGR5ln7gVe6/t" + - "me35J9n+Xe5LLmRogMo1CxCoyJxuDX4RrTpPGSepJCrvsBaMA7bQXc/9SbckPF4DYGbE5j3L6IyFU++8RKep/xjc" + - "FAK4yhEgriDh7Gb+sbG6Mv2qTO4p6TR9WhMKXhMgHdk1JYyaSsJ+tSruKiPVmMAcQLBWgNez6MUIC1WVDyvCvfXI" + - "pgsxosVCMtEDSllYe2lVta5tq1RkyzrvkazMEROK+0CVTfg8CadyBn83WTdWRsAX3qiwng8fQU3R4D9HuF/monfH" + - "XuHsr53J+6v8CAwEAAaNEMEIwEgYDVR0TAQH/BAgwBgEB/wIBAzAsBgNVHREBAf8EIjAggg0qLmV4YW1wbGUuY29" + - "tgg93d3cuZXhhbXBsZS5vcmcwDQYJKoZIhvcNAQELBQADggEBAC/+HbZBfVzazPARyI90ot3wzyEmCnXEotNhyl3" + - "0QHZ6UGtJwvVBqY187xg9whytqdMFmadCp8FQT/dLRUn27gtQLOju4FfA3yetJ5oWjbgkaAr7YGP7Auz3o+w51aa" + - "YpseFTZ/zABwnADSiHCIl35TGZJa1XOl32+RWn9VhT92zm3R12FMBovpMFaDckSJAi0jhMHm/QsFK66V0DZxdvl9" + - "LX/UI7q870lojkolCmDJfftAnd2eazoY/O3TqP/duRH522U+C42nXRg9y0CFgzVWmee4EzsCHhkeHUDbsijgSHd4" + - "vjraGi943vN59SjQrflkISUnOqChOaWP0oSztRUA=").decodeBase64()!! + val certificateByteString = + ( + "MIIDHzCCAgegAwIBAgIBETANBgkqhkiG9w0BAQsFADAwMRYwFAYDVQQLDA1HZW5" + + "lIFJlc2VhcmNoMRYwFAYDVQQDDA1KdXJhc3NpYyBQYXJrMB4XDTY5MTIzMTIzNTk1OVoXDTcwMDEwMTAwMDAwMlo" + + "wMDEWMBQGA1UECwwNR2VuZSBSZXNlYXJjaDEWMBQGA1UEAwwNSnVyYXNzaWMgUGFyazCCASIwDQYJKoZIhvcNAQE" + + "BBQADggEPADCCAQoCggEBAMfROxfCzmxIX5bDSZt6hstXALVeiywFFzTLW5UI0eKSDCliojmiKBcGR5ln7gVe6/t" + + "me35J9n+Xe5LLmRogMo1CxCoyJxuDX4RrTpPGSepJCrvsBaMA7bQXc/9SbckPF4DYGbE5j3L6IyFU++8RKep/xjc" + + "FAK4yhEgriDh7Gb+sbG6Mv2qTO4p6TR9WhMKXhMgHdk1JYyaSsJ+tSruKiPVmMAcQLBWgNez6MUIC1WVDyvCvfXI" + + "pgsxosVCMtEDSllYe2lVta5tq1RkyzrvkazMEROK+0CVTfg8CadyBn83WTdWRsAX3qiwng8fQU3R4D9HuF/monfH" + + "XuHsr53J+6v8CAwEAAaNEMEIwEgYDVR0TAQH/BAgwBgEB/wIBAzAsBgNVHREBAf8EIjAggg0qLmV4YW1wbGUuY29" + + "tgg93d3cuZXhhbXBsZS5vcmcwDQYJKoZIhvcNAQELBQADggEBAC/+HbZBfVzazPARyI90ot3wzyEmCnXEotNhyl3" + + "0QHZ6UGtJwvVBqY187xg9whytqdMFmadCp8FQT/dLRUn27gtQLOju4FfA3yetJ5oWjbgkaAr7YGP7Auz3o+w51aa" + + "YpseFTZ/zABwnADSiHCIl35TGZJa1XOl32+RWn9VhT92zm3R12FMBovpMFaDckSJAi0jhMHm/QsFK66V0DZxdvl9" + + "LX/UI7q870lojkolCmDJfftAnd2eazoY/O3TqP/duRH522U+C42nXRg9y0CFgzVWmee4EzsCHhkeHUDbsijgSHd4" + + "vjraGi943vN59SjQrflkISUnOqChOaWP0oSztRUA=" + ).decodeBase64()!! val decoded = CertificateAdapters.certificate.fromDer(certificateByteString) val encoded = CertificateAdapters.certificate.toDer(decoded) @@ -805,16 +918,19 @@ internal class DerCertificatesTest { @Test fun `private key info`() { - val privateKeyInfoByteString = ("MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAICkUeG2stqf" + - "byr6gyiVm5pN9YEDRXlowi+rfYGyWhC7ouW9fXAnhgShQKMOU862mG3tcttSYGdsjM3z1crhQlUzpKqncrzwqbzP" + - "uAyt2t9Oib/bvjAvbl8gJH7IMRDl9RVgGYkApdkXVqgjSYigTHTEWxCEgnrfu/YzEkO6l3rXAgMBAAECgYB99mhn" + - "B6piADOuddXv626NzUBTr4xbsYRTgSxHzwf50oFTTBSDuW+1IOBVyTWu94SSPyt0LllPbC8Di3sQSTnVGpSqAvEX" + - "knBMzIc0UO74Rn9p3gZjEenPt1l77fIBa2nK06/rdsJCoE/1P1JSfM9w7LU1RsTmseYMLeJl5F79gQJBAO/BbAKq" + - "g1yzK7VijygvBoUrr+rt2lbmKgcUQ/rxu8IIQk0M/xgJqSkXDXuOnboGM7sQSKfJAZUtT7xozvLzV7ECQQCJW59w" + - "7NIM0qZ/gIX2gcNZr1B/V3zcGlolTDciRm+fnKGNt2EEDKnVL3swzbEfTCa48IT0QKgZJqpXZERa26UHAkBLXmiP" + - "5f5pk8F3wcXzAeVw06z3k1IB41Tu6MX+CyPU+TeudRlz+wV8b0zDvK+EnRKCCbptVFj1Bkt8lQ4JfcnhAkAk2Y3G" + - "z+HySrkcT7Cg12M/NkdUQnZe3jr88pt/+IGNwomc6Wt/mJ4fcWONTkGMcfOZff1NQeNXDAZ6941XCsIVAkASOg02" + - "PlVHLidU7mIE65swMM5/RNhS4aFjez/MwxFNOHaxc9VgCwYPXCLOtdf7AVovdyG0XWgbUXH+NyxKwboE") + val privateKeyInfoByteString = + ( + "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAICkUeG2stqf" + + "byr6gyiVm5pN9YEDRXlowi+rfYGyWhC7ouW9fXAnhgShQKMOU862mG3tcttSYGdsjM3z1crhQlUzpKqncrzwqbzP" + + "uAyt2t9Oib/bvjAvbl8gJH7IMRDl9RVgGYkApdkXVqgjSYigTHTEWxCEgnrfu/YzEkO6l3rXAgMBAAECgYB99mhn" + + "B6piADOuddXv626NzUBTr4xbsYRTgSxHzwf50oFTTBSDuW+1IOBVyTWu94SSPyt0LllPbC8Di3sQSTnVGpSqAvEX" + + "knBMzIc0UO74Rn9p3gZjEenPt1l77fIBa2nK06/rdsJCoE/1P1JSfM9w7LU1RsTmseYMLeJl5F79gQJBAO/BbAKq" + + "g1yzK7VijygvBoUrr+rt2lbmKgcUQ/rxu8IIQk0M/xgJqSkXDXuOnboGM7sQSKfJAZUtT7xozvLzV7ECQQCJW59w" + + "7NIM0qZ/gIX2gcNZr1B/V3zcGlolTDciRm+fnKGNt2EEDKnVL3swzbEfTCa48IT0QKgZJqpXZERa26UHAkBLXmiP" + + "5f5pk8F3wcXzAeVw06z3k1IB41Tu6MX+CyPU+TeudRlz+wV8b0zDvK+EnRKCCbptVFj1Bkt8lQ4JfcnhAkAk2Y3G" + + "z+HySrkcT7Cg12M/NkdUQnZe3jr88pt/+IGNwomc6Wt/mJ4fcWONTkGMcfOZff1NQeNXDAZ6941XCsIVAkASOg02" + + "PlVHLidU7mIE65swMM5/RNhS4aFjez/MwxFNOHaxc9VgCwYPXCLOtdf7AVovdyG0XWgbUXH+NyxKwboE" + ) .decodeBase64()!! val decoded = CertificateAdapters.privateKeyInfo.fromDer(privateKeyInfoByteString) @@ -829,11 +945,13 @@ internal class DerCertificatesTest { @Test fun `RSA issuer and signature`() { - val root = HeldCertificate.Builder() + val root = + HeldCertificate.Builder() .certificateAuthority(0) .rsa2048() .build() - val certificate = HeldCertificate.Builder() + val certificate = + HeldCertificate.Builder() .signedBy(root) .rsa2048() .build() @@ -841,17 +959,20 @@ internal class DerCertificatesTest { val certificateByteString = certificate.certificate.encoded.toByteString() // Valid signature. - val okHttpCertificate = CertificateAdapters.certificate + val okHttpCertificate = + CertificateAdapters.certificate .fromDer(certificateByteString) println(okHttpCertificate) assertThat(okHttpCertificate.checkSignature(root.keyPair.public)).isTrue() // Invalid signature. - val okHttpCertificateWithBadSignature = okHttpCertificate.copy( - signatureValue = okHttpCertificate.signatureValue.copy( - byteString = okHttpCertificate.signatureValue.byteString.offByOneBit() - ) - ) + val okHttpCertificateWithBadSignature = + okHttpCertificate.copy( + signatureValue = + okHttpCertificate.signatureValue.copy( + byteString = okHttpCertificate.signatureValue.byteString.offByOneBit(), + ), + ) assertThat(okHttpCertificateWithBadSignature.checkSignature(root.keyPair.public)).isFalse() // Wrong public key. @@ -860,11 +981,13 @@ internal class DerCertificatesTest { @Test fun `EC issuer and signature`() { - val root = HeldCertificate.Builder() + val root = + HeldCertificate.Builder() .certificateAuthority(0) .ecdsa256() .build() - val certificate = HeldCertificate.Builder() + val certificate = + HeldCertificate.Builder() .signedBy(root) .ecdsa256() .build() @@ -872,16 +995,19 @@ internal class DerCertificatesTest { val certificateByteString = certificate.certificate.encoded.toByteString() // Valid signature. - val okHttpCertificate = CertificateAdapters.certificate + val okHttpCertificate = + CertificateAdapters.certificate .fromDer(certificateByteString) assertThat(okHttpCertificate.checkSignature(root.keyPair.public)).isTrue() // Invalid signature. - val okHttpCertificateWithBadSignature = okHttpCertificate.copy( - signatureValue = okHttpCertificate.signatureValue.copy( - byteString = okHttpCertificate.signatureValue.byteString.offByOneBit() - ) - ) + val okHttpCertificateWithBadSignature = + okHttpCertificate.copy( + signatureValue = + okHttpCertificate.signatureValue.copy( + byteString = okHttpCertificate.signatureValue.byteString.offByOneBit(), + ), + ) assertThat(okHttpCertificateWithBadSignature.checkSignature(root.keyPair.public)).isFalse() // Wrong public key. @@ -894,59 +1020,70 @@ internal class DerCertificatesTest { */ @Test fun `unsupported general name tag`() { - val certificateByteString = ("MIIFEDCCA/igAwIBAgIRAJK4dE9xztDibHKj2NXZJbIwDQYJKoZIhvcNAQELBQA" + - "wSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmV" + - "UcnVzdCBDQTAeFw0xNjA5MDExNDM1MzVaFw0yNDA5MjkxNDM1MzVaMIG1MQswCQYDVQQGEwJVUzERMA8GA1UECBM" + - "ISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE9MDs" + - "GA1UEAxM0VHJ1c3R3YXZlIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIFNIQTI1NiBDQSwgTGV2ZWwgMTEfMB0GCSq" + - "GSIb3DQEJARYQY2FAdHJ1c3R3YXZlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPTqIZSRwS" + - "f47okE5omzktvKR7wgqdWzznOnpUOtgwmBPwNeCV1LSPMmlHPZxY4enTc0eyoxTxKv6g6ZUJe39U74eYnwTTT9sE" + - "OnvNtE1pTzuB4Uf+YOPt4hZidTe5Ba8Q6dfz/Ht/vZXCbF3JFwrXxZEPbJaICap2grIqYHax+IEIYnBQC+WKh8Ng" + - "Cn3LWS0j6cYSN8SEjFf5SEMGT1iNtttb/QC3JKJIeaVunUyvMfMjVFMntc7eZrFs6rp3wY1WFVI+fy17uOoUvfTH" + - "8bvNAESUch7FyLh2zM8FVxqilT2XygHRwZeXtxJQozcDcvh4ItPb0uz6AFIYwn/8Gzp0CAwEAAaOCAYUwggGBMBI" + - "GA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFMrOHRgDdx4c83xYsppwqAiAFvSuMA4GA1UdDwEB/wQEAwIBhjA" + - "yBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnRydXN0d2F2ZS5jb20vU1RDQS5jcmwwPQYDVR0gBDYwNDAyBgR" + - "VHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vc3NsLnRydXN0d2F2ZS5jb20vQ0EwbAYIKwYBBQUHAQEEYDBeMCU" + - "GCCsGAQUFBzABhhlodHRwOi8vb2NzcC50cnVzdHdhdmUuY29tMDUGCCsGAQUFBzAChilodHRwOi8vc3NsLnRydXN" + - "0d2F2ZS5jb20vaXNzdWVycy9TVENBLmNydDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwHwYDVR0jBBg" + - "wFoAUQjK2FvoE/f5dS3rD/fdMQB1aQ68wGwYDVR0RBBQwEoEQY2FAdHJ1c3R3YXZlLmNvbTANBgkqhkiG9w0BAQs" + - "FAAOCAQEAC0OvN7/UJBcRDXchA4b2qJo7mBD05+XR96N7vucMaanz26CnUxs1o8DcBckpqyEXCxdOanIr+/UJNbB" + - "LXLJCzNLJEJcgV9TjbVu33eQR23yMuXD+cZsqLMF+L5IIM47W8dlwKJvMy0xs7Jb1S3NOIhcoVu+XPzRsgKv8Yi2" + - "B6l278RfzegiCx4vYJv0pBjFzizEiFH9bWTYIOlIJJSM57hoICgjCTS8BoEgndwWIyc/nEmlYaUwmCo9QynY+UmW" + - "1WPWmVITEJPMdMK6AZqvvaWmuHJ6/vURaz+Hoc5D3z0yJDDCkv52bXV04ZoF6cbcWry7JvNA+djvay/4BRR4SZQ==") + val certificateByteString = + ( + "MIIFEDCCA/igAwIBAgIRAJK4dE9xztDibHKj2NXZJbIwDQYJKoZIhvcNAQELBQA" + + "wSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmV" + + "UcnVzdCBDQTAeFw0xNjA5MDExNDM1MzVaFw0yNDA5MjkxNDM1MzVaMIG1MQswCQYDVQQGEwJVUzERMA8GA1UECBM" + + "ISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE9MDs" + + "GA1UEAxM0VHJ1c3R3YXZlIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIFNIQTI1NiBDQSwgTGV2ZWwgMTEfMB0GCSq" + + "GSIb3DQEJARYQY2FAdHJ1c3R3YXZlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPTqIZSRwS" + + "f47okE5omzktvKR7wgqdWzznOnpUOtgwmBPwNeCV1LSPMmlHPZxY4enTc0eyoxTxKv6g6ZUJe39U74eYnwTTT9sE" + + "OnvNtE1pTzuB4Uf+YOPt4hZidTe5Ba8Q6dfz/Ht/vZXCbF3JFwrXxZEPbJaICap2grIqYHax+IEIYnBQC+WKh8Ng" + + "Cn3LWS0j6cYSN8SEjFf5SEMGT1iNtttb/QC3JKJIeaVunUyvMfMjVFMntc7eZrFs6rp3wY1WFVI+fy17uOoUvfTH" + + "8bvNAESUch7FyLh2zM8FVxqilT2XygHRwZeXtxJQozcDcvh4ItPb0uz6AFIYwn/8Gzp0CAwEAAaOCAYUwggGBMBI" + + "GA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFMrOHRgDdx4c83xYsppwqAiAFvSuMA4GA1UdDwEB/wQEAwIBhjA" + + "yBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnRydXN0d2F2ZS5jb20vU1RDQS5jcmwwPQYDVR0gBDYwNDAyBgR" + + "VHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vc3NsLnRydXN0d2F2ZS5jb20vQ0EwbAYIKwYBBQUHAQEEYDBeMCU" + + "GCCsGAQUFBzABhhlodHRwOi8vb2NzcC50cnVzdHdhdmUuY29tMDUGCCsGAQUFBzAChilodHRwOi8vc3NsLnRydXN" + + "0d2F2ZS5jb20vaXNzdWVycy9TVENBLmNydDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwHwYDVR0jBBg" + + "wFoAUQjK2FvoE/f5dS3rD/fdMQB1aQ68wGwYDVR0RBBQwEoEQY2FAdHJ1c3R3YXZlLmNvbTANBgkqhkiG9w0BAQs" + + "FAAOCAQEAC0OvN7/UJBcRDXchA4b2qJo7mBD05+XR96N7vucMaanz26CnUxs1o8DcBckpqyEXCxdOanIr+/UJNbB" + + "LXLJCzNLJEJcgV9TjbVu33eQR23yMuXD+cZsqLMF+L5IIM47W8dlwKJvMy0xs7Jb1S3NOIhcoVu+XPzRsgKv8Yi2" + + "B6l278RfzegiCx4vYJv0pBjFzizEiFH9bWTYIOlIJJSM57hoICgjCTS8BoEgndwWIyc/nEmlYaUwmCo9QynY+UmW" + + "1WPWmVITEJPMdMK6AZqvvaWmuHJ6/vURaz+Hoc5D3z0yJDDCkv52bXV04ZoF6cbcWry7JvNA+djvay/4BRR4SZQ==" + ) .decodeBase64()!! val decoded = CertificateAdapters.certificate.fromDer(certificateByteString) - assertThat(decoded.subjectAlternativeNames).isEqualTo(Extension( + assertThat(decoded.subjectAlternativeNames).isEqualTo( + Extension( id = SUBJECT_ALTERNATIVE_NAME, critical = false, - value = listOf( - Adapters.ANY_VALUE to AnyValue( + value = + listOf( + Adapters.ANY_VALUE to + AnyValue( tagClass = DerHeader.TAG_CLASS_CONTEXT_SPECIFIC, tag = 1L, constructed = false, length = 16, - bytes = "ca@trustwave.com".encodeUtf8() - ) - ) - )) + bytes = "ca@trustwave.com".encodeUtf8(), + ), + ), + ), + ) } /** Converts public key bytes to SubjectPublicKeyInfo bytes. */ - private fun encodeKey(algorithm: String, publicKeyBytes: ByteString): ByteString { - val subjectPublicKeyInfo = SubjectPublicKeyInfo( + private fun encodeKey( + algorithm: String, + publicKeyBytes: ByteString, + ): ByteString { + val subjectPublicKeyInfo = + SubjectPublicKeyInfo( algorithm = AlgorithmIdentifier(algorithm = algorithm, parameters = null), - subjectPublicKey = BitString(publicKeyBytes, 0) - ) + subjectPublicKey = BitString(publicKeyBytes, 0), + ) return CertificateAdapters.subjectPublicKeyInfo.toDer(subjectPublicKeyInfo) } /** Returns a byte string that differs from this one by one bit. */ private fun ByteString.offByOneBit(): ByteString { return Buffer() - .write(this, 0, size - 1) - .writeByte(this[size - 1].toInt() xor 1) - .readByteString() + .write(this, 0, size - 1) + .writeByte(this[size - 1].toInt() xor 1) + .readByteString() } private fun date(s: String): Date { diff --git a/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerTest.kt b/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerTest.kt index aeac49e19a9a..b31be6dccb4a 100644 --- a/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerTest.kt +++ b/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerTest.kt @@ -43,7 +43,8 @@ import org.junit.jupiter.api.Test internal class DerTest { @Test fun `decode tag and length`() { - val buffer = Buffer() + val buffer = + Buffer() .writeByte(0b00011110) .writeByte(0b10000001) .writeByte(0b11001001) @@ -61,7 +62,8 @@ internal class DerTest { } @Test fun `decode length encoded with leading zero byte`() { - val buffer = Buffer() + val buffer = + Buffer() .writeByte(0b00000010) .writeByte(0b10000010) .writeByte(0b00000000) @@ -77,7 +79,8 @@ internal class DerTest { } @Test fun `decode length not encoded in shortest form possible`() { - val buffer = Buffer() + val buffer = + Buffer() .writeByte(0b00000010) .writeByte(0b10000001) .writeByte(0b01111111) @@ -92,7 +95,8 @@ internal class DerTest { } @Test fun `decode length equal to Long MAX_VALUE`() { - val buffer = Buffer() + val buffer = + Buffer() .writeByte(0b00000010) .writeByte(0b10001000) .writeByte(0b01111111) @@ -111,7 +115,8 @@ internal class DerTest { } @Test fun `decode length overflowing Long`() { - val buffer = Buffer() + val buffer = + Buffer() .writeByte(0b00000010) .writeByte(0b10001000) .writeByte(0b10000000) @@ -133,7 +138,8 @@ internal class DerTest { } @Test fun `decode length encoded with more than 8 bytes`() { - val buffer = Buffer() + val buffer = + Buffer() .writeByte(0b00000010) .writeByte(0b10001001) .writeByte(0b11111111) @@ -153,7 +159,7 @@ internal class DerTest { derReader.read("test") {} }.also { expected -> assertThat(expected.message) - .isEqualTo("length encoded with more than 8 bytes is not supported") + .isEqualTo("length encoded with more than 8 bytes is not supported") } } @@ -170,7 +176,8 @@ internal class DerTest { } @Test fun `decode primitive bit string`() { - val buffer = Buffer() + val buffer = + Buffer() .write("0307040A3B5F291CD0".decodeHex()) val derReader = DerReader(buffer) @@ -195,7 +202,8 @@ internal class DerTest { } @Test fun `decode primitive string`() { - val buffer = Buffer() + val buffer = + Buffer() .write("1A054A6F6E6573".decodeHex()) val derReader = DerReader(buffer) @@ -224,7 +232,8 @@ internal class DerTest { @Test fun `decode implicit prefixed type`() { // Type1 ::= VisibleString // Type2 ::= [APPLICATION 3] IMPLICIT Type1 - val buffer = Buffer() + val buffer = + Buffer() .write("43054A6F6E6573".decodeHex()) val derReader = DerReader(buffer) @@ -255,7 +264,8 @@ internal class DerTest { // Type1 ::= VisibleString // Type2 ::= [APPLICATION 3] IMPLICIT Type1 // Type3 ::= [2] Type2 - val buffer = Buffer() + val buffer = + Buffer() .write("A20743054A6F6E6573".decodeHex()) val derReader = DerReader(buffer) @@ -299,7 +309,8 @@ internal class DerTest { // Type2 ::= [APPLICATION 3] IMPLICIT Type1 // Type3 ::= [2] Type2 // Type4 ::= [APPLICATION 7] IMPLICIT Type3 - val buffer = Buffer() + val buffer = + Buffer() .write("670743054A6F6E6573".decodeHex()) val derReader = DerReader(buffer) @@ -343,7 +354,8 @@ internal class DerTest { // Type1 ::= VisibleString // Type2 ::= [APPLICATION 3] IMPLICIT Type1 // Type5 ::= [2] IMPLICIT Type2 - val buffer = Buffer() + val buffer = + Buffer() .write("82054A6F6E6573".decodeHex()) val derReader = DerReader(buffer) @@ -366,9 +378,9 @@ internal class DerTest { val derWriter = DerWriter(buffer) derWriter.write( - name = "test", - tagClass = DerHeader.TAG_CLASS_CONTEXT_SPECIFIC, - tag = 2L + name = "test", + tagClass = DerHeader.TAG_CLASS_CONTEXT_SPECIFIC, + tag = 2L, ) { derWriter.writeOctetString("Jones".encodeUtf8()) } @@ -377,7 +389,8 @@ internal class DerTest { } @Test fun `decode object identifier without adapter`() { - val buffer = Buffer() + val buffer = + Buffer() .write("0603883703".decodeHex()) val derReader = DerReader(buffer) @@ -397,9 +410,9 @@ internal class DerTest { val derWriter = DerWriter(buffer) derWriter.write( - name = "test", - tagClass = DerHeader.TAG_CLASS_UNIVERSAL, - tag = 6L + name = "test", + tagClass = DerHeader.TAG_CLASS_UNIVERSAL, + tag = 6L, ) { derWriter.writeObjectIdentifier("2.999.3") } @@ -408,7 +421,8 @@ internal class DerTest { } @Test fun `decode relative object identifier`() { - val buffer = Buffer() + val buffer = + Buffer() .write("0D04c27B0302".decodeHex()) val derReader = DerReader(buffer) @@ -428,9 +442,9 @@ internal class DerTest { val derWriter = DerWriter(buffer) derWriter.write( - name = "test", - tagClass = DerHeader.TAG_CLASS_UNIVERSAL, - tag = 13L + name = "test", + tagClass = DerHeader.TAG_CLASS_UNIVERSAL, + tag = 13L, ) { derWriter.writeRelativeObjectIdentifier("8571.3.2") } @@ -439,7 +453,8 @@ internal class DerTest { } @Test fun `decode raw sequence`() { - val buffer = Buffer() + val buffer = + Buffer() .write("300A".decodeHex()) .write("1505".decodeHex()) .write("Smith".encodeUtf8()) @@ -473,23 +488,22 @@ internal class DerTest { val derWriter = DerWriter(buffer) derWriter.write( - name = "test", - tagClass = DerHeader.TAG_CLASS_UNIVERSAL, - tag = 16L + name = "test", + tagClass = DerHeader.TAG_CLASS_UNIVERSAL, + tag = 16L, ) { - derWriter.write( - name = "test", - tagClass = DerHeader.TAG_CLASS_UNIVERSAL, - tag = 21L + name = "test", + tagClass = DerHeader.TAG_CLASS_UNIVERSAL, + tag = 21L, ) { derWriter.writeOctetString("Smith".encodeUtf8()) } derWriter.write( - name = "test", - tagClass = DerHeader.TAG_CLASS_UNIVERSAL, - tag = 1L + name = "test", + tagClass = DerHeader.TAG_CLASS_UNIVERSAL, + tag = 1L, ) { derWriter.writeBoolean(true) } @@ -679,62 +693,63 @@ internal class DerTest { @Test fun `parse utc time`() { assertThat(Adapters.parseUtcTime("920521000000Z")) - .isEqualTo(date("1992-05-21T00:00:00.000+0000").time) + .isEqualTo(date("1992-05-21T00:00:00.000+0000").time) assertThat(Adapters.parseUtcTime("920622123421Z")) - .isEqualTo(date("1992-06-22T12:34:21.000+0000").time) + .isEqualTo(date("1992-06-22T12:34:21.000+0000").time) assertThat(Adapters.parseUtcTime("920722132100Z")) - .isEqualTo(date("1992-07-22T13:21:00.000+0000").time) + .isEqualTo(date("1992-07-22T13:21:00.000+0000").time) } @Test fun `decode utc time two digit year cutoff is 1950`() { assertThat(Adapters.parseUtcTime("500101000000Z")) - .isEqualTo(date("1950-01-01T00:00:00.000+0000").time) + .isEqualTo(date("1950-01-01T00:00:00.000+0000").time) assertThat(Adapters.parseUtcTime("500101010000Z")) - .isEqualTo(date("1950-01-01T01:00:00.000+0000").time) + .isEqualTo(date("1950-01-01T01:00:00.000+0000").time) assertThat(Adapters.parseUtcTime("491231225959Z")) - .isEqualTo(date("2049-12-31T22:59:59.000+0000").time) + .isEqualTo(date("2049-12-31T22:59:59.000+0000").time) assertThat(Adapters.parseUtcTime("491231235959Z")) - .isEqualTo(date("2049-12-31T23:59:59.000+0000").time) + .isEqualTo(date("2049-12-31T23:59:59.000+0000").time) } @Test fun `encode utc time two digit year cutoff is 1950`() { assertThat(Adapters.formatUtcTime(date("1950-01-01T00:00:00.000+0000").time)) - .isEqualTo("500101000000Z") + .isEqualTo("500101000000Z") assertThat(Adapters.formatUtcTime(date("2049-12-31T23:59:59.000+0000").time)) - .isEqualTo("491231235959Z") + .isEqualTo("491231235959Z") } @Test fun `parse generalized time`() { assertThat(Adapters.parseGeneralizedTime("18990101000000Z")) - .isEqualTo(date("1899-01-01T00:00:00.000+0000").time) + .isEqualTo(date("1899-01-01T00:00:00.000+0000").time) assertThat(Adapters.parseGeneralizedTime("19500101000000Z")) - .isEqualTo(date("1950-01-01T00:00:00.000+0000").time) + .isEqualTo(date("1950-01-01T00:00:00.000+0000").time) assertThat(Adapters.parseGeneralizedTime("20500101000000Z")) - .isEqualTo(date("2050-01-01T00:00:00.000+0000").time) + .isEqualTo(date("2050-01-01T00:00:00.000+0000").time) assertThat(Adapters.parseGeneralizedTime("20990101000000Z")) - .isEqualTo(date("2099-01-01T00:00:00.000+0000").time) + .isEqualTo(date("2099-01-01T00:00:00.000+0000").time) assertThat(Adapters.parseGeneralizedTime("19920521000000Z")) - .isEqualTo(date("1992-05-21T00:00:00.000+0000").time) + .isEqualTo(date("1992-05-21T00:00:00.000+0000").time) assertThat(Adapters.parseGeneralizedTime("19920622123421Z")) - .isEqualTo(date("1992-06-22T12:34:21.000+0000").time) + .isEqualTo(date("1992-06-22T12:34:21.000+0000").time) } @Disabled("fractional seconds are not implemented") - @Test fun `parse generalized time with fractional seconds`() { + @Test + fun `parse generalized time with fractional seconds`() { assertThat(Adapters.parseGeneralizedTime("19920722132100.3Z")) - .isEqualTo(date("1992-07-22T13:21:00.300+0000").time) + .isEqualTo(date("1992-07-22T13:21:00.300+0000").time) } @Test fun `format generalized time`() { assertThat(Adapters.formatGeneralizedTime(date("1899-01-01T00:00:00.000+0000").time)) - .isEqualTo("18990101000000Z") + .isEqualTo("18990101000000Z") assertThat(Adapters.formatGeneralizedTime(date("1950-01-01T00:00:00.000+0000").time)) - .isEqualTo("19500101000000Z") + .isEqualTo("19500101000000Z") assertThat(Adapters.formatGeneralizedTime(date("2050-01-01T00:00:00.000+0000").time)) - .isEqualTo("20500101000000Z") + .isEqualTo("20500101000000Z") assertThat(Adapters.formatGeneralizedTime(date("2099-01-01T00:00:00.000+0000").time)) - .isEqualTo("20990101000000Z") + .isEqualTo("20990101000000Z") } @Test fun `decode object identifier`() { @@ -751,14 +766,15 @@ internal class DerTest { @Test fun `sequence algorithm`() { val bytes = "300d06092a864886f70d01010b0500".decodeHex() - val algorithmIdentifier = AlgorithmIdentifier( + val algorithmIdentifier = + AlgorithmIdentifier( algorithm = SHA256_WITH_RSA_ENCRYPTION, - parameters = null - ) + parameters = null, + ) assertThat(CertificateAdapters.algorithmIdentifier.fromDer(bytes)) - .isEqualTo(algorithmIdentifier) + .isEqualTo(algorithmIdentifier) assertThat(CertificateAdapters.algorithmIdentifier.toDer(algorithmIdentifier)) - .isEqualTo(bytes) + .isEqualTo(bytes) } @Test fun `bit string`() { @@ -788,7 +804,7 @@ internal class DerTest { @Test fun `cannot decode constructed octet string`() { assertFailsWith { Adapters.OCTET_STRING.fromDer( - "2410040668656c6c6f200406776f726c6421".decodeHex() + "2410040668656c6c6f200406776f726c6421".decodeHex(), ) }.also { expected -> assertThat(expected).hasMessage("constructed octet strings not supported for DER") @@ -798,7 +814,7 @@ internal class DerTest { @Test fun `cannot decode constructed bit string`() { assertFailsWith { Adapters.BIT_STRING.fromDer( - "231203070068656c6c6f20030700776f726c6421".decodeHex() + "231203070068656c6c6f20030700776f726c6421".decodeHex(), ) }.also { expected -> assertThat(expected).hasMessage("constructed bit strings not supported for DER") @@ -808,7 +824,8 @@ internal class DerTest { @Test fun `cannot decode constructed string`() { assertFailsWith { Adapters.UTF8_STRING.fromDer( - "2c100c0668656c6c6f200c06776f726c6421".decodeHex()) + "2c100c0668656c6c6f200c06776f726c6421".decodeHex(), + ) }.also { expected -> assertThat(expected).hasMessage("constructed strings not supported for DER") } @@ -817,14 +834,16 @@ internal class DerTest { @Test fun `cannot decode indefinite length bit string`() { assertFailsWith { Adapters.BIT_STRING.fromDer( - "23800303000A3B0305045F291CD00000".decodeHex()) + "23800303000A3B0305045F291CD00000".decodeHex(), + ) }.also { expected -> assertThat(expected).hasMessage("indefinite length not permitted for DER") } } @Test fun `cannot decode constructed octet string in enclosing sequence`() { - val buffer = Buffer() + val buffer = + Buffer() .write("3A0904034A6F6E04026573".decodeHex()) val derReader = DerReader(buffer) assertFailsWith { @@ -840,63 +859,66 @@ internal class DerTest { val bytes = "8704c0a80201".decodeHex() val localhost = InetAddress.getByName("192.168.2.1").address.toByteString() assertThat(CertificateAdapters.generalName.fromDer(bytes)) - .isEqualTo(generalNameIpAddress to localhost) + .isEqualTo(generalNameIpAddress to localhost) assertThat(CertificateAdapters.generalName.toDer(generalNameIpAddress to localhost)) - .isEqualTo(bytes) + .isEqualTo(bytes) } @Test fun `choice dns`() { val bytes = "820b6578616d706c652e636f6d".decodeHex() assertThat(CertificateAdapters.generalName.fromDer(bytes)) - .isEqualTo(generalNameDnsName to "example.com") + .isEqualTo(generalNameDnsName to "example.com") assertThat(CertificateAdapters.generalName.toDer(generalNameDnsName to "example.com")) - .isEqualTo(bytes) + .isEqualTo(bytes) } @Test fun `extension with type hint for basic constraints`() { - val extension = Extension( + val extension = + Extension( BASIC_CONSTRAINTS, false, - BasicConstraints(true, 4) - ) + BasicConstraints(true, 4), + ) val bytes = "300f0603551d13040830060101ff020104".decodeHex() assertThat(CertificateAdapters.extension.toDer(extension)) - .isEqualTo(bytes) + .isEqualTo(bytes) assertThat(CertificateAdapters.extension.fromDer(bytes)) - .isEqualTo(extension) + .isEqualTo(extension) } @Test fun `extension with type hint for subject alternative names`() { - val extension = Extension( + val extension = + Extension( SUBJECT_ALTERNATIVE_NAME, false, listOf( - generalNameDnsName to "cash.app", - generalNameDnsName to "www.cash.app" - ) - ) + generalNameDnsName to "cash.app", + generalNameDnsName to "www.cash.app", + ), + ) val bytes = "30210603551d11041a30188208636173682e617070820c7777772e636173682e617070".decodeHex() assertThat(CertificateAdapters.extension.toDer(extension)) - .isEqualTo(bytes) + .isEqualTo(bytes) assertThat(CertificateAdapters.extension.fromDer(bytes)) - .isEqualTo(extension) + .isEqualTo(extension) } @Test fun `extension with unknown type hint`() { - val extension = Extension( + val extension = + Extension( // common name is not an extension. COMMON_NAME, false, - "3006800109810109".decodeHex() - ) + "3006800109810109".decodeHex(), + ) val bytes = "300f060355040304083006800109810109".decodeHex() assertThat(CertificateAdapters.extension.toDer(extension)) - .isEqualTo(bytes) + .isEqualTo(bytes) assertThat(CertificateAdapters.extension.fromDer(bytes)) - .isEqualTo(extension) + .isEqualTo(extension) } /** Tags larger than 30 are a special case. */ @@ -938,16 +960,17 @@ internal class DerTest { */ data class Point( val x: Long?, - val y: Long? + val y: Long?, ) { companion object { - val ADAPTER = Adapters.sequence( + val ADAPTER = + Adapters.sequence( "Point", Adapters.INTEGER_AS_LONG.withTag(tag = 0L).optional(), Adapters.INTEGER_AS_LONG.withTag(tag = 1L).optional(), decompose = { listOf(it.x, it.y) }, - construct = { Point(it[0] as Long?, it[1] as Long?) } - ) + construct = { Point(it[0] as Long?, it[1] as Long?) }, + ) } } diff --git a/okhttp-urlconnection/src/main/kotlin/okhttp3/JavaNetAuthenticator.kt b/okhttp-urlconnection/src/main/kotlin/okhttp3/JavaNetAuthenticator.kt index c6157b75a144..42e17efca23d 100644 --- a/okhttp-urlconnection/src/main/kotlin/okhttp3/JavaNetAuthenticator.kt +++ b/okhttp-urlconnection/src/main/kotlin/okhttp3/JavaNetAuthenticator.kt @@ -32,6 +32,8 @@ import okhttp3.Authenticator.Companion.JAVA_NET_AUTHENTICATOR @Deprecated(message = "Use okhttp3.Authenticator.Companion.JAVA_NET_AUTHENTICATOR instead") class JavaNetAuthenticator : Authenticator { @Throws(IOException::class) - override fun authenticate(route: Route?, response: Response): Request? = - JAVA_NET_AUTHENTICATOR.authenticate(route, response) + override fun authenticate( + route: Route?, + response: Response, + ): Request? = JAVA_NET_AUTHENTICATOR.authenticate(route, response) } diff --git a/okhttp-urlconnection/src/main/kotlin/okhttp3/JavaNetCookieJar.kt b/okhttp-urlconnection/src/main/kotlin/okhttp3/JavaNetCookieJar.kt index 49f17a5037fd..e9d1b3c4b483 100644 --- a/okhttp-urlconnection/src/main/kotlin/okhttp3/JavaNetCookieJar.kt +++ b/okhttp-urlconnection/src/main/kotlin/okhttp3/JavaNetCookieJar.kt @@ -32,7 +32,7 @@ class JavaNetCookieJar private constructor( ) : CookieJar by delegate { constructor(cookieHandler: CookieHandler) : this( okhttp3.java.net.cookiejar.JavaNetCookieJar( - cookieHandler - ) + cookieHandler, + ), ) } diff --git a/okhttp/src/main/kotlin/okhttp3/-JvmPlatform.kt b/okhttp/src/main/kotlin/okhttp3/-JvmPlatform.kt index ca0f158f1d7b..cc00db7c68fa 100644 --- a/okhttp/src/main/kotlin/okhttp3/-JvmPlatform.kt +++ b/okhttp/src/main/kotlin/okhttp3/-JvmPlatform.kt @@ -15,6 +15,7 @@ * */ @file:Suppress("ktlint:standard:filename") + package okhttp3 typealias ProtocolException = java.net.ProtocolException diff --git a/okhttp/src/main/kotlin/okhttp3/Address.kt b/okhttp/src/main/kotlin/okhttp3/Address.kt index 61b5ab557562..dbd589315671 100644 --- a/okhttp/src/main/kotlin/okhttp3/Address.kt +++ b/okhttp/src/main/kotlin/okhttp3/Address.kt @@ -36,42 +36,36 @@ class Address( uriPort: Int, /** Returns the service that will be used to resolve IP addresses for hostnames. */ @get:JvmName("dns") val dns: Dns, - /** Returns the socket factory for new connections. */ @get:JvmName("socketFactory") val socketFactory: SocketFactory, - /** Returns the SSL socket factory, or null if this is not an HTTPS address. */ @get:JvmName("sslSocketFactory") val sslSocketFactory: SSLSocketFactory?, - /** Returns the hostname verifier, or null if this is not an HTTPS address. */ @get:JvmName("hostnameVerifier") val hostnameVerifier: HostnameVerifier?, - /** Returns this address's certificate pinner, or null if this is not an HTTPS address. */ @get:JvmName("certificatePinner") val certificatePinner: CertificatePinner?, - /** Returns the client's proxy authenticator. */ @get:JvmName("proxyAuthenticator") val proxyAuthenticator: Authenticator, - /** * Returns this address's explicitly-specified HTTP proxy, or null to delegate to the * [proxy selector][proxySelector]. */ @get:JvmName("proxy") val proxy: Proxy?, - protocols: List, connectionSpecs: List, - /** * Returns this address's proxy selector. Only used if the proxy is null. If none of this * selector's proxies are reachable, a direct connection will be attempted. */ - @get:JvmName("proxySelector") val proxySelector: ProxySelector + @get:JvmName("proxySelector") val proxySelector: ProxySelector, ) { /** * Returns a URL with the hostname and port of the origin server. The path, query, and fragment of * this URL are always empty, since they are not significant for planning a route. */ - @get:JvmName("url") val url: HttpUrl = HttpUrl.Builder() + @get:JvmName("url") + val url: HttpUrl = + HttpUrl.Builder() .scheme(if (sslSocketFactory != null) "https" else "http") .host(uriHost) .port(uriPort) @@ -81,92 +75,105 @@ class Address( * The protocols the client supports. This method always returns a non-null list that * contains minimally [Protocol.HTTP_1_1]. */ - @get:JvmName("protocols") val protocols: List = protocols.toImmutableList() + @get:JvmName("protocols") + val protocols: List = protocols.toImmutableList() - @get:JvmName("connectionSpecs") val connectionSpecs: List = - connectionSpecs.toImmutableList() + @get:JvmName("connectionSpecs") + val connectionSpecs: List = + connectionSpecs.toImmutableList() @JvmName("-deprecated_url") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "url"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "url"), + level = DeprecationLevel.ERROR, + ) fun url(): HttpUrl = url @JvmName("-deprecated_dns") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "dns"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "dns"), + level = DeprecationLevel.ERROR, + ) fun dns(): Dns = dns @JvmName("-deprecated_socketFactory") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "socketFactory"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "socketFactory"), + level = DeprecationLevel.ERROR, + ) fun socketFactory(): SocketFactory = socketFactory @JvmName("-deprecated_proxyAuthenticator") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "proxyAuthenticator"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "proxyAuthenticator"), + level = DeprecationLevel.ERROR, + ) fun proxyAuthenticator(): Authenticator = proxyAuthenticator @JvmName("-deprecated_protocols") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "protocols"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "protocols"), + level = DeprecationLevel.ERROR, + ) fun protocols(): List = protocols @JvmName("-deprecated_connectionSpecs") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "connectionSpecs"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "connectionSpecs"), + level = DeprecationLevel.ERROR, + ) fun connectionSpecs(): List = connectionSpecs @JvmName("-deprecated_proxySelector") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "proxySelector"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "proxySelector"), + level = DeprecationLevel.ERROR, + ) fun proxySelector(): ProxySelector = proxySelector @JvmName("-deprecated_proxy") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "proxy"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "proxy"), + level = DeprecationLevel.ERROR, + ) fun proxy(): Proxy? = proxy @JvmName("-deprecated_sslSocketFactory") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "sslSocketFactory"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "sslSocketFactory"), + level = DeprecationLevel.ERROR, + ) fun sslSocketFactory(): SSLSocketFactory? = sslSocketFactory @JvmName("-deprecated_hostnameVerifier") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "hostnameVerifier"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "hostnameVerifier"), + level = DeprecationLevel.ERROR, + ) fun hostnameVerifier(): HostnameVerifier? = hostnameVerifier @JvmName("-deprecated_certificatePinner") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "certificatePinner"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "certificatePinner"), + level = DeprecationLevel.ERROR, + ) fun certificatePinner(): CertificatePinner? = certificatePinner override fun equals(other: Any?): Boolean { return other is Address && - url == other.url && - equalsNonHost(other) + url == other.url && + equalsNonHost(other) } override fun hashCode(): Int { @@ -186,21 +193,21 @@ class Address( internal fun equalsNonHost(that: Address): Boolean { return this.dns == that.dns && - this.proxyAuthenticator == that.proxyAuthenticator && - this.protocols == that.protocols && - this.connectionSpecs == that.connectionSpecs && - this.proxySelector == that.proxySelector && - this.proxy == that.proxy && - this.sslSocketFactory == that.sslSocketFactory && - this.hostnameVerifier == that.hostnameVerifier && - this.certificatePinner == that.certificatePinner && - this.url.port == that.url.port + this.proxyAuthenticator == that.proxyAuthenticator && + this.protocols == that.protocols && + this.connectionSpecs == that.connectionSpecs && + this.proxySelector == that.proxySelector && + this.proxy == that.proxy && + this.sslSocketFactory == that.sslSocketFactory && + this.hostnameVerifier == that.hostnameVerifier && + this.certificatePinner == that.certificatePinner && + this.url.port == that.url.port } override fun toString(): String { return "Address{" + - "${url.host}:${url.port}, " + - (if (proxy != null) "proxy=$proxy" else "proxySelector=$proxySelector") + - "}" + "${url.host}:${url.port}, " + + (if (proxy != null) "proxy=$proxy" else "proxySelector=$proxySelector") + + "}" } } diff --git a/okhttp/src/main/kotlin/okhttp3/AsyncDns.kt b/okhttp/src/main/kotlin/okhttp3/AsyncDns.kt index eaff00d477fa..69e6cf677300 100644 --- a/okhttp/src/main/kotlin/okhttp3/AsyncDns.kt +++ b/okhttp/src/main/kotlin/okhttp3/AsyncDns.kt @@ -36,7 +36,10 @@ interface AsyncDns { /** * Query DNS records for `hostname`, in the order they are received. */ - fun query(hostname: String, callback: Callback) + fun query( + hostname: String, + callback: Callback, + ) /** * Callback to receive results from the DNS Queries. @@ -46,12 +49,18 @@ interface AsyncDns { * Return addresses for a dns query for a single class of IPv4 (A) or IPv6 (AAAA). * May be an empty list indicating that the host is unreachable. */ - fun onResponse(hostname: String, addresses: List) + fun onResponse( + hostname: String, + addresses: List, + ) /** * Returns an error for the DNS query. */ - fun onFailure(hostname: String, e: IOException) + fun onFailure( + hostname: String, + e: IOException, + ) } /** @@ -60,7 +69,7 @@ interface AsyncDns { */ enum class DnsClass(val type: Int) { IPV4(TYPE_A), - IPV6(TYPE_AAAA); + IPV6(TYPE_AAAA), } companion object { @@ -71,43 +80,53 @@ interface AsyncDns { * Adapt an AsyncDns implementation to Dns, waiting until onComplete is received * and returning results if available. */ - fun toDns(vararg asyncDns: AsyncDns): Dns = Dns { hostname -> - val allAddresses = mutableListOf() - val allExceptions = mutableListOf() - val latch = CountDownLatch(asyncDns.size) + fun toDns(vararg asyncDns: AsyncDns): Dns = + Dns { hostname -> + val allAddresses = mutableListOf() + val allExceptions = mutableListOf() + val latch = CountDownLatch(asyncDns.size) - asyncDns.forEach { - it.query(hostname, object : Callback { - override fun onResponse(hostname: String, addresses: List) { - synchronized(allAddresses) { - allAddresses.addAll(addresses) - } - latch.countDown() - } + asyncDns.forEach { + it.query( + hostname, + object : Callback { + override fun onResponse( + hostname: String, + addresses: List, + ) { + synchronized(allAddresses) { + allAddresses.addAll(addresses) + } + latch.countDown() + } - override fun onFailure(hostname: String, e: IOException) { - synchronized(allExceptions) { - allExceptions.add(e) - } - latch.countDown() - } - }) - } + override fun onFailure( + hostname: String, + e: IOException, + ) { + synchronized(allExceptions) { + allExceptions.add(e) + } + latch.countDown() + } + }, + ) + } - latch.await() + latch.await() - // No mutations should be possible after this point - if (allAddresses.isEmpty()) { - val first = allExceptions.firstOrNull() ?: UnknownHostException("No results for $hostname") + // No mutations should be possible after this point + if (allAddresses.isEmpty()) { + val first = allExceptions.firstOrNull() ?: UnknownHostException("No results for $hostname") - allExceptions.drop(1).forEach { - first.addSuppressed(it) + allExceptions.drop(1).forEach { + first.addSuppressed(it) + } + + throw first } - throw first + allAddresses } - - allAddresses - } } } diff --git a/okhttp/src/main/kotlin/okhttp3/Authenticator.kt b/okhttp/src/main/kotlin/okhttp3/Authenticator.kt index b42da2647d7f..3c8007e4cae3 100644 --- a/okhttp/src/main/kotlin/okhttp3/Authenticator.kt +++ b/okhttp/src/main/kotlin/okhttp3/Authenticator.kt @@ -122,14 +122,21 @@ fun interface Authenticator { * application interceptor, such as when implementing client-specific retries. */ @Throws(IOException::class) - fun authenticate(route: Route?, response: Response): Request? + fun authenticate( + route: Route?, + response: Response, + ): Request? companion object { /** An authenticator that knows no credentials and makes no attempt to authenticate. */ @JvmField val NONE: Authenticator = AuthenticatorNone() + private class AuthenticatorNone : Authenticator { - override fun authenticate(route: Route?, response: Response): Request? = null + override fun authenticate( + route: Route?, + response: Response, + ): Request? = null } /** An authenticator that uses the java.net.Authenticator global authenticator. */ diff --git a/okhttp/src/main/kotlin/okhttp3/Cache.kt b/okhttp/src/main/kotlin/okhttp3/Cache.kt index 38dc2cb68494..4e8a62afbf2e 100644 --- a/okhttp/src/main/kotlin/okhttp3/Cache.kt +++ b/okhttp/src/main/kotlin/okhttp3/Cache.kt @@ -24,7 +24,6 @@ import java.security.cert.CertificateEncodingException import java.security.cert.CertificateException import java.security.cert.CertificateFactory import java.util.TreeSet -import java.util.concurrent.TimeUnit import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.internal.EMPTY_HEADERS @@ -33,7 +32,6 @@ import okhttp3.internal.cache.CacheStrategy import okhttp3.internal.cache.DiskLruCache import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.TaskRunner -import okhttp3.internal.connection.RealConnectionPool import okhttp3.internal.http.HttpMethod import okhttp3.internal.http.StatusLine import okhttp3.internal.platform.Platform @@ -147,7 +145,7 @@ class Cache internal constructor( directory: Path, maxSize: Long, fileSystem: FileSystem, - taskRunner: TaskRunner + taskRunner: TaskRunner, ) : Closeable, Flushable { constructor( directory: Path, @@ -157,17 +155,18 @@ class Cache internal constructor( directory, maxSize, fileSystem, - TaskRunner.INSTANCE + TaskRunner.INSTANCE, ) - internal val cache = DiskLruCache( - fileSystem = fileSystem, - directory = directory, - appVersion = VERSION, - valueCount = ENTRY_COUNT, - maxSize = maxSize, - taskRunner = taskRunner - ) + internal val cache = + DiskLruCache( + fileSystem = fileSystem, + directory = directory, + appVersion = VERSION, + valueCount = ENTRY_COUNT, + maxSize = maxSize, + taskRunner = taskRunner, + ) // read and write statistics, all guarded by 'this'. internal var writeSuccessCount = 0 @@ -181,23 +180,27 @@ class Cache internal constructor( /** Create a cache of at most [maxSize] bytes in [directory]. */ constructor(directory: File, maxSize: Long) : this( - directory.toOkioPath(), maxSize, FileSystem.SYSTEM + directory.toOkioPath(), + maxSize, + FileSystem.SYSTEM, ) internal fun get(request: Request): Response? { val key = key(request.url) - val snapshot: DiskLruCache.Snapshot = try { - cache[key] ?: return null - } catch (_: IOException) { - return null // Give up because the cache cannot be read. - } + val snapshot: DiskLruCache.Snapshot = + try { + cache[key] ?: return null + } catch (_: IOException) { + return null // Give up because the cache cannot be read. + } - val entry: Entry = try { - Entry(snapshot.getSource(ENTRY_METADATA)) - } catch (_: IOException) { - snapshot.closeQuietly() - return null - } + val entry: Entry = + try { + Entry(snapshot.getSource(ENTRY_METADATA)) + } catch (_: IOException) { + snapshot.closeQuietly() + return null + } val response = entry.response(snapshot) if (!entry.matches(request, response)) { @@ -247,7 +250,10 @@ class Cache internal constructor( cache.remove(key(request.url)) } - internal fun update(cached: Response, network: Response) { + internal fun update( + cached: Response, + network: Response, + ) { val entry = Entry(network) val snapshot = (cached.body as CacheResponseBody).snapshot var editor: DiskLruCache.Editor? = null @@ -373,17 +379,19 @@ class Cache internal constructor( cache.close() } - @get:JvmName("directory") val directory: File + @get:JvmName("directory") + val directory: File get() = cache.directory.toFile() - @get:JvmName("directoryPath") val directoryPath: Path + @get:JvmName("directoryPath") + val directoryPath: Path get() = cache.directory @JvmName("-deprecated_directory") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "directory"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun directory(): File = cache.directory.toFile() @@ -410,25 +418,26 @@ class Cache internal constructor( @Synchronized fun requestCount(): Int = requestCount private inner class RealCacheRequest( - private val editor: DiskLruCache.Editor + private val editor: DiskLruCache.Editor, ) : CacheRequest { private val cacheOut: Sink = editor.newSink(ENTRY_BODY) private val body: Sink var done = false init { - this.body = object : ForwardingSink(cacheOut) { - @Throws(IOException::class) - override fun close() { - synchronized(this@Cache) { - if (done) return - done = true - writeSuccessCount++ + this.body = + object : ForwardingSink(cacheOut) { + @Throws(IOException::class) + override fun close() { + synchronized(this@Cache) { + if (done) return + done = true + writeSuccessCount++ + } + super.close() + editor.commit() } - super.close() - editor.commit() } - } } override fun abort() { @@ -510,7 +519,8 @@ class Cache internal constructor( * each on their own line. A length of -1 is used to encode a null array. The last line is * optional. If present, it contains the TLS version. */ - @Throws(IOException::class) constructor(rawSource: Source) { + @Throws(IOException::class) + constructor(rawSource: Source) { rawSource.use { val source = rawSource.buffer() val urlLine = source.readUtf8LineStrict() @@ -553,11 +563,12 @@ class Cache internal constructor( val cipherSuite = CipherSuite.forJavaName(cipherSuiteString) val peerCertificates = readCertificateList(source) val localCertificates = readCertificateList(source) - val tlsVersion = if (!source.exhausted()) { - TlsVersion.forJavaName(source.readUtf8LineStrict()) - } else { - TlsVersion.SSL_3_0 - } + val tlsVersion = + if (!source.exhausted()) { + TlsVersion.forJavaName(source.readUtf8LineStrict()) + } else { + TlsVersion.SSL_3_0 + } handshake = Handshake.get(tlsVersion, cipherSuite, peerCertificates, localCertificates) } else { handshake = null @@ -640,7 +651,10 @@ class Cache internal constructor( } @Throws(IOException::class) - private fun writeCertList(sink: BufferedSink, certificates: List) { + private fun writeCertList( + sink: BufferedSink, + certificates: List, + ) { try { sink.writeDecimalLong(certificates.size.toLong()).writeByte('\n'.code) for (element in certificates) { @@ -653,7 +667,10 @@ class Cache internal constructor( } } - fun matches(request: Request, response: Response): Boolean { + fun matches( + request: Request, + response: Response, + ): Boolean { return url == request.url && requestMethod == request.method && varyMatches(response, varyHeaders, request) @@ -688,19 +705,20 @@ class Cache internal constructor( private class CacheResponseBody( val snapshot: DiskLruCache.Snapshot, private val contentType: String?, - private val contentLength: String? + private val contentLength: String?, ) : ResponseBody() { private val bodySource: BufferedSource init { val source = snapshot.getSource(ENTRY_BODY) - bodySource = object : ForwardingSource(source) { - @Throws(IOException::class) - override fun close() { - snapshot.close() - super.close() - } - }.buffer() + bodySource = + object : ForwardingSource(source) { + @Throws(IOException::class) + override fun close() { + snapshot.close() + super.close() + } + }.buffer() } override fun contentType(): MediaType? = contentType?.toMediaTypeOrNull() @@ -740,7 +758,7 @@ class Cache internal constructor( fun varyMatches( cachedResponse: Response, cachedRequest: Headers, - newRequest: Request + newRequest: Request, ): Boolean { return cachedResponse.headers.varyFields().none { cachedRequest.values(it) != newRequest.headers(it) @@ -786,7 +804,10 @@ class Cache internal constructor( * Returns the subset of the headers in [requestHeaders] that impact the content of the * response's body. */ - private fun varyHeaders(requestHeaders: Headers, responseHeaders: Headers): Headers { + private fun varyHeaders( + requestHeaders: Headers, + responseHeaders: Headers, + ): Headers { val varyFields = responseHeaders.varyFields() if (varyFields.isEmpty()) return EMPTY_HEADERS diff --git a/okhttp/src/main/kotlin/okhttp3/CacheControl.kt b/okhttp/src/main/kotlin/okhttp3/CacheControl.kt index 5147d04eb8ca..9ef7984f0333 100644 --- a/okhttp/src/main/kotlin/okhttp3/CacheControl.kt +++ b/okhttp/src/main/kotlin/okhttp3/CacheControl.kt @@ -47,28 +47,20 @@ class CacheControl internal constructor( * In a request, it means do not use a cache to satisfy the request. */ @get:JvmName("noCache") val noCache: Boolean, - /** If true, this response should not be cached. */ @get:JvmName("noStore") val noStore: Boolean, - /** The duration past the response's served date that it can be served without validation. */ @get:JvmName("maxAgeSeconds") val maxAgeSeconds: Int, - /** * The "s-maxage" directive is the max age for shared caches. Not to be confused with "max-age" * for non-shared caches, As in Firefox and Chrome, this directive is not honored by this cache. */ @get:JvmName("sMaxAgeSeconds") val sMaxAgeSeconds: Int, - val isPrivate: Boolean, val isPublic: Boolean, - @get:JvmName("mustRevalidate") val mustRevalidate: Boolean, - @get:JvmName("maxStaleSeconds") val maxStaleSeconds: Int, - @get:JvmName("minFreshSeconds") val minFreshSeconds: Int, - /** * This field's name "only-if-cached" is misleading. It actually means "do not use the network". * It is set by a client who only wants to make a request if it can be fully satisfied by the @@ -76,81 +68,88 @@ class CacheControl internal constructor( * if this header is set. */ @get:JvmName("onlyIfCached") val onlyIfCached: Boolean, - @get:JvmName("noTransform") val noTransform: Boolean, - @get:JvmName("immutable") val immutable: Boolean, - - internal var headerValue: String? + internal var headerValue: String?, ) { @JvmName("-deprecated_noCache") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "noCache"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "noCache"), + level = DeprecationLevel.ERROR, + ) fun noCache(): Boolean = noCache @JvmName("-deprecated_noStore") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "noStore"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "noStore"), + level = DeprecationLevel.ERROR, + ) fun noStore(): Boolean = noStore @JvmName("-deprecated_maxAgeSeconds") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "maxAgeSeconds"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "maxAgeSeconds"), + level = DeprecationLevel.ERROR, + ) fun maxAgeSeconds(): Int = maxAgeSeconds @JvmName("-deprecated_sMaxAgeSeconds") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "sMaxAgeSeconds"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "sMaxAgeSeconds"), + level = DeprecationLevel.ERROR, + ) fun sMaxAgeSeconds(): Int = sMaxAgeSeconds @JvmName("-deprecated_mustRevalidate") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "mustRevalidate"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "mustRevalidate"), + level = DeprecationLevel.ERROR, + ) fun mustRevalidate(): Boolean = mustRevalidate @JvmName("-deprecated_maxStaleSeconds") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "maxStaleSeconds"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "maxStaleSeconds"), + level = DeprecationLevel.ERROR, + ) fun maxStaleSeconds(): Int = maxStaleSeconds @JvmName("-deprecated_minFreshSeconds") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "minFreshSeconds"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "minFreshSeconds"), + level = DeprecationLevel.ERROR, + ) fun minFreshSeconds(): Int = minFreshSeconds @JvmName("-deprecated_onlyIfCached") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "onlyIfCached"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "onlyIfCached"), + level = DeprecationLevel.ERROR, + ) fun onlyIfCached(): Boolean = onlyIfCached @JvmName("-deprecated_noTransform") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "noTransform"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "noTransform"), + level = DeprecationLevel.ERROR, + ) fun noTransform(): Boolean = noTransform @JvmName("-deprecated_immutable") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "immutable"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "immutable"), + level = DeprecationLevel.ERROR, + ) fun immutable(): Boolean = immutable override fun toString(): String = commonToString() @@ -190,11 +189,20 @@ class CacheControl internal constructor( * @param maxAge a non-negative integer. This is stored and transmitted with [TimeUnit.SECONDS] * precision; finer precision will be lost. */ - fun maxAge(maxAge: Int, timeUnit: DurationUnit) = commonMaxAge(maxAge, timeUnit) + fun maxAge( + maxAge: Int, + timeUnit: DurationUnit, + ) = commonMaxAge(maxAge, timeUnit) - fun maxStale(maxStale: Int, timeUnit: DurationUnit) = commonMaxStale(maxStale, timeUnit) + fun maxStale( + maxStale: Int, + timeUnit: DurationUnit, + ) = commonMaxStale(maxStale, timeUnit) - fun minFresh(minFresh: Int, timeUnit: DurationUnit) = commonMinFresh(minFresh, timeUnit) + fun minFresh( + minFresh: Int, + timeUnit: DurationUnit, + ) = commonMinFresh(minFresh, timeUnit) /** * Sets the maximum age of a cached response. If the cache response's age exceeds [maxAge], it @@ -203,7 +211,10 @@ class CacheControl internal constructor( * @param maxAge a non-negative integer. This is stored and transmitted with [TimeUnit.SECONDS] * precision; finer precision will be lost. */ - fun maxAge(maxAge: Int, timeUnit: TimeUnit) = apply { + fun maxAge( + maxAge: Int, + timeUnit: TimeUnit, + ) = apply { require(maxAge >= 0) { "maxAge < 0: $maxAge" } val maxAgeSecondsLong = timeUnit.toSeconds(maxAge.toLong()) this.maxAgeSeconds = maxAgeSecondsLong.commonClampToInt() @@ -216,7 +227,10 @@ class CacheControl internal constructor( * @param maxStale a non-negative integer. This is stored and transmitted with * [TimeUnit.SECONDS] precision; finer precision will be lost. */ - fun maxStale(maxStale: Int, timeUnit: TimeUnit) = apply { + fun maxStale( + maxStale: Int, + timeUnit: TimeUnit, + ) = apply { require(maxStale >= 0) { "maxStale < 0: $maxStale" } val maxStaleSecondsLong = timeUnit.toSeconds(maxStale.toLong()) this.maxStaleSeconds = maxStaleSecondsLong.commonClampToInt() @@ -230,7 +244,10 @@ class CacheControl internal constructor( * @param minFresh a non-negative integer. This is stored and transmitted with * [TimeUnit.SECONDS] precision; finer precision will be lost. */ - fun minFresh(minFresh: Int, timeUnit: TimeUnit) = apply { + fun minFresh( + minFresh: Int, + timeUnit: TimeUnit, + ) = apply { require(minFresh >= 0) { "minFresh < 0: $minFresh" } val minFreshSecondsLong = timeUnit.toSeconds(minFresh.toLong()) this.minFreshSeconds = minFreshSecondsLong.commonClampToInt() diff --git a/okhttp/src/main/kotlin/okhttp3/Callback.kt b/okhttp/src/main/kotlin/okhttp3/Callback.kt index 7579df19e249..f5425d07d17c 100644 --- a/okhttp/src/main/kotlin/okhttp3/Callback.kt +++ b/okhttp/src/main/kotlin/okhttp3/Callback.kt @@ -23,7 +23,10 @@ interface Callback { * timeout. Because networks can fail during an exchange, it is possible that the remote server * accepted the request before the failure. */ - fun onFailure(call: Call, e: IOException) + fun onFailure( + call: Call, + e: IOException, + ) /** * Called when the HTTP response was successfully returned by the remote server. The callback may @@ -36,5 +39,8 @@ interface Callback { * response code like 404 or 500. */ @Throws(IOException::class) - fun onResponse(call: Call, response: Response) + fun onResponse( + call: Call, + response: Response, + ) } diff --git a/okhttp/src/main/kotlin/okhttp3/CertificatePinner.kt b/okhttp/src/main/kotlin/okhttp3/CertificatePinner.kt index 571a8215fe5f..a3bbc453f33b 100644 --- a/okhttp/src/main/kotlin/okhttp3/CertificatePinner.kt +++ b/okhttp/src/main/kotlin/okhttp3/CertificatePinner.kt @@ -135,7 +135,7 @@ import okio.ByteString.Companion.toByteString @Suppress("NAME_SHADOWING") class CertificatePinner internal constructor( val pins: Set, - internal val certificateChainCleaner: CertificateChainCleaner? = null + internal val certificateChainCleaner: CertificateChainCleaner? = null, ) { /** * Confirms that at least one of the certificates pinned for `hostname` is in `peerCertificates`. @@ -146,14 +146,20 @@ class CertificatePinner internal constructor( * for `hostname`. */ @Throws(SSLPeerUnverifiedException::class) - fun check(hostname: String, peerCertificates: List) { + fun check( + hostname: String, + peerCertificates: List, + ) { return check(hostname) { (certificateChainCleaner?.clean(peerCertificates, hostname) ?: peerCertificates) - .map { it as X509Certificate } + .map { it as X509Certificate } } } - internal fun check(hostname: String, cleanedPeerCertificatesFn: () -> List) { + internal fun check( + hostname: String, + cleanedPeerCertificatesFn: () -> List, + ) { val pins = findMatchingPins(hostname) if (pins.isEmpty()) return @@ -180,32 +186,36 @@ class CertificatePinner internal constructor( } // If we couldn't find a matching pin, format a nice exception. - val message = buildString { - append("Certificate pinning failure!") - append("\n Peer certificate chain:") - for (element in peerCertificates) { - append("\n ") - append(pin(element)) - append(": ") - append(element.subjectDN.name) - } - append("\n Pinned certificates for ") - append(hostname) - append(":") - for (pin in pins) { - append("\n ") - append(pin) + val message = + buildString { + append("Certificate pinning failure!") + append("\n Peer certificate chain:") + for (element in peerCertificates) { + append("\n ") + append(pin(element)) + append(": ") + append(element.subjectDN.name) + } + append("\n Pinned certificates for ") + append(hostname) + append(":") + for (pin in pins) { + append("\n ") + append(pin) + } } - } throw SSLPeerUnverifiedException(message) } @Deprecated( - "replaced with {@link #check(String, List)}.", - ReplaceWith("check(hostname, peerCertificates.toList())") + "replaced with {@link #check(String, List)}.", + ReplaceWith("check(hostname, peerCertificates.toList())"), ) @Throws(SSLPeerUnverifiedException::class) - fun check(hostname: String, vararg peerCertificates: Certificate) { + fun check( + hostname: String, + vararg peerCertificates: Certificate, + ) { check(hostname, peerCertificates.toList()) } @@ -216,9 +226,7 @@ class CertificatePinner internal constructor( fun findMatchingPins(hostname: String): List = pins.filterList { matchesHostname(hostname) } /** Returns a certificate pinner that uses `certificateChainCleaner`. */ - internal fun withCertificateChainCleaner( - certificateChainCleaner: CertificateChainCleaner - ): CertificatePinner { + internal fun withCertificateChainCleaner(certificateChainCleaner: CertificateChainCleaner): CertificatePinner { return if (this.certificateChainCleaner == certificateChainCleaner) { this } else { @@ -228,8 +236,8 @@ class CertificatePinner internal constructor( override fun equals(other: Any?): Boolean { return other is CertificatePinner && - other.pins == pins && - other.certificateChainCleaner == certificateChainCleaner + other.pins == pins && + other.certificateChainCleaner == certificateChainCleaner } override fun hashCode(): Int { @@ -251,9 +259,11 @@ class CertificatePinner internal constructor( val hash: ByteString init { - require((pattern.startsWith("*.") && pattern.indexOf("*", 1) == -1) || + require( + (pattern.startsWith("*.") && pattern.indexOf("*", 1) == -1) || (pattern.startsWith("**.") && pattern.indexOf("*", 2) == -1) || - pattern.indexOf("*") == -1) { + pattern.indexOf("*") == -1, + ) { "Unexpected pattern: $pattern" } @@ -280,25 +290,25 @@ class CertificatePinner internal constructor( val suffixLength = pattern.length - 3 val prefixLength = hostname.length - suffixLength hostname.regionMatches(hostname.length - suffixLength, pattern, 3, suffixLength) && - (prefixLength == 0 || hostname[prefixLength - 1] == '.') + (prefixLength == 0 || hostname[prefixLength - 1] == '.') } pattern.startsWith("*.") -> { // With * there must be a prefix so include the dot in regionMatches(). val suffixLength = pattern.length - 1 val prefixLength = hostname.length - suffixLength hostname.regionMatches(hostname.length - suffixLength, pattern, 1, suffixLength) && - hostname.lastIndexOf('.', prefixLength - 1) == -1 + hostname.lastIndexOf('.', prefixLength - 1) == -1 } else -> hostname == pattern } } fun matchesCertificate(certificate: X509Certificate): Boolean { - return when (hashAlgorithm) { - "sha256" -> hash == certificate.sha256Hash() - "sha1" -> hash == certificate.sha1Hash() - else -> false - } + return when (hashAlgorithm) { + "sha256" -> hash == certificate.sha256Hash() + "sha1" -> hash == certificate.sha1Hash() + else -> false + } } override fun toString(): String = "$hashAlgorithm/${hash.base64()}" @@ -333,7 +343,10 @@ class CertificatePinner internal constructor( * @param pins SHA-256 or SHA-1 hashes. Each pin is a hash of a certificate's Subject Public Key * Info, base64-encoded and prefixed with either `sha256/` or `sha1/`. */ - fun add(pattern: String, vararg pins: String) = apply { + fun add( + pattern: String, + vararg pins: String, + ) = apply { for (pin in pins) { this.pins.add(Pin(pattern, pin)) } @@ -347,12 +360,10 @@ class CertificatePinner internal constructor( val DEFAULT = Builder().build() @JvmStatic - fun X509Certificate.sha1Hash(): ByteString = - publicKey.encoded.toByteString().sha1() + fun X509Certificate.sha1Hash(): ByteString = publicKey.encoded.toByteString().sha1() @JvmStatic - fun X509Certificate.sha256Hash(): ByteString = - publicKey.encoded.toByteString().sha256() + fun X509Certificate.sha256Hash(): ByteString = publicKey.encoded.toByteString().sha256() /** * Returns the SHA-256 of `certificate`'s public key. diff --git a/okhttp/src/main/kotlin/okhttp3/Challenge.kt b/okhttp/src/main/kotlin/okhttp3/Challenge.kt index 1ceaa87c2f26..13b266f6990f 100644 --- a/okhttp/src/main/kotlin/okhttp3/Challenge.kt +++ b/okhttp/src/main/kotlin/okhttp3/Challenge.kt @@ -32,21 +32,23 @@ import okhttp3.internal.commonToString class Challenge( /** Returns the authentication scheme, like `Basic`. */ @get:JvmName("scheme") val scheme: String, - - authParams: Map + authParams: Map, ) { /** * Returns the auth params, including [realm] and [charset] if present, but as * strings. The map's keys are lowercase and should be treated case-insensitively. */ - @get:JvmName("authParams") val authParams: Map + @get:JvmName("authParams") + val authParams: Map /** Returns the protection space. */ - @get:JvmName("realm") val realm: String? + @get:JvmName("realm") + val realm: String? get() = authParams["realm"] /** The charset that should be used to encode the credentials. */ - @get:JvmName("charset") val charset: Charset + @get:JvmName("charset") + val charset: Charset get() { val charset = authParams["charset"] if (charset != null) { @@ -78,30 +80,34 @@ class Challenge( @JvmName("-deprecated_scheme") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "scheme"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "scheme"), + level = DeprecationLevel.ERROR, + ) fun scheme(): String = scheme @JvmName("-deprecated_authParams") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "authParams"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "authParams"), + level = DeprecationLevel.ERROR, + ) fun authParams(): Map = authParams @JvmName("-deprecated_realm") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "realm"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "realm"), + level = DeprecationLevel.ERROR, + ) fun realm(): String? = realm @JvmName("-deprecated_charset") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "charset"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "charset"), + level = DeprecationLevel.ERROR, + ) fun charset(): Charset = charset override fun equals(other: Any?): Boolean = commonEquals(other) diff --git a/okhttp/src/main/kotlin/okhttp3/CipherSuite.kt b/okhttp/src/main/kotlin/okhttp3/CipherSuite.kt index 734047d9332a..b1fb5e33010a 100644 --- a/okhttp/src/main/kotlin/okhttp3/CipherSuite.kt +++ b/okhttp/src/main/kotlin/okhttp3/CipherSuite.kt @@ -42,13 +42,14 @@ class CipherSuite private constructor( * prefixed `TLS_`. For example, `TLS_RSA_EXPORT_WITH_RC4_40_MD5.javaName()` is * `"SSL_RSA_EXPORT_WITH_RC4_40_MD5"`. */ - @get:JvmName("javaName") val javaName: String + @get:JvmName("javaName") val javaName: String, ) { @JvmName("-deprecated_javaName") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "javaName"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "javaName"), + level = DeprecationLevel.ERROR, + ) fun javaName(): String = javaName override fun toString(): String = javaName @@ -59,22 +60,26 @@ class CipherSuite private constructor( * ignoring the "TLS_" or "SSL_" prefix which is not consistent across platforms. In particular * some IBM JVMs use the "SSL_" prefix everywhere whereas Oracle JVMs mix "TLS_" and "SSL_". */ - internal val ORDER_BY_NAME = object : Comparator { - override fun compare(a: String, b: String): Int { - var i = 4 - val limit = minOf(a.length, b.length) - while (i < limit) { - val charA = a[i] - val charB = b[i] - if (charA != charB) return if (charA < charB) -1 else 1 - i++ + internal val ORDER_BY_NAME = + object : Comparator { + override fun compare( + a: String, + b: String, + ): Int { + var i = 4 + val limit = minOf(a.length, b.length) + while (i < limit) { + val charA = a[i] + val charB = b[i] + if (charA != charB) return if (charA < charB) -1 else 1 + i++ + } + val lengthA = a.length + val lengthB = b.length + if (lengthA != lengthB) return if (lengthA < lengthB) -1 else 1 + return 0 } - val lengthA = a.length - val lengthB = b.length - if (lengthA != lengthB) return if (lengthA < lengthB) -1 else 1 - return 0 } - } /** * Holds interned instances. This needs to be above the init() calls below so that it's @@ -86,15 +91,23 @@ class CipherSuite private constructor( // @JvmField val TLS_NULL_WITH_NULL_NULL = init("TLS_NULL_WITH_NULL_NULL", 0x0000) @JvmField val TLS_RSA_WITH_NULL_MD5 = init("SSL_RSA_WITH_NULL_MD5", 0x0001) + @JvmField val TLS_RSA_WITH_NULL_SHA = init("SSL_RSA_WITH_NULL_SHA", 0x0002) + @JvmField val TLS_RSA_EXPORT_WITH_RC4_40_MD5 = init("SSL_RSA_EXPORT_WITH_RC4_40_MD5", 0x0003) + @JvmField val TLS_RSA_WITH_RC4_128_MD5 = init("SSL_RSA_WITH_RC4_128_MD5", 0x0004) + @JvmField val TLS_RSA_WITH_RC4_128_SHA = init("SSL_RSA_WITH_RC4_128_SHA", 0x0005) + // @JvmField val TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = init("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 0x0006) // @JvmField val TLS_RSA_WITH_IDEA_CBC_SHA = init("TLS_RSA_WITH_IDEA_CBC_SHA", 0x0007) @JvmField val TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = init("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0008) + @JvmField val TLS_RSA_WITH_DES_CBC_SHA = init("SSL_RSA_WITH_DES_CBC_SHA", 0x0009) + @JvmField val TLS_RSA_WITH_3DES_EDE_CBC_SHA = init("SSL_RSA_WITH_3DES_EDE_CBC_SHA", 0x000a) + // @JvmField val TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x000b) // @JvmField val TLS_DH_DSS_WITH_DES_CBC_SHA = init("TLS_DH_DSS_WITH_DES_CBC_SHA", 0x000c) // @JvmField val TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = init("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", 0x000d) @@ -102,74 +115,122 @@ class CipherSuite private constructor( // @JvmField val TLS_DH_RSA_WITH_DES_CBC_SHA = init("TLS_DH_RSA_WITH_DES_CBC_SHA", 0x000f) // @JvmField val TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", 0x0010) @JvmField val TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x0011) + @JvmField val TLS_DHE_DSS_WITH_DES_CBC_SHA = init("SSL_DHE_DSS_WITH_DES_CBC_SHA", 0x0012) + @JvmField val TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = init("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 0x0013) + @JvmField val TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0014) + @JvmField val TLS_DHE_RSA_WITH_DES_CBC_SHA = init("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0015) + @JvmField val TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = init("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 0x0016) + @JvmField val TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = init("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", 0x0017) + @JvmField val TLS_DH_anon_WITH_RC4_128_MD5 = init("SSL_DH_anon_WITH_RC4_128_MD5", 0x0018) + @JvmField val TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", 0x0019) + @JvmField val TLS_DH_anon_WITH_DES_CBC_SHA = init("SSL_DH_anon_WITH_DES_CBC_SHA", 0x001a) + @JvmField val TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = init("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b) + @JvmField val TLS_KRB5_WITH_DES_CBC_SHA = init("TLS_KRB5_WITH_DES_CBC_SHA", 0x001e) + @JvmField val TLS_KRB5_WITH_3DES_EDE_CBC_SHA = init("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", 0x001f) + @JvmField val TLS_KRB5_WITH_RC4_128_SHA = init("TLS_KRB5_WITH_RC4_128_SHA", 0x0020) + // @JvmField val TLS_KRB5_WITH_IDEA_CBC_SHA = init("TLS_KRB5_WITH_IDEA_CBC_SHA", 0x0021) @JvmField val TLS_KRB5_WITH_DES_CBC_MD5 = init("TLS_KRB5_WITH_DES_CBC_MD5", 0x0022) + @JvmField val TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = init("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", 0x0023) + @JvmField val TLS_KRB5_WITH_RC4_128_MD5 = init("TLS_KRB5_WITH_RC4_128_MD5", 0x0024) + // @JvmField val TLS_KRB5_WITH_IDEA_CBC_MD5 = init("TLS_KRB5_WITH_IDEA_CBC_MD5", 0x0025) @JvmField val TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = init("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", 0x0026) + // @JvmField val TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = init("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027) @JvmField val TLS_KRB5_EXPORT_WITH_RC4_40_SHA = init("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", 0x0028) + @JvmField val TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = init("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 0x0029) + // @JvmField val TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = init("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a) @JvmField val TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = init("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", 0x002b) + // @JvmField val TLS_PSK_WITH_NULL_SHA = init("TLS_PSK_WITH_NULL_SHA", 0x002c) // @JvmField val TLS_DHE_PSK_WITH_NULL_SHA = init("TLS_DHE_PSK_WITH_NULL_SHA", 0x002d) // @JvmField val TLS_RSA_PSK_WITH_NULL_SHA = init("TLS_RSA_PSK_WITH_NULL_SHA", 0x002e) @JvmField val TLS_RSA_WITH_AES_128_CBC_SHA = init("TLS_RSA_WITH_AES_128_CBC_SHA", 0x002f) + // @JvmField val TLS_DH_DSS_WITH_AES_128_CBC_SHA = init("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030) // @JvmField val TLS_DH_RSA_WITH_AES_128_CBC_SHA = init("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x0031) @JvmField val TLS_DHE_DSS_WITH_AES_128_CBC_SHA = init("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032) + @JvmField val TLS_DHE_RSA_WITH_AES_128_CBC_SHA = init("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 0x0033) + @JvmField val TLS_DH_anon_WITH_AES_128_CBC_SHA = init("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034) + @JvmField val TLS_RSA_WITH_AES_256_CBC_SHA = init("TLS_RSA_WITH_AES_256_CBC_SHA", 0x0035) + // @JvmField val TLS_DH_DSS_WITH_AES_256_CBC_SHA = init("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x0036) // @JvmField val TLS_DH_RSA_WITH_AES_256_CBC_SHA = init("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x0037) @JvmField val TLS_DHE_DSS_WITH_AES_256_CBC_SHA = init("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038) + @JvmField val TLS_DHE_RSA_WITH_AES_256_CBC_SHA = init("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 0x0039) + @JvmField val TLS_DH_anon_WITH_AES_256_CBC_SHA = init("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a) + @JvmField val TLS_RSA_WITH_NULL_SHA256 = init("TLS_RSA_WITH_NULL_SHA256", 0x003b) + @JvmField val TLS_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_RSA_WITH_AES_128_CBC_SHA256", 0x003c) + @JvmField val TLS_RSA_WITH_AES_256_CBC_SHA256 = init("TLS_RSA_WITH_AES_256_CBC_SHA256", 0x003d) + // @JvmField val TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = init("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x003e) // @JvmField val TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x003f) @JvmField val TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = init("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", 0x0040) + @JvmField val TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = init("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0041) + // @JvmField val TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0042) // @JvmField val TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0043) @JvmField val TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0044) + @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0045) + // @JvmField val TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 0x0046) @JvmField val TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", 0x0067) + // @JvmField val TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = init("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x0068) // @JvmField val TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = init("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069) @JvmField val TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = init("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 0x006a) + @JvmField val TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = init("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", 0x006b) + @JvmField val TLS_DH_anon_WITH_AES_128_CBC_SHA256 = init("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c) + @JvmField val TLS_DH_anon_WITH_AES_256_CBC_SHA256 = init("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d) + @JvmField val TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = init("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0084) + // @JvmField val TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0085) // @JvmField val TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0086) @JvmField val TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0087) + @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0088) + // @JvmField val TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 0x0089) @JvmField val TLS_PSK_WITH_RC4_128_SHA = init("TLS_PSK_WITH_RC4_128_SHA", 0x008a) + @JvmField val TLS_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x008b) + @JvmField val TLS_PSK_WITH_AES_128_CBC_SHA = init("TLS_PSK_WITH_AES_128_CBC_SHA", 0x008c) + @JvmField val TLS_PSK_WITH_AES_256_CBC_SHA = init("TLS_PSK_WITH_AES_256_CBC_SHA", 0x008d) + // @JvmField val TLS_DHE_PSK_WITH_RC4_128_SHA = init("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x008e) // @JvmField val TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x008f) // @JvmField val TLS_DHE_PSK_WITH_AES_128_CBC_SHA = init("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x0090) @@ -179,23 +240,32 @@ class CipherSuite private constructor( // @JvmField val TLS_RSA_PSK_WITH_AES_128_CBC_SHA = init("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x0094) // @JvmField val TLS_RSA_PSK_WITH_AES_256_CBC_SHA = init("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x0095) @JvmField val TLS_RSA_WITH_SEED_CBC_SHA = init("TLS_RSA_WITH_SEED_CBC_SHA", 0x0096) + // @JvmField val TLS_DH_DSS_WITH_SEED_CBC_SHA = init("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x0097) // @JvmField val TLS_DH_RSA_WITH_SEED_CBC_SHA = init("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x0098) // @JvmField val TLS_DHE_DSS_WITH_SEED_CBC_SHA = init("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x0099) // @JvmField val TLS_DHE_RSA_WITH_SEED_CBC_SHA = init("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x009a) // @JvmField val TLS_DH_anon_WITH_SEED_CBC_SHA = init("TLS_DH_anon_WITH_SEED_CBC_SHA", 0x009b) @JvmField val TLS_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c) + @JvmField val TLS_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d) + @JvmField val TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e) + @JvmField val TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f) + // @JvmField val TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0) // @JvmField val TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1) @JvmField val TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = init("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2) + @JvmField val TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = init("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3) + // @JvmField val TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = init("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4) // @JvmField val TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = init("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5) @JvmField val TLS_DH_anon_WITH_AES_128_GCM_SHA256 = init("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6) + @JvmField val TLS_DH_anon_WITH_AES_256_GCM_SHA384 = init("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7) + // @JvmField val TLS_PSK_WITH_AES_128_GCM_SHA256 = init("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8) // @JvmField val TLS_PSK_WITH_AES_256_GCM_SHA384 = init("TLS_PSK_WITH_AES_256_GCM_SHA384", 0x00a9) // @JvmField val TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = init("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0x00aa) @@ -227,32 +297,59 @@ class CipherSuite private constructor( // @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c4) // @JvmField val TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0x00c5) @JvmField val TLS_EMPTY_RENEGOTIATION_INFO_SCSV = init("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", 0x00ff) + @JvmField val TLS_FALLBACK_SCSV = init("TLS_FALLBACK_SCSV", 0x5600) + @JvmField val TLS_ECDH_ECDSA_WITH_NULL_SHA = init("TLS_ECDH_ECDSA_WITH_NULL_SHA", 0xc001) + @JvmField val TLS_ECDH_ECDSA_WITH_RC4_128_SHA = init("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 0xc002) + @JvmField val TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc003) + @JvmField val TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = init("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 0xc004) + @JvmField val TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = init("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 0xc005) + @JvmField val TLS_ECDHE_ECDSA_WITH_NULL_SHA = init("TLS_ECDHE_ECDSA_WITH_NULL_SHA", 0xc006) + @JvmField val TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = init("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xc007) + @JvmField val TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc008) + @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = init("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 0xc009) + @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = init("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 0xc00a) + @JvmField val TLS_ECDH_RSA_WITH_NULL_SHA = init("TLS_ECDH_RSA_WITH_NULL_SHA", 0xc00b) + @JvmField val TLS_ECDH_RSA_WITH_RC4_128_SHA = init("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xc00c) + @JvmField val TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 0xc00d) + @JvmField val TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = init("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 0xc00e) + @JvmField val TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = init("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 0xc00f) + @JvmField val TLS_ECDHE_RSA_WITH_NULL_SHA = init("TLS_ECDHE_RSA_WITH_NULL_SHA", 0xc010) + @JvmField val TLS_ECDHE_RSA_WITH_RC4_128_SHA = init("TLS_ECDHE_RSA_WITH_RC4_128_SHA", 0xc011) + @JvmField val TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 0xc012) + @JvmField val TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = init("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 0xc013) + @JvmField val TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = init("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 0xc014) + @JvmField val TLS_ECDH_anon_WITH_NULL_SHA = init("TLS_ECDH_anon_WITH_NULL_SHA", 0xc015) + @JvmField val TLS_ECDH_anon_WITH_RC4_128_SHA = init("TLS_ECDH_anon_WITH_RC4_128_SHA", 0xc016) + @JvmField val TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", 0xc017) + @JvmField val TLS_ECDH_anon_WITH_AES_128_CBC_SHA = init("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", 0xc018) + @JvmField val TLS_ECDH_anon_WITH_AES_256_CBC_SHA = init("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", 0xc019) + // @JvmField val TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xc01a) // @JvmField val TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xc01b) // @JvmField val TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xc01c) @@ -263,25 +360,43 @@ class CipherSuite private constructor( // @JvmField val TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = init("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021) // @JvmField val TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = init("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022) @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = init("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023) + @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = init("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024) + @JvmField val TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = init("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", 0xc025) + @JvmField val TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = init("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", 0xc026) + @JvmField val TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 0xc027) + @JvmField val TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = init("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 0xc028) + @JvmField val TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 0xc029) + @JvmField val TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = init("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", 0xc02a) + @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = init("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b) + @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = init("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c) + @JvmField val TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = init("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d) + @JvmField val TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = init("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e) + @JvmField val TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f) + @JvmField val TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030) + @JvmField val TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031) + @JvmField val TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032) + // @JvmField val TLS_ECDHE_PSK_WITH_RC4_128_SHA = init("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033) // @JvmField val TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034) @JvmField val TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = init("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xc035) + @JvmField val TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = init("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xc036) + // @JvmField val TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xc037) // @JvmField val TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xc038) // @JvmField val TLS_ECDHE_PSK_WITH_NULL_SHA = init("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xc039) @@ -404,8 +519,11 @@ class CipherSuite private constructor( // @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = init("TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", 0xc0ae) // @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = init("TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", 0xc0af) @JvmField val TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 0xcca8) + @JvmField val TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", 0xcca9) + @JvmField val TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 0xccaa) + // @JvmField val TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccab) @JvmField val TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccac) // @JvmField val TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccad) @@ -413,9 +531,13 @@ class CipherSuite private constructor( // TLS 1.3 https://tools.ietf.org/html/rfc8446 @JvmField val TLS_AES_128_GCM_SHA256 = init("TLS_AES_128_GCM_SHA256", 0x1301) + @JvmField val TLS_AES_256_GCM_SHA384 = init("TLS_AES_256_GCM_SHA384", 0x1302) + @JvmField val TLS_CHACHA20_POLY1305_SHA256 = init("TLS_CHACHA20_POLY1305_SHA256", 0x1303) + @JvmField val TLS_AES_128_CCM_SHA256 = init("TLS_AES_128_CCM_SHA256", 0x1304) + @JvmField val TLS_AES_128_CCM_8_SHA256 = init("TLS_AES_128_CCM_8_SHA256", 0x1305) /** @@ -451,7 +573,10 @@ class CipherSuite private constructor( * name for older cipher suites because the prefix is `SSL_` instead of `TLS_`. * @param value the integer identifier for this cipher suite. (Documentation only.) */ - private fun init(javaName: String, value: Int): CipherSuite { + private fun init( + javaName: String, + value: Int, + ): CipherSuite { val suite = CipherSuite(javaName) INSTANCES[javaName] = suite return suite diff --git a/okhttp/src/main/kotlin/okhttp3/ConnectionListener.kt b/okhttp/src/main/kotlin/okhttp3/ConnectionListener.kt index 77c86dafad51..6c364cc80224 100644 --- a/okhttp/src/main/kotlin/okhttp3/ConnectionListener.kt +++ b/okhttp/src/main/kotlin/okhttp3/ConnectionListener.kt @@ -28,17 +28,28 @@ abstract class ConnectionListener { /** * Invoked as soon as a call causes a connection to be started. */ - open fun connectStart(route: Route, call: Call) {} + open fun connectStart( + route: Route, + call: Call, + ) {} /** * Invoked when a connection fails to be established. */ - open fun connectFailed(route: Route, call: Call, failure: IOException) {} + open fun connectFailed( + route: Route, + call: Call, + failure: IOException, + ) {} /** * Invoked as soon as a connection is successfully established. */ - open fun connectEnd(connection: Connection, route: Route, call: Call) {} + open fun connectEnd( + connection: Connection, + route: Route, + call: Call, + ) {} /** * Invoked when a connection is released as no longer required. @@ -48,12 +59,18 @@ abstract class ConnectionListener { /** * Invoked when a call is assigned a particular connection. */ - open fun connectionAcquired(connection: Connection, call: Call) {} + open fun connectionAcquired( + connection: Connection, + call: Call, + ) {} /** * Invoked when a call no longer uses a connection. */ - open fun connectionReleased(connection: Connection, call: Call) {} + open fun connectionReleased( + connection: Connection, + call: Call, + ) {} /** * Invoked when a connection is marked for no new exchanges. diff --git a/okhttp/src/main/kotlin/okhttp3/ConnectionPool.kt b/okhttp/src/main/kotlin/okhttp3/ConnectionPool.kt index 50d34a6f1d86..a0f7302d491a 100644 --- a/okhttp/src/main/kotlin/okhttp3/ConnectionPool.kt +++ b/okhttp/src/main/kotlin/okhttp3/ConnectionPool.kt @@ -31,7 +31,7 @@ import okhttp3.internal.connection.RealConnectionPool * inactivity. */ class ConnectionPool internal constructor( - internal val delegate: RealConnectionPool + internal val delegate: RealConnectionPool, ) { internal constructor( maxIdleConnections: Int = 5, @@ -39,13 +39,15 @@ class ConnectionPool internal constructor( timeUnit: TimeUnit = TimeUnit.MINUTES, taskRunner: TaskRunner = TaskRunner.INSTANCE, connectionListener: ConnectionListener = ConnectionListener.NONE, - ) : this(RealConnectionPool( + ) : this( + RealConnectionPool( taskRunner = taskRunner, maxIdleConnections = maxIdleConnections, keepAliveDuration = keepAliveDuration, timeUnit = timeUnit, - connectionListener = connectionListener - )) + connectionListener = connectionListener, + ), + ) // Public API constructor( @@ -58,7 +60,7 @@ class ConnectionPool internal constructor( maxIdleConnections = maxIdleConnections, keepAliveDuration = keepAliveDuration, timeUnit = timeUnit, - connectionListener = connectionListener + connectionListener = connectionListener, ) // Public API @@ -71,7 +73,7 @@ class ConnectionPool internal constructor( keepAliveDuration = keepAliveDuration, timeUnit = timeUnit, taskRunner = TaskRunner.INSTANCE, - connectionListener = ConnectionListener.NONE + connectionListener = ConnectionListener.NONE, ) constructor() : this(5, 5, TimeUnit.MINUTES) diff --git a/okhttp/src/main/kotlin/okhttp3/ConnectionSpec.kt b/okhttp/src/main/kotlin/okhttp3/ConnectionSpec.kt index 92544b64b345..2bed9b524fd3 100644 --- a/okhttp/src/main/kotlin/okhttp3/ConnectionSpec.kt +++ b/okhttp/src/main/kotlin/okhttp3/ConnectionSpec.kt @@ -48,50 +48,57 @@ class ConnectionSpec internal constructor( @get:JvmName("isTls") val isTls: Boolean, @get:JvmName("supportsTlsExtensions") val supportsTlsExtensions: Boolean, internal val cipherSuitesAsString: Array?, - private val tlsVersionsAsString: Array? + private val tlsVersionsAsString: Array?, ) { - /** * Returns the cipher suites to use for a connection. Returns null if all of the SSL socket's * enabled cipher suites should be used. */ - @get:JvmName("cipherSuites") val cipherSuites: List? + @get:JvmName("cipherSuites") + val cipherSuites: List? get() { return cipherSuitesAsString?.map { CipherSuite.forJavaName(it) } } @JvmName("-deprecated_cipherSuites") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "cipherSuites"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "cipherSuites"), + level = DeprecationLevel.ERROR, + ) fun cipherSuites(): List? = cipherSuites /** * Returns the TLS versions to use when negotiating a connection. Returns null if all of the SSL * socket's enabled TLS versions should be used. */ - @get:JvmName("tlsVersions") val tlsVersions: List? + @get:JvmName("tlsVersions") + val tlsVersions: List? get() { return tlsVersionsAsString?.map { TlsVersion.forJavaName(it) } } @JvmName("-deprecated_tlsVersions") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "tlsVersions"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "tlsVersions"), + level = DeprecationLevel.ERROR, + ) fun tlsVersions(): List? = tlsVersions @JvmName("-deprecated_supportsTlsExtensions") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "supportsTlsExtensions"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "supportsTlsExtensions"), + level = DeprecationLevel.ERROR, + ) fun supportsTlsExtensions(): Boolean = supportsTlsExtensions /** Applies this spec to [sslSocket]. */ - internal fun apply(sslSocket: SSLSocket, isFallback: Boolean) { + internal fun apply( + sslSocket: SSLSocket, + isFallback: Boolean, + ) { val specToApply = supportedSpec(sslSocket, isFallback) if (specToApply.tlsVersions != null) { @@ -106,30 +113,39 @@ class ConnectionSpec internal constructor( /** * Returns a copy of this that omits cipher suites and TLS versions not enabled by [sslSocket]. */ - private fun supportedSpec(sslSocket: SSLSocket, isFallback: Boolean): ConnectionSpec { + private fun supportedSpec( + sslSocket: SSLSocket, + isFallback: Boolean, + ): ConnectionSpec { val socketEnabledCipherSuites = sslSocket.enabledCipherSuites var cipherSuitesIntersection: Array = effectiveCipherSuites(socketEnabledCipherSuites) - val tlsVersionsIntersection = if (tlsVersionsAsString != null) { - sslSocket.enabledProtocols.intersect(tlsVersionsAsString, naturalOrder()) - } else { - sslSocket.enabledProtocols - } + val tlsVersionsIntersection = + if (tlsVersionsAsString != null) { + sslSocket.enabledProtocols.intersect(tlsVersionsAsString, naturalOrder()) + } else { + sslSocket.enabledProtocols + } // In accordance with https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 the SCSV // cipher is added to signal that a protocol fallback has taken place. val supportedCipherSuites = sslSocket.supportedCipherSuites - val indexOfFallbackScsv = supportedCipherSuites.indexOf( - "TLS_FALLBACK_SCSV", CipherSuite.ORDER_BY_NAME) + val indexOfFallbackScsv = + supportedCipherSuites.indexOf( + "TLS_FALLBACK_SCSV", + CipherSuite.ORDER_BY_NAME, + ) if (isFallback && indexOfFallbackScsv != -1) { - cipherSuitesIntersection = cipherSuitesIntersection.concat( - supportedCipherSuites[indexOfFallbackScsv]) + cipherSuitesIntersection = + cipherSuitesIntersection.concat( + supportedCipherSuites[indexOfFallbackScsv], + ) } return Builder(this) - .cipherSuites(*cipherSuitesIntersection) - .tlsVersions(*tlsVersionsIntersection) - .build() + .cipherSuites(*cipherSuitesIntersection) + .tlsVersions(*tlsVersionsIntersection) + .build() } /** @@ -149,13 +165,16 @@ class ConnectionSpec internal constructor( } if (tlsVersionsAsString != null && - !tlsVersionsAsString.hasIntersection(socket.enabledProtocols, naturalOrder())) { + !tlsVersionsAsString.hasIntersection(socket.enabledProtocols, naturalOrder()) + ) { return false } if (cipherSuitesAsString != null && - !cipherSuitesAsString.hasIntersection( - socket.enabledCipherSuites, CipherSuite.ORDER_BY_NAME)) { + !cipherSuitesAsString.hasIntersection( + socket.enabledCipherSuites, CipherSuite.ORDER_BY_NAME, + ) + ) { return false } @@ -190,10 +209,12 @@ class ConnectionSpec internal constructor( override fun toString(): String { if (!isTls) return "ConnectionSpec()" - return ("ConnectionSpec(" + + return ( + "ConnectionSpec(" + "cipherSuites=${Objects.toString(cipherSuites, "[all enabled]")}, " + "tlsVersions=${Objects.toString(tlsVersions, "[all enabled]")}, " + - "supportsTlsExtensions=$supportsTlsExtensions)") + "supportsTlsExtensions=$supportsTlsExtensions)" + ) } class Builder { @@ -213,84 +234,95 @@ class ConnectionSpec internal constructor( this.supportsTlsExtensions = connectionSpec.supportsTlsExtensions } - fun allEnabledCipherSuites() = apply { - require(tls) { "no cipher suites for cleartext connections" } - this.cipherSuites = null - } - - fun cipherSuites(vararg cipherSuites: CipherSuite): Builder = apply { - require(tls) { "no cipher suites for cleartext connections" } - val strings = cipherSuites.map { it.javaName }.toTypedArray() - return cipherSuites(*strings) - } - - fun cipherSuites(vararg cipherSuites: String) = apply { - require(tls) { "no cipher suites for cleartext connections" } - require(cipherSuites.isNotEmpty()) { "At least one cipher suite is required" } - - this.cipherSuites = cipherSuites.copyOf() as Array // Defensive copy. - } - - fun allEnabledTlsVersions() = apply { - require(tls) { "no TLS versions for cleartext connections" } - this.tlsVersions = null - } - - fun tlsVersions(vararg tlsVersions: TlsVersion): Builder = apply { - require(tls) { "no TLS versions for cleartext connections" } - - val strings = tlsVersions.map { it.javaName }.toTypedArray() - return tlsVersions(*strings) - } - - fun tlsVersions(vararg tlsVersions: String) = apply { - require(tls) { "no TLS versions for cleartext connections" } - require(tlsVersions.isNotEmpty()) { "At least one TLS version is required" } - - this.tlsVersions = tlsVersions.copyOf() as Array // Defensive copy. - } - - @Deprecated("since OkHttp 3.13 all TLS-connections are expected to support TLS extensions.\n" + + fun allEnabledCipherSuites() = + apply { + require(tls) { "no cipher suites for cleartext connections" } + this.cipherSuites = null + } + + fun cipherSuites(vararg cipherSuites: CipherSuite): Builder = + apply { + require(tls) { "no cipher suites for cleartext connections" } + val strings = cipherSuites.map { it.javaName }.toTypedArray() + return cipherSuites(*strings) + } + + fun cipherSuites(vararg cipherSuites: String) = + apply { + require(tls) { "no cipher suites for cleartext connections" } + require(cipherSuites.isNotEmpty()) { "At least one cipher suite is required" } + + this.cipherSuites = cipherSuites.copyOf() as Array // Defensive copy. + } + + fun allEnabledTlsVersions() = + apply { + require(tls) { "no TLS versions for cleartext connections" } + this.tlsVersions = null + } + + fun tlsVersions(vararg tlsVersions: TlsVersion): Builder = + apply { + require(tls) { "no TLS versions for cleartext connections" } + + val strings = tlsVersions.map { it.javaName }.toTypedArray() + return tlsVersions(*strings) + } + + fun tlsVersions(vararg tlsVersions: String) = + apply { + require(tls) { "no TLS versions for cleartext connections" } + require(tlsVersions.isNotEmpty()) { "At least one TLS version is required" } + + this.tlsVersions = tlsVersions.copyOf() as Array // Defensive copy. + } + + @Deprecated( + "since OkHttp 3.13 all TLS-connections are expected to support TLS extensions.\n" + "In a future release setting this to true will be unnecessary and setting it to false\n" + - "will have no effect.") - fun supportsTlsExtensions(supportsTlsExtensions: Boolean) = apply { - require(tls) { "no TLS extensions for cleartext connections" } - this.supportsTlsExtensions = supportsTlsExtensions - } - - fun build(): ConnectionSpec = ConnectionSpec( + "will have no effect.", + ) + fun supportsTlsExtensions(supportsTlsExtensions: Boolean) = + apply { + require(tls) { "no TLS extensions for cleartext connections" } + this.supportsTlsExtensions = supportsTlsExtensions + } + + fun build(): ConnectionSpec = + ConnectionSpec( tls, supportsTlsExtensions, cipherSuites, - tlsVersions - ) + tlsVersions, + ) } @Suppress("DEPRECATION") companion object { // Most secure but generally supported list. - private val RESTRICTED_CIPHER_SUITES = listOf( + private val RESTRICTED_CIPHER_SUITES = + listOf( // TLSv1.3. CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_AES_256_GCM_SHA384, CipherSuite.TLS_CHACHA20_POLY1305_SHA256, - // TLSv1.0, TLSv1.1, TLSv1.2. CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) + CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + ) // This is nearly equal to the cipher suites supported in Chrome 72, current as of 2019-02-24. // See https://tinyurl.com/okhttp-cipher-suites for availability. - private val APPROVED_CIPHER_SUITES = listOf( + private val APPROVED_CIPHER_SUITES = + listOf( // TLSv1.3. CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_AES_256_GCM_SHA384, CipherSuite.TLS_CHACHA20_POLY1305_SHA256, - // TLSv1.0, TLSv1.1, TLSv1.2. CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, @@ -298,7 +330,6 @@ class ConnectionSpec internal constructor( CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - // Note that the following cipher suites are all on HTTP/2's bad cipher suites list. We'll // continue to include them until better suites are commonly available. CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, @@ -307,11 +338,13 @@ class ConnectionSpec internal constructor( CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, - CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA) + CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + ) /** A secure TLS connection that requires a recent client platform and a recent server. */ @JvmField - val RESTRICTED_TLS = Builder(true) + val RESTRICTED_TLS = + Builder(true) .cipherSuites(*RESTRICTED_CIPHER_SUITES.toTypedArray()) .tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2) .supportsTlsExtensions(true) @@ -322,7 +355,8 @@ class ConnectionSpec internal constructor( * This is OkHttp's default configuration. */ @JvmField - val MODERN_TLS = Builder(true) + val MODERN_TLS = + Builder(true) .cipherSuites(*APPROVED_CIPHER_SUITES.toTypedArray()) .tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2) .supportsTlsExtensions(true) @@ -334,7 +368,8 @@ class ConnectionSpec internal constructor( * rather than using this configuration. */ @JvmField - val COMPATIBLE_TLS = Builder(true) + val COMPATIBLE_TLS = + Builder(true) .cipherSuites(*APPROVED_CIPHER_SUITES.toTypedArray()) .tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0) .supportsTlsExtensions(true) diff --git a/okhttp/src/main/kotlin/okhttp3/Cookie.kt b/okhttp/src/main/kotlin/okhttp3/Cookie.kt index 3663fc6c560d..c0558422d90f 100644 --- a/okhttp/src/main/kotlin/okhttp3/Cookie.kt +++ b/okhttp/src/main/kotlin/okhttp3/Cookie.kt @@ -44,10 +44,8 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement class Cookie private constructor( /** Returns a non-empty string with this cookie's name. */ @get:JvmName("name") val name: String, - /** Returns a possibly-empty string with this cookie's value. */ @get:JvmName("value") val value: String, - /** * Returns the time that this cookie expires, in the same format as [System.currentTimeMillis]. * This is December 31, 9999 if the cookie is not [persistent], in which case it will expire at the @@ -58,36 +56,30 @@ class Cookie private constructor( * that may or may not themselves be expired. */ @get:JvmName("expiresAt") val expiresAt: Long, - /** * Returns the cookie's domain. If [hostOnly] returns true this is the only domain that matches * this cookie; otherwise it matches this domain and all subdomains. */ @get:JvmName("domain") val domain: String, - /** * Returns this cookie's path. This cookie matches URLs prefixed with path segments that match * this path's segments. For example, if this path is `/foo` this cookie matches requests to * `/foo` and `/foo/bar`, but not `/` or `/football`. */ @get:JvmName("path") val path: String, - /** Returns true if this cookie should be limited to only HTTPS requests. */ @get:JvmName("secure") val secure: Boolean, - /** * Returns true if this cookie should be limited to only HTTP APIs. In web browsers this prevents * the cookie from being accessible to scripts. */ @get:JvmName("httpOnly") val httpOnly: Boolean, - /** * Returns true if this cookie does not expire at the end of the current session. * * This is true if either 'expires' or 'max-age' is present. */ @get:JvmName("persistent") val persistent: Boolean, - /** * Returns true if this cookie's domain should be interpreted as a single host name, or false if * it should be interpreted as a pattern. This flag will be false if its `Set-Cookie` header @@ -100,7 +92,6 @@ class Cookie private constructor( * This is true unless 'domain' is present. */ @get:JvmName("hostOnly") val hostOnly: Boolean, - /** * Returns a string describing whether this cookie is sent for cross-site calls. * @@ -128,17 +119,17 @@ class Cookie private constructor( */ @get:JvmName("sameSite") val sameSite: String?, ) { - /** * Returns true if this cookie should be included on a request to [url]. In addition to this * check callers should also confirm that this cookie has not expired. */ fun matches(url: HttpUrl): Boolean { - val domainMatch = if (hostOnly) { - url.host == domain - } else { - domainMatch(url.host, domain) - } + val domainMatch = + if (hostOnly) { + url.host == domain + } else { + domainMatch(url.host, domain) + } if (!domainMatch) return false if (!pathMatch(url, path)) return false @@ -182,63 +173,72 @@ class Cookie private constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "name"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun name(): String = name @JvmName("-deprecated_value") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "value"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun value(): String = value @JvmName("-deprecated_persistent") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "persistent"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun persistent(): Boolean = persistent @JvmName("-deprecated_expiresAt") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "expiresAt"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun expiresAt(): Long = expiresAt @JvmName("-deprecated_hostOnly") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "hostOnly"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun hostOnly(): Boolean = hostOnly @JvmName("-deprecated_domain") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "domain"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun domain(): String = domain @JvmName("-deprecated_path") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "path"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun path(): String = path @JvmName("-deprecated_httpOnly") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "httpOnly"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun httpOnly(): Boolean = httpOnly @JvmName("-deprecated_secure") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "secure"), - level = DeprecationLevel.ERROR) + level = DeprecationLevel.ERROR, + ) fun secure(): Boolean = secure /** @@ -317,23 +317,26 @@ class Cookie private constructor( this.sameSite = cookie.sameSite } - fun name(name: String) = apply { - require(name.trim() == name) { "name is not trimmed" } - this.name = name - } + fun name(name: String) = + apply { + require(name.trim() == name) { "name is not trimmed" } + this.name = name + } - fun value(value: String) = apply { - require(value.trim() == value) { "value is not trimmed" } - this.value = value - } + fun value(value: String) = + apply { + require(value.trim() == value) { "value is not trimmed" } + this.value = value + } - fun expiresAt(expiresAt: Long) = apply { - var expiresAt = expiresAt - if (expiresAt <= 0L) expiresAt = Long.MIN_VALUE - if (expiresAt > MAX_DATE) expiresAt = MAX_DATE - this.expiresAt = expiresAt - this.persistent = true - } + fun expiresAt(expiresAt: Long) = + apply { + var expiresAt = expiresAt + if (expiresAt <= 0L) expiresAt = Long.MIN_VALUE + if (expiresAt > MAX_DATE) expiresAt = MAX_DATE + this.expiresAt = expiresAt + this.persistent = true + } /** * Set the domain pattern for this cookie. The cookie will match [domain] and all of its @@ -347,33 +350,40 @@ class Cookie private constructor( */ fun hostOnlyDomain(domain: String): Builder = domain(domain, true) - private fun domain(domain: String, hostOnly: Boolean) = apply { - val canonicalDomain = domain.toCanonicalHost() - ?: throw IllegalArgumentException("unexpected domain: $domain") + private fun domain( + domain: String, + hostOnly: Boolean, + ) = apply { + val canonicalDomain = + domain.toCanonicalHost() + ?: throw IllegalArgumentException("unexpected domain: $domain") this.domain = canonicalDomain this.hostOnly = hostOnly } - fun path(path: String) = apply { - require(path.startsWith("/")) { "path must start with '/'" } - this.path = path - } + fun path(path: String) = + apply { + require(path.startsWith("/")) { "path must start with '/'" } + this.path = path + } - fun secure() = apply { - this.secure = true - } + fun secure() = + apply { + this.secure = true + } - fun httpOnly() = apply { - this.httpOnly = true - } + fun httpOnly() = + apply { + this.httpOnly = true + } - fun sameSite(sameSite: String) = apply { - require(sameSite.trim() == sameSite) { "sameSite is not trimmed" } - this.sameSite = sameSite - } + fun sameSite(sameSite: String) = + apply { + require(sameSite.trim() == sameSite) { "sameSite is not trimmed" } + this.sameSite = sameSite + } fun build(): Cookie { - return Cookie( name ?: throw NullPointerException("builder.name == null"), value ?: throw NullPointerException("builder.value == null"), @@ -384,7 +394,7 @@ class Cookie private constructor( httpOnly, persistent, hostOnly, - sameSite + sameSite, ) } } @@ -397,7 +407,10 @@ class Cookie private constructor( private val DAY_OF_MONTH_PATTERN = Pattern.compile("(\\d{1,2})[^\\d]*") private val TIME_PATTERN = Pattern.compile("(\\d{1,2}):(\\d{1,2}):(\\d{1,2})[^\\d]*") - private fun domainMatch(urlHost: String, domain: String): Boolean { + private fun domainMatch( + urlHost: String, + domain: String, + ): Boolean { if (urlHost == domain) { return true // As in 'example.com' matching 'example.com'. } @@ -407,7 +420,10 @@ class Cookie private constructor( !urlHost.canParseAsIpAddress() } - private fun pathMatch(url: HttpUrl, path: String): Boolean { + private fun pathMatch( + url: HttpUrl, + path: String, + ): Boolean { val urlPath = url.encodedPath if (urlPath == path) { @@ -427,10 +443,16 @@ class Cookie private constructor( * [setCookie] is not a well-formed cookie. */ @JvmStatic - fun parse(url: HttpUrl, setCookie: String): Cookie? = - parse(System.currentTimeMillis(), url, setCookie) - - internal fun parse(currentTimeMillis: Long, url: HttpUrl, setCookie: String): Cookie? { + fun parse( + url: HttpUrl, + setCookie: String, + ): Cookie? = parse(System.currentTimeMillis(), url, setCookie) + + internal fun parse( + currentTimeMillis: Long, + url: HttpUrl, + setCookie: String, + ): Cookie? { val cookiePairEnd = setCookie.delimiterOffset(';') val pairEqualsSign = setCookie.delimiterOffset('=', endIndex = cookiePairEnd) @@ -459,11 +481,12 @@ class Cookie private constructor( val attributeEqualsSign = setCookie.delimiterOffset('=', pos, attributePairEnd) val attributeName = setCookie.trimSubstring(pos, attributeEqualsSign) - val attributeValue = if (attributeEqualsSign < attributePairEnd) { - setCookie.trimSubstring(attributeEqualsSign + 1, attributePairEnd) - } else { - "" - } + val attributeValue = + if (attributeEqualsSign < attributePairEnd) { + setCookie.trimSubstring(attributeEqualsSign + 1, attributePairEnd) + } else { + "" + } when { attributeName.equals("expires", ignoreCase = true) -> { @@ -512,11 +535,12 @@ class Cookie private constructor( if (deltaSeconds == Long.MIN_VALUE) { expiresAt = Long.MIN_VALUE } else if (deltaSeconds != -1L) { - val deltaMilliseconds = if (deltaSeconds <= Long.MAX_VALUE / 1000) { - deltaSeconds * 1000 - } else { - Long.MAX_VALUE - } + val deltaMilliseconds = + if (deltaSeconds <= Long.MAX_VALUE / 1000) { + deltaSeconds * 1000 + } else { + Long.MAX_VALUE + } expiresAt = currentTimeMillis + deltaMilliseconds if (expiresAt < currentTimeMillis || expiresAt > MAX_DATE) { expiresAt = MAX_DATE // Handle overflow & limit the date range. @@ -533,7 +557,8 @@ class Cookie private constructor( // If the domain is a suffix of the url host, it must not be a public suffix. if (urlHost.length != domain.length && - PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain) == null) { + PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain) == null + ) { return null } @@ -545,12 +570,18 @@ class Cookie private constructor( path = if (lastSlash != 0) encodedPath.substring(0, lastSlash) else "/" } - return Cookie(cookieName, cookieValue, expiresAt, domain, path, secureOnly, httpOnly, - persistent, hostOnly, sameSite) + return Cookie( + cookieName, cookieValue, expiresAt, domain, path, secureOnly, httpOnly, + persistent, hostOnly, sameSite, + ) } /** Parse a date as specified in RFC 6265, section 5.1.1. */ - private fun parseExpires(s: String, pos: Int, limit: Int): Long { + private fun parseExpires( + s: String, + pos: Int, + limit: Int, + ): Long { var pos = pos pos = dateCharacterOffset(s, pos, limit, false) @@ -617,14 +648,21 @@ class Cookie private constructor( * Returns the index of the next date character in `input`, or if `invert` the index * of the next non-date character in `input`. */ - private fun dateCharacterOffset(input: String, pos: Int, limit: Int, invert: Boolean): Int { + private fun dateCharacterOffset( + input: String, + pos: Int, + limit: Int, + invert: Boolean, + ): Int { for (i in pos until limit) { val c = input[i].code - val dateCharacter = (c < ' '.code && c != '\t'.code || c >= '\u007f'.code || - c in '0'.code..'9'.code || - c in 'a'.code..'z'.code || - c in 'A'.code..'Z'.code || - c == ':'.code) + val dateCharacter = ( + c < ' '.code && c != '\t'.code || c >= '\u007f'.code || + c in '0'.code..'9'.code || + c in 'a'.code..'z'.code || + c in 'A'.code..'Z'.code || + c == ':'.code + ) if (dateCharacter == !invert) return i } return limit @@ -660,7 +698,10 @@ class Cookie private constructor( /** Returns all of the cookies from a set of HTTP response headers. */ @JvmStatic - fun parseAll(url: HttpUrl, headers: Headers): List { + fun parseAll( + url: HttpUrl, + headers: Headers, + ): List { val cookieStrings = headers.values("Set-Cookie") var cookies: MutableList? = null diff --git a/okhttp/src/main/kotlin/okhttp3/CookieJar.kt b/okhttp/src/main/kotlin/okhttp3/CookieJar.kt index 52eebf251e0d..a8cc3ac20356 100644 --- a/okhttp/src/main/kotlin/okhttp3/CookieJar.kt +++ b/okhttp/src/main/kotlin/okhttp3/CookieJar.kt @@ -37,7 +37,10 @@ interface CookieJar { * includes a trailer. For this obscure HTTP feature, [cookies] contains only the trailer's * cookies. */ - fun saveFromResponse(url: HttpUrl, cookies: List) + fun saveFromResponse( + url: HttpUrl, + cookies: List, + ) /** * Load cookies from the jar for an HTTP request to [url]. This method returns a possibly @@ -52,8 +55,12 @@ interface CookieJar { /** A cookie jar that never accepts any cookies. */ @JvmField val NO_COOKIES: CookieJar = NoCookies() + private class NoCookies : CookieJar { - override fun saveFromResponse(url: HttpUrl, cookies: List) { + override fun saveFromResponse( + url: HttpUrl, + cookies: List, + ) { } override fun loadForRequest(url: HttpUrl): List { diff --git a/okhttp/src/main/kotlin/okhttp3/Credentials.kt b/okhttp/src/main/kotlin/okhttp3/Credentials.kt index 5ae99cc8287d..4f147d083549 100644 --- a/okhttp/src/main/kotlin/okhttp3/Credentials.kt +++ b/okhttp/src/main/kotlin/okhttp3/Credentials.kt @@ -22,10 +22,11 @@ import okio.ByteString.Companion.encode /** Factory for HTTP authorization credentials. */ object Credentials { /** Returns an auth credential for the Basic scheme. */ - @JvmStatic @JvmOverloads fun basic( + @JvmStatic @JvmOverloads + fun basic( username: String, password: String, - charset: Charset = ISO_8859_1 + charset: Charset = ISO_8859_1, ): String { val usernameAndPassword = "$username:$password" val encoded = usernameAndPassword.encode(charset).base64() diff --git a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt index 29f686dfb7ba..ad4cd30c4419 100644 --- a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt +++ b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt @@ -89,11 +89,15 @@ class Dispatcher() { private var executorServiceOrNull: ExecutorService? = null @get:Synchronized - @get:JvmName("executorService") val executorService: ExecutorService + @get:JvmName("executorService") + val executorService: ExecutorService get() { if (executorServiceOrNull == null) { - executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS, - SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false)) + executorServiceOrNull = + ThreadPoolExecutor( + 0, Int.MAX_VALUE, 60, TimeUnit.SECONDS, + SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false), + ) } return executorServiceOrNull!! } @@ -183,17 +187,17 @@ class Dispatcher() { // particularly because RealCall handles a RejectedExecutionException // by executing on the same thread. if (executorService.isShutdown) { - for (i in 0 until executableCalls.size) { - val asyncCall = executableCalls[i] - asyncCall.callsPerHost.decrementAndGet() - - synchronized(this) { - runningAsyncCalls.remove(asyncCall) - } + for (i in 0 until executableCalls.size) { + val asyncCall = executableCalls[i] + asyncCall.callsPerHost.decrementAndGet() - asyncCall.failRejected() + synchronized(this) { + runningAsyncCalls.remove(asyncCall) } - idleCallback?.run() + + asyncCall.failRejected() + } + idleCallback?.run() } else { for (i in 0 until executableCalls.size) { val asyncCall = executableCalls[i] @@ -220,7 +224,10 @@ class Dispatcher() { finished(runningSyncCalls, call) } - private fun finished(calls: Deque, call: T) { + private fun finished( + calls: Deque, + call: T, + ) { val idleCallback: Runnable? synchronized(this) { if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!") @@ -250,8 +257,9 @@ class Dispatcher() { @JvmName("-deprecated_executorService") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "executorService"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "executorService"), + level = DeprecationLevel.ERROR, + ) fun executorService(): ExecutorService = executorService } diff --git a/okhttp/src/main/kotlin/okhttp3/Dns.kt b/okhttp/src/main/kotlin/okhttp3/Dns.kt index 60cc8b83726c..d7fdd38d564c 100644 --- a/okhttp/src/main/kotlin/okhttp3/Dns.kt +++ b/okhttp/src/main/kotlin/okhttp3/Dns.kt @@ -43,6 +43,7 @@ fun interface Dns { */ @JvmField val SYSTEM: Dns = DnsSystem() + private class DnsSystem : Dns { override fun lookup(hostname: String): List { try { diff --git a/okhttp/src/main/kotlin/okhttp3/EventListener.kt b/okhttp/src/main/kotlin/okhttp3/EventListener.kt index 7abb1d4486fe..42a08988a215 100644 --- a/okhttp/src/main/kotlin/okhttp3/EventListener.kt +++ b/okhttp/src/main/kotlin/okhttp3/EventListener.kt @@ -66,9 +66,7 @@ abstract class EventListener { * This will be invoked only once for a single [Call]. Retries of different routes or redirects * will be handled within the boundaries of a single [callStart] and [callEnd]/[callFailed] pair. */ - open fun callStart( - call: Call - ) { + open fun callStart(call: Call) { } /** @@ -81,7 +79,7 @@ abstract class EventListener { */ open fun proxySelectStart( call: Call, - url: HttpUrl + url: HttpUrl, ) { } @@ -103,7 +101,7 @@ abstract class EventListener { open fun proxySelectEnd( call: Call, url: HttpUrl, - proxies: List<@JvmSuppressWildcards Proxy> + proxies: List<@JvmSuppressWildcards Proxy>, ) { } @@ -118,7 +116,7 @@ abstract class EventListener { */ open fun dnsStart( call: Call, - domainName: String + domainName: String, ) { } @@ -130,7 +128,7 @@ abstract class EventListener { open fun dnsEnd( call: Call, domainName: String, - inetAddressList: List<@JvmSuppressWildcards InetAddress> + inetAddressList: List<@JvmSuppressWildcards InetAddress>, ) { } @@ -145,7 +143,7 @@ abstract class EventListener { open fun connectStart( call: Call, inetSocketAddress: InetSocketAddress, - proxy: Proxy + proxy: Proxy, ) { } @@ -161,9 +159,7 @@ abstract class EventListener { * This can be invoked more than 1 time for a single [Call]. For example, if the response to the * [Call.request] is a redirect to a different address, or a connection is retried. */ - open fun secureConnectStart( - call: Call - ) { + open fun secureConnectStart(call: Call) { } /** @@ -173,7 +169,7 @@ abstract class EventListener { */ open fun secureConnectEnd( call: Call, - handshake: Handshake? + handshake: Handshake?, ) { } @@ -187,7 +183,7 @@ abstract class EventListener { call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, - protocol: Protocol? + protocol: Protocol?, ) { } @@ -203,7 +199,7 @@ abstract class EventListener { inetSocketAddress: InetSocketAddress, proxy: Proxy, protocol: Protocol?, - ioe: IOException + ioe: IOException, ) { } @@ -215,7 +211,7 @@ abstract class EventListener { */ open fun connectionAcquired( call: Call, - connection: Connection + connection: Connection, ) { } @@ -229,7 +225,7 @@ abstract class EventListener { */ open fun connectionReleased( call: Call, - connection: Connection + connection: Connection, ) { } @@ -241,9 +237,7 @@ abstract class EventListener { * This can be invoked more than 1 time for a single [Call]. For example, if the response to the * [Call.request] is a redirect to a different address. */ - open fun requestHeadersStart( - call: Call - ) { + open fun requestHeadersStart(call: Call) { } /** @@ -254,7 +248,10 @@ abstract class EventListener { * @param request the request sent over the network. It is an error to access the body of this * request. */ - open fun requestHeadersEnd(call: Call, request: Request) { + open fun requestHeadersEnd( + call: Call, + request: Request, + ) { } /** @@ -266,9 +263,7 @@ abstract class EventListener { * This can be invoked more than 1 time for a single [Call]. For example, if the response to the * [Call.request] is a redirect to a different address. */ - open fun requestBodyStart( - call: Call - ) { + open fun requestBodyStart(call: Call) { } /** @@ -278,7 +273,7 @@ abstract class EventListener { */ open fun requestBodyEnd( call: Call, - byteCount: Long + byteCount: Long, ) { } @@ -290,7 +285,7 @@ abstract class EventListener { */ open fun requestFailed( call: Call, - ioe: IOException + ioe: IOException, ) { } @@ -305,9 +300,7 @@ abstract class EventListener { * Prior to OkHttp 4.3 this was incorrectly invoked when the client was ready to read headers. * This was misleading for tracing because it was too early. */ - open fun responseHeadersStart( - call: Call - ) { + open fun responseHeadersStart(call: Call) { } /** @@ -320,7 +313,7 @@ abstract class EventListener { */ open fun responseHeadersEnd( call: Call, - response: Response + response: Response, ) { } @@ -341,9 +334,7 @@ abstract class EventListener { * Prior to OkHttp 4.3 this was incorrectly invoked when the client was ready to read the response * body. This was misleading for tracing because it was too early. */ - open fun responseBodyStart( - call: Call - ) { + open fun responseBodyStart(call: Call) { } /** @@ -360,7 +351,7 @@ abstract class EventListener { */ open fun responseBodyEnd( call: Call, - byteCount: Long + byteCount: Long, ) { } @@ -375,7 +366,7 @@ abstract class EventListener { */ open fun responseFailed( call: Call, - ioe: IOException + ioe: IOException, ) { } @@ -385,9 +376,7 @@ abstract class EventListener { * * This method is always invoked after [callStart]. */ - open fun callEnd( - call: Call - ) { + open fun callEnd(call: Call) { } /** @@ -397,7 +386,7 @@ abstract class EventListener { */ open fun callFailed( call: Call, - ioe: IOException + ioe: IOException, ) { } @@ -417,16 +406,17 @@ abstract class EventListener { * This is invoked at most once, even if [Call.cancel] is invoked multiple times. It may be * invoked at any point in a call's life, including before [callStart] and after [callEnd]. */ - open fun canceled( - call: Call - ) { + open fun canceled(call: Call) { } /** * Invoked when a call fails due to cache rules. * For example, we're forbidden from using the network and the cache is insufficient */ - open fun satisfactionFailure(call: Call, response: Response) { + open fun satisfactionFailure( + call: Call, + response: Response, + ) { } /** @@ -435,7 +425,10 @@ abstract class EventListener { * * This event will only be received when a Cache is configured for the client. */ - open fun cacheHit(call: Call, response: Response) { + open fun cacheHit( + call: Call, + response: Response, + ) { } /** @@ -454,7 +447,10 @@ abstract class EventListener { * * This event will only be received when a Cache is configured for the client. */ - open fun cacheConditionalHit(call: Call, cachedResponse: Response) { + open fun cacheConditionalHit( + call: Call, + cachedResponse: Response, + ) { } fun interface Factory { @@ -472,7 +468,8 @@ abstract class EventListener { companion object { @JvmField - val NONE: EventListener = object : EventListener() { - } + val NONE: EventListener = + object : EventListener() { + } } } diff --git a/okhttp/src/main/kotlin/okhttp3/ExperimentalOkHttpApi.kt b/okhttp/src/main/kotlin/okhttp3/ExperimentalOkHttpApi.kt index 73a4649479c7..082eeeec677e 100644 --- a/okhttp/src/main/kotlin/okhttp3/ExperimentalOkHttpApi.kt +++ b/okhttp/src/main/kotlin/okhttp3/ExperimentalOkHttpApi.kt @@ -40,7 +40,7 @@ package okhttp3 AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, - AnnotationTarget.TYPEALIAS + AnnotationTarget.TYPEALIAS, ) @RequiresOptIn(level = RequiresOptIn.Level.ERROR) public annotation class ExperimentalOkHttpApi diff --git a/okhttp/src/main/kotlin/okhttp3/FormBody.kt b/okhttp/src/main/kotlin/okhttp3/FormBody.kt index b9a7c2a80a42..81b1cc7b9df0 100644 --- a/okhttp/src/main/kotlin/okhttp3/FormBody.kt +++ b/okhttp/src/main/kotlin/okhttp3/FormBody.kt @@ -27,20 +27,22 @@ import okio.BufferedSink class FormBody internal constructor( encodedNames: List, - encodedValues: List + encodedValues: List, ) : RequestBody() { private val encodedNames: List = encodedNames.toImmutableList() private val encodedValues: List = encodedValues.toImmutableList() /** The number of key-value pairs in this form-encoded body. */ - @get:JvmName("size") val size: Int + @get:JvmName("size") + val size: Int get() = encodedNames.size @JvmName("-deprecated_size") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "size"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "size"), + level = DeprecationLevel.ERROR, + ) fun size(): Int = size fun encodedName(index: Int): String = encodedNames[index] @@ -66,7 +68,10 @@ class FormBody internal constructor( * to awkward operations like measuring the encoded length of header strings, or the * length-in-digits of an encoded integer. */ - private fun writeOrCountBytes(sink: BufferedSink?, countBytes: Boolean): Long { + private fun writeOrCountBytes( + sink: BufferedSink?, + countBytes: Boolean, + ): Long { var byteCount = 0L val buffer: Buffer = if (countBytes) Buffer() else sink!!.buffer @@ -85,43 +90,55 @@ class FormBody internal constructor( return byteCount } - class Builder @JvmOverloads constructor(private val charset: Charset? = null) { - private val names = mutableListOf() - private val values = mutableListOf() - - fun add(name: String, value: String) = apply { - names += name.canonicalizeWithCharset( - encodeSet = FORM_ENCODE_SET, - // Plus is encoded as `%2B`, space is encoded as plus. - plusIsSpace = false, - charset = charset - ) - values += value.canonicalizeWithCharset( - encodeSet = FORM_ENCODE_SET, - // Plus is encoded as `%2B`, space is encoded as plus. - plusIsSpace = false, - charset = charset - ) + class Builder + @JvmOverloads + constructor(private val charset: Charset? = null) { + private val names = mutableListOf() + private val values = mutableListOf() + + fun add( + name: String, + value: String, + ) = apply { + names += + name.canonicalizeWithCharset( + encodeSet = FORM_ENCODE_SET, + // Plus is encoded as `%2B`, space is encoded as plus. + plusIsSpace = false, + charset = charset, + ) + values += + value.canonicalizeWithCharset( + encodeSet = FORM_ENCODE_SET, + // Plus is encoded as `%2B`, space is encoded as plus. + plusIsSpace = false, + charset = charset, + ) + } + + fun addEncoded( + name: String, + value: String, + ) = apply { + names += + name.canonicalizeWithCharset( + encodeSet = FORM_ENCODE_SET, + alreadyEncoded = true, + plusIsSpace = true, + charset = charset, + ) + values += + value.canonicalizeWithCharset( + encodeSet = FORM_ENCODE_SET, + alreadyEncoded = true, + plusIsSpace = true, + charset = charset, + ) + } + + fun build(): FormBody = FormBody(names, values) } - fun addEncoded(name: String, value: String) = apply { - names += name.canonicalizeWithCharset( - encodeSet = FORM_ENCODE_SET, - alreadyEncoded = true, - plusIsSpace = true, - charset = charset - ) - values += value.canonicalizeWithCharset( - encodeSet = FORM_ENCODE_SET, - alreadyEncoded = true, - plusIsSpace = true, - charset = charset - ) - } - - fun build(): FormBody = FormBody(names, values) - } - companion object { private val CONTENT_TYPE: MediaType = "application/x-www-form-urlencoded".toMediaType() } diff --git a/okhttp/src/main/kotlin/okhttp3/Handshake.kt b/okhttp/src/main/kotlin/okhttp3/Handshake.kt index 6b0f8c70314c..9c3d9c0edc06 100644 --- a/okhttp/src/main/kotlin/okhttp3/Handshake.kt +++ b/okhttp/src/main/kotlin/okhttp3/Handshake.kt @@ -37,18 +37,16 @@ class Handshake internal constructor( * 3.0. For responses cached by preceding versions this returns [TlsVersion.SSL_3_0]. */ @get:JvmName("tlsVersion") val tlsVersion: TlsVersion, - /** Returns the cipher suite used for the connection. */ @get:JvmName("cipherSuite") val cipherSuite: CipherSuite, - /** Returns a possibly-empty list of certificates that identify this peer. */ @get:JvmName("localCertificates") val localCertificates: List, - // Delayed provider of peerCertificates, to allow lazy cleaning. - peerCertificatesFn: () -> List + peerCertificatesFn: () -> List, ) { /** Returns a possibly-empty list of certificates that identify the remote peer. */ - @get:JvmName("peerCertificates") val peerCertificates: List by lazy { + @get:JvmName("peerCertificates") + val peerCertificates: List by lazy { try { peerCertificatesFn() } catch (spue: SSLPeerUnverifiedException) { @@ -58,23 +56,26 @@ class Handshake internal constructor( @JvmName("-deprecated_tlsVersion") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "tlsVersion"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "tlsVersion"), + level = DeprecationLevel.ERROR, + ) fun tlsVersion(): TlsVersion = tlsVersion @JvmName("-deprecated_cipherSuite") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "cipherSuite"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "cipherSuite"), + level = DeprecationLevel.ERROR, + ) fun cipherSuite(): CipherSuite = cipherSuite @JvmName("-deprecated_peerCertificates") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "peerCertificates"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "peerCertificates"), + level = DeprecationLevel.ERROR, + ) fun peerCertificates(): List = peerCertificates /** Returns the remote peer's principle, or null if that peer is anonymous. */ @@ -84,16 +85,18 @@ class Handshake internal constructor( @JvmName("-deprecated_peerPrincipal") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "peerPrincipal"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "peerPrincipal"), + level = DeprecationLevel.ERROR, + ) fun peerPrincipal(): Principal? = peerPrincipal @JvmName("-deprecated_localCertificates") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "localCertificates"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "localCertificates"), + level = DeprecationLevel.ERROR, + ) fun localCertificates(): List = localCertificates /** Returns the local principle, or null if this peer is anonymous. */ @@ -103,17 +106,18 @@ class Handshake internal constructor( @JvmName("-deprecated_localPrincipal") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "localPrincipal"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "localPrincipal"), + level = DeprecationLevel.ERROR, + ) fun localPrincipal(): Principal? = localPrincipal override fun equals(other: Any?): Boolean { return other is Handshake && - other.tlsVersion == tlsVersion && - other.cipherSuite == cipherSuite && - other.peerCertificates == peerCertificates && - other.localCertificates == localCertificates + other.tlsVersion == tlsVersion && + other.cipherSuite == cipherSuite && + other.peerCertificates == peerCertificates && + other.localCertificates == localCertificates } override fun hashCode(): Int { @@ -128,42 +132,48 @@ class Handshake internal constructor( override fun toString(): String { val peerCertificatesString = peerCertificates.map { it.name }.toString() return "Handshake{" + - "tlsVersion=$tlsVersion " + - "cipherSuite=$cipherSuite " + - "peerCertificates=$peerCertificatesString " + - "localCertificates=${localCertificates.map { it.name }}}" + "tlsVersion=$tlsVersion " + + "cipherSuite=$cipherSuite " + + "peerCertificates=$peerCertificatesString " + + "localCertificates=${localCertificates.map { it.name }}}" } private val Certificate.name: String - get() = when (this) { - is X509Certificate -> subjectDN.toString() - else -> type - } + get() = + when (this) { + is X509Certificate -> subjectDN.toString() + else -> type + } companion object { @Throws(IOException::class) @JvmStatic @JvmName("get") fun SSLSession.handshake(): Handshake { - val cipherSuite = when (val cipherSuiteString = checkNotNull(cipherSuite) { "cipherSuite == null" }) { - "TLS_NULL_WITH_NULL_NULL", "SSL_NULL_WITH_NULL_NULL" -> { - throw IOException("cipherSuite == $cipherSuiteString") + val cipherSuite = + when (val cipherSuiteString = checkNotNull(cipherSuite) { "cipherSuite == null" }) { + "TLS_NULL_WITH_NULL_NULL", "SSL_NULL_WITH_NULL_NULL" -> { + throw IOException("cipherSuite == $cipherSuiteString") + } + else -> CipherSuite.forJavaName(cipherSuiteString) } - else -> CipherSuite.forJavaName(cipherSuiteString) - } val tlsVersionString = checkNotNull(protocol) { "tlsVersion == null" } if ("NONE" == tlsVersionString) throw IOException("tlsVersion == NONE") val tlsVersion = TlsVersion.forJavaName(tlsVersionString) - val peerCertificatesCopy = try { - peerCertificates.toImmutableList() - } catch (_: SSLPeerUnverifiedException) { - listOf() - } + val peerCertificatesCopy = + try { + peerCertificates.toImmutableList() + } catch (_: SSLPeerUnverifiedException) { + listOf() + } - return Handshake(tlsVersion, cipherSuite, - localCertificates.toImmutableList()) { peerCertificatesCopy } + return Handshake( + tlsVersion, + cipherSuite, + localCertificates.toImmutableList(), + ) { peerCertificatesCopy } } private fun Array?.toImmutableList(): List { @@ -177,9 +187,10 @@ class Handshake internal constructor( @Throws(IOException::class) @JvmName("-deprecated_get") @Deprecated( - message = "moved to extension function", - replaceWith = ReplaceWith(expression = "sslSession.handshake()"), - level = DeprecationLevel.ERROR) + message = "moved to extension function", + replaceWith = ReplaceWith(expression = "sslSession.handshake()"), + level = DeprecationLevel.ERROR, + ) fun get(sslSession: SSLSession) = sslSession.handshake() @JvmStatic @@ -187,7 +198,7 @@ class Handshake internal constructor( tlsVersion: TlsVersion, cipherSuite: CipherSuite, peerCertificates: List, - localCertificates: List + localCertificates: List, ): Handshake { val peerCertificatesCopy = peerCertificates.toImmutableList() return Handshake(tlsVersion, cipherSuite, localCertificates.toImmutableList()) { diff --git a/okhttp/src/main/kotlin/okhttp3/Headers.kt b/okhttp/src/main/kotlin/okhttp3/Headers.kt index da74b0504bdc..4313b1e2b356 100644 --- a/okhttp/src/main/kotlin/okhttp3/Headers.kt +++ b/okhttp/src/main/kotlin/okhttp3/Headers.kt @@ -64,7 +64,7 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement */ @Suppress("NAME_SHADOWING") class Headers internal constructor( - internal val namesAndValues: Array + internal val namesAndValues: Array, ) : Iterable> { /** Returns the last value corresponding to the specified field, or null. */ operator fun get(name: String): String? = commonHeadersGet(namesAndValues, name) @@ -85,14 +85,16 @@ class Headers internal constructor( } /** Returns the number of field values. */ - @get:JvmName("size") val size: Int + @get:JvmName("size") + val size: Int get() = namesAndValues.size / 2 @JvmName("-deprecated_size") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "size"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "size"), + level = DeprecationLevel.ERROR, + ) fun size(): Int = size /** Returns the field at `position`. */ @@ -208,41 +210,49 @@ class Headers internal constructor( * Add a header line without any validation. Only appropriate for headers from the remote peer * or cache. */ - internal fun addLenient(line: String) = apply { - val index = line.indexOf(':', 1) - when { - index != -1 -> { - addLenient(line.substring(0, index), line.substring(index + 1)) - } - line[0] == ':' -> { - // Work around empty header names and header names that start with a colon (created by old - // broken SPDY versions of the response cache). - addLenient("", line.substring(1)) // Empty header name. - } - else -> { - // No header name. - addLenient("", line) + internal fun addLenient(line: String) = + apply { + val index = line.indexOf(':', 1) + when { + index != -1 -> { + addLenient(line.substring(0, index), line.substring(index + 1)) + } + line[0] == ':' -> { + // Work around empty header names and header names that start with a colon (created by old + // broken SPDY versions of the response cache). + addLenient("", line.substring(1)) // Empty header name. + } + else -> { + // No header name. + addLenient("", line) + } } } - } /** Add an header line containing a field name, a literal colon, and a value. */ - fun add(line: String) = apply { - val index = line.indexOf(':') - require(index != -1) { "Unexpected header: $line" } - add(line.substring(0, index).trim(), line.substring(index + 1)) - } + fun add(line: String) = + apply { + val index = line.indexOf(':') + require(index != -1) { "Unexpected header: $line" } + add(line.substring(0, index).trim(), line.substring(index + 1)) + } /** * Add a header with the specified name and value. Does validation of header names and values. */ - fun add(name: String, value: String) = commonAdd(name, value) + fun add( + name: String, + value: String, + ) = commonAdd(name, value) /** * Add a header with the specified name and value. Does validation of header names, allowing * non-ASCII values. */ - fun addUnsafeNonAscii(name: String, value: String) = apply { + fun addUnsafeNonAscii( + name: String, + value: String, + ) = apply { headersCheckName(name) addLenient(name, value) } @@ -256,20 +266,29 @@ class Headers internal constructor( * Add a header with the specified name and formatted date. Does validation of header names and * value. */ - fun add(name: String, value: Date) = add(name, value.toHttpDateString()) + fun add( + name: String, + value: Date, + ) = add(name, value.toHttpDateString()) /** * Add a header with the specified name and formatted instant. Does validation of header names * and value. */ @IgnoreJRERequirement // Only programs that already have Instant will use this. - fun add(name: String, value: Instant) = add(name, Date.from(value)) + fun add( + name: String, + value: Instant, + ) = add(name, Date.from(value)) /** * Set a field with the specified date. If the field is not found, it is added. If the field is * found, the existing values are replaced. */ - operator fun set(name: String, value: Date) = set(name, value.toHttpDateString()) + operator fun set( + name: String, + value: Date, + ) = set(name, value.toHttpDateString()) /** * Set a field with the specified instant. If the field is not found, it is added. If the field @@ -282,7 +301,10 @@ class Headers internal constructor( * Add a field with the specified value without any validation. Only appropriate for headers * from the remote peer or cache. */ - internal fun addLenient(name: String, value: String) = commonAddLenient(name, value) + internal fun addLenient( + name: String, + value: String, + ) = commonAddLenient(name, value) fun removeAll(name: String) = commonRemoveAll(name) @@ -290,7 +312,10 @@ class Headers internal constructor( * Set a field with the specified value. If the field is not found, it is added. If the field is * found, the existing values are replaced. */ - operator fun set(name: String, value: String) = commonSet(name, value) + operator fun set( + name: String, + value: String, + ) = commonSet(name, value) /** Equivalent to `build().get(name)`, but potentially faster. */ operator fun get(name: String): String? = commonGet(name) @@ -309,9 +334,10 @@ class Headers internal constructor( @JvmName("-deprecated_of") @Deprecated( - message = "function name changed", - replaceWith = ReplaceWith(expression = "headersOf(*namesAndValues)"), - level = DeprecationLevel.ERROR) + message = "function name changed", + replaceWith = ReplaceWith(expression = "headersOf(*namesAndValues)"), + level = DeprecationLevel.ERROR, + ) fun of(vararg namesAndValues: String): Headers { return headersOf(*namesAndValues) } @@ -323,9 +349,10 @@ class Headers internal constructor( @JvmName("-deprecated_of") @Deprecated( - message = "function moved to extension", - replaceWith = ReplaceWith(expression = "headers.toHeaders()"), - level = DeprecationLevel.ERROR) + message = "function moved to extension", + replaceWith = ReplaceWith(expression = "headers.toHeaders()"), + level = DeprecationLevel.ERROR, + ) fun of(headers: Map): Headers { return headers.toHeaders() } diff --git a/okhttp/src/main/kotlin/okhttp3/HttpUrl.kt b/okhttp/src/main/kotlin/okhttp3/HttpUrl.kt index 07dc1f77f625..d43055e00b5d 100644 --- a/okhttp/src/main/kotlin/okhttp3/HttpUrl.kt +++ b/okhttp/src/main/kotlin/okhttp3/HttpUrl.kt @@ -323,7 +323,6 @@ import okhttp3.internal.publicsuffix.PublicSuffixDatabase class HttpUrl internal constructor( /** Either "http" or "https". */ @get:JvmName("scheme") val scheme: String, - /** * The decoded username, or an empty string if none is present. * @@ -335,7 +334,6 @@ class HttpUrl internal constructor( * | `http://a%20b:c%20d@host/` | `"a b"` | */ @get:JvmName("username") val username: String, - /** * Returns the decoded password, or an empty string if none is present. * @@ -347,7 +345,6 @@ class HttpUrl internal constructor( * | `http://a%20b:c%20d@host/` | `"c d"` | */ @get:JvmName("password") val password: String, - /** * The host address suitable for use with [InetAddress.getAllByName]. May be: * @@ -367,7 +364,6 @@ class HttpUrl internal constructor( * | `http://xn--n3h.net/` | `"xn--n3h.net"` | */ @get:JvmName("host") val host: String, - /** * The explicitly-specified port if one was provided, or the default port for this URL's scheme. * For example, this returns 8443 for `https://square.com:8443/` and 443 for @@ -380,7 +376,6 @@ class HttpUrl internal constructor( * | `https://host/` | `443` | */ @get:JvmName("port") val port: Int, - /** * A list of path segments like `["a", "b", "c"]` for the URL `http://host/a/b/c`. This list is * never empty though it may contain a single empty string. @@ -392,14 +387,12 @@ class HttpUrl internal constructor( * | `http://host/a/b%20c/d"` | `["a", "b c", "d"]` | */ @get:JvmName("pathSegments") val pathSegments: List, - /** * Alternating, decoded query names and values, or null for no query. Names may be empty or * non-empty, but never null. Values are null if the name has no corresponding '=' separator, or * empty, or non-empty. */ internal val queryNamesAndValues: List?, - /** * This URL's fragment, like `"abc"` for `http://host/#abc`. This is null if the URL has no * fragment. @@ -412,15 +405,15 @@ class HttpUrl internal constructor( * | `http://host/#abc|def` | `"abc|def"` | */ @get:JvmName("fragment") val fragment: String?, - /** Canonical URL. */ - internal val url: String + internal val url: String, ) { val isHttps: Boolean get() = scheme == "https" /** Returns this URL as a [java.net.URL][URL]. */ - @JvmName("url") fun toUrl(): URL { + @JvmName("url") + fun toUrl(): URL { try { return URL(url) } catch (e: MalformedURLException) { @@ -441,7 +434,8 @@ class HttpUrl internal constructor( * These differences may have a significant consequence when the URI is interpreted by a * web server. For this reason the [URI class][URI] and this method should be avoided. */ - @JvmName("uri") fun toUri(): URI { + @JvmName("uri") + fun toUri(): URI { val uri = newBuilder().reencodeForUri().toString() return try { URI(uri) @@ -466,7 +460,8 @@ class HttpUrl internal constructor( * | `http://username:password@host/` | `"username"` | * | `http://a%20b:c%20d@host/` | `"a%20b"` | */ - @get:JvmName("encodedUsername") val encodedUsername: String + @get:JvmName("encodedUsername") + val encodedUsername: String get() = commonEncodedUsername /** @@ -479,7 +474,8 @@ class HttpUrl internal constructor( * | `http://username:password@host/` | `"password"` | * | `http://a%20b:c%20d@host/` | `"c%20d"` | */ - @get:JvmName("encodedPassword") val encodedPassword: String + @get:JvmName("encodedPassword") + val encodedPassword: String get() = commonEncodedPassword /** @@ -506,7 +502,8 @@ class HttpUrl internal constructor( * | `http://host/a/b/c` | `"/a/b/c"` | * | `http://host/a/b%20c/d` | `"/a/b%20c/d"` | */ - @get:JvmName("encodedPath") val encodedPath: String + @get:JvmName("encodedPath") + val encodedPath: String get() = commonEncodedPath /** @@ -519,7 +516,8 @@ class HttpUrl internal constructor( * | `http://host/a/b/c` | `["a", "b", "c"]` | * | `http://host/a/b%20c/d` | `["a", "b%20c", "d"]` | */ - @get:JvmName("encodedPathSegments") val encodedPathSegments: List + @get:JvmName("encodedPathSegments") + val encodedPathSegments: List get() = commonEncodedPathSegments /** @@ -534,7 +532,8 @@ class HttpUrl internal constructor( * | `http://host/?a=apple&a=apricot` | `"a=apple&a=apricot"` | * | `http://host/?a=apple&b` | `"a=apple&b"` | */ - @get:JvmName("encodedQuery") val encodedQuery: String? + @get:JvmName("encodedQuery") + val encodedQuery: String? get() = commonEncodedQuery /** @@ -550,7 +549,8 @@ class HttpUrl internal constructor( * | `http://host/?a=apple&a=apricot` | `"a=apple&a=apricot"` | * | `http://host/?a=apple&b` | `"a=apple&b"` | */ - @get:JvmName("query") val query: String? + @get:JvmName("query") + val query: String? get() = commonQuery /** @@ -566,7 +566,8 @@ class HttpUrl internal constructor( * | `http://host/?a=apple&a=apricot` | `2` | * | `http://host/?a=apple&b` | `2` | */ - @get:JvmName("querySize") val querySize: Int + @get:JvmName("querySize") + val querySize: Int get() = commonQuerySize /** @@ -595,7 +596,8 @@ class HttpUrl internal constructor( * | `http://host/?a=apple&a=apricot` | `["a"]` | * | `http://host/?a=apple&b` | `["a", "b"]` | */ - @get:JvmName("queryParameterNames") val queryParameterNames: Set + @get:JvmName("queryParameterNames") + val queryParameterNames: Set get() = commonQueryParameterNames /** @@ -715,135 +717,154 @@ class HttpUrl internal constructor( @JvmName("-deprecated_url") @Deprecated( - message = "moved to toUrl()", - replaceWith = ReplaceWith(expression = "toUrl()"), - level = DeprecationLevel.ERROR) + message = "moved to toUrl()", + replaceWith = ReplaceWith(expression = "toUrl()"), + level = DeprecationLevel.ERROR, + ) fun url(): URL = toUrl() @JvmName("-deprecated_uri") @Deprecated( - message = "moved to toUri()", - replaceWith = ReplaceWith(expression = "toUri()"), - level = DeprecationLevel.ERROR) + message = "moved to toUri()", + replaceWith = ReplaceWith(expression = "toUri()"), + level = DeprecationLevel.ERROR, + ) fun uri(): URI = toUri() @JvmName("-deprecated_scheme") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "scheme"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "scheme"), + level = DeprecationLevel.ERROR, + ) fun scheme(): String = scheme @JvmName("-deprecated_encodedUsername") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "encodedUsername"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "encodedUsername"), + level = DeprecationLevel.ERROR, + ) fun encodedUsername(): String = encodedUsername @JvmName("-deprecated_username") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "username"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "username"), + level = DeprecationLevel.ERROR, + ) fun username(): String = username @JvmName("-deprecated_encodedPassword") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "encodedPassword"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "encodedPassword"), + level = DeprecationLevel.ERROR, + ) fun encodedPassword(): String = encodedPassword @JvmName("-deprecated_password") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "password"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "password"), + level = DeprecationLevel.ERROR, + ) fun password(): String = password @JvmName("-deprecated_host") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "host"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "host"), + level = DeprecationLevel.ERROR, + ) fun host(): String = host @JvmName("-deprecated_port") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "port"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "port"), + level = DeprecationLevel.ERROR, + ) fun port(): Int = port @JvmName("-deprecated_pathSize") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "pathSize"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "pathSize"), + level = DeprecationLevel.ERROR, + ) fun pathSize(): Int = pathSize @JvmName("-deprecated_encodedPath") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "encodedPath"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "encodedPath"), + level = DeprecationLevel.ERROR, + ) fun encodedPath(): String = encodedPath @JvmName("-deprecated_encodedPathSegments") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "encodedPathSegments"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "encodedPathSegments"), + level = DeprecationLevel.ERROR, + ) fun encodedPathSegments(): List = encodedPathSegments @JvmName("-deprecated_pathSegments") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "pathSegments"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "pathSegments"), + level = DeprecationLevel.ERROR, + ) fun pathSegments(): List = pathSegments @JvmName("-deprecated_encodedQuery") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "encodedQuery"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "encodedQuery"), + level = DeprecationLevel.ERROR, + ) fun encodedQuery(): String? = encodedQuery @JvmName("-deprecated_query") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "query"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "query"), + level = DeprecationLevel.ERROR, + ) fun query(): String? = query @JvmName("-deprecated_querySize") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "querySize"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "querySize"), + level = DeprecationLevel.ERROR, + ) fun querySize(): Int = querySize @JvmName("-deprecated_queryParameterNames") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "queryParameterNames"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "queryParameterNames"), + level = DeprecationLevel.ERROR, + ) fun queryParameterNames(): Set = queryParameterNames @JvmName("-deprecated_encodedFragment") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "encodedFragment"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "encodedFragment"), + level = DeprecationLevel.ERROR, + ) fun encodedFragment(): String? = encodedFragment @JvmName("-deprecated_fragment") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "fragment"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "fragment"), + level = DeprecationLevel.ERROR, + ) fun fragment(): String? = fragment class Builder { @@ -893,9 +914,15 @@ class HttpUrl internal constructor( */ fun addEncodedPathSegments(encodedPathSegments: String): Builder = commonAddEncodedPathSegments(encodedPathSegments) - fun setPathSegment(index: Int, pathSegment: String) = commonSetPathSegment(index, pathSegment) + fun setPathSegment( + index: Int, + pathSegment: String, + ) = commonSetPathSegment(index, pathSegment) - fun setEncodedPathSegment(index: Int, encodedPathSegment: String) = commonSetEncodedPathSegment(index, encodedPathSegment) + fun setEncodedPathSegment( + index: Int, + encodedPathSegment: String, + ) = commonSetEncodedPathSegment(index, encodedPathSegment) fun removePathSegment(index: Int) = commonRemovePathSegment(index) @@ -906,14 +933,26 @@ class HttpUrl internal constructor( fun encodedQuery(encodedQuery: String?) = commonEncodedQuery(encodedQuery) /** Encodes the query parameter using UTF-8 and adds it to this URL's query string. */ - fun addQueryParameter(name: String, value: String?) = commonAddQueryParameter(name, value) + fun addQueryParameter( + name: String, + value: String?, + ) = commonAddQueryParameter(name, value) /** Adds the pre-encoded query parameter to this URL's query string. */ - fun addEncodedQueryParameter(encodedName: String, encodedValue: String?) = commonAddEncodedQueryParameter(encodedName, encodedValue) + fun addEncodedQueryParameter( + encodedName: String, + encodedValue: String?, + ) = commonAddEncodedQueryParameter(encodedName, encodedValue) - fun setQueryParameter(name: String, value: String?) = commonSetQueryParameter(name, value) + fun setQueryParameter( + name: String, + value: String?, + ) = commonSetQueryParameter(name, value) - fun setEncodedQueryParameter(encodedName: String, encodedValue: String?) = commonSetEncodedQueryParameter(encodedName, encodedValue) + fun setEncodedQueryParameter( + encodedName: String, + encodedValue: String?, + ) = commonSetEncodedQueryParameter(encodedName, encodedValue) fun removeAllQueryParameters(name: String) = commonRemoveAllQueryParameters(name) @@ -927,42 +966,49 @@ class HttpUrl internal constructor( * Re-encodes the components of this URL so that it satisfies (obsolete) RFC 2396, which is * particularly strict for certain components. */ - internal fun reencodeForUri() = apply { - host = host?.replace(Regex("[\"<>^`{|}]"), "") - - for (i in 0 until encodedPathSegments.size) { - encodedPathSegments[i] = encodedPathSegments[i].canonicalize( - encodeSet = PATH_SEGMENT_ENCODE_SET_URI, - alreadyEncoded = true, - strict = true - ) - } + internal fun reencodeForUri() = + apply { + host = host?.replace(Regex("[\"<>^`{|}]"), "") + + for (i in 0 until encodedPathSegments.size) { + encodedPathSegments[i] = + encodedPathSegments[i].canonicalize( + encodeSet = PATH_SEGMENT_ENCODE_SET_URI, + alreadyEncoded = true, + strict = true, + ) + } + + val encodedQueryNamesAndValues = this.encodedQueryNamesAndValues + if (encodedQueryNamesAndValues != null) { + for (i in 0 until encodedQueryNamesAndValues.size) { + encodedQueryNamesAndValues[i] = + encodedQueryNamesAndValues[i]?.canonicalize( + encodeSet = QUERY_COMPONENT_ENCODE_SET_URI, + alreadyEncoded = true, + strict = true, + plusIsSpace = true, + ) + } + } - val encodedQueryNamesAndValues = this.encodedQueryNamesAndValues - if (encodedQueryNamesAndValues != null) { - for (i in 0 until encodedQueryNamesAndValues.size) { - encodedQueryNamesAndValues[i] = encodedQueryNamesAndValues[i]?.canonicalize( - encodeSet = QUERY_COMPONENT_ENCODE_SET_URI, + encodedFragment = + encodedFragment?.canonicalize( + encodeSet = FRAGMENT_ENCODE_SET_URI, alreadyEncoded = true, strict = true, - plusIsSpace = true + unicodeAllowed = true, ) - } } - encodedFragment = encodedFragment?.canonicalize( - encodeSet = FRAGMENT_ENCODE_SET_URI, - alreadyEncoded = true, - strict = true, - unicodeAllowed = true - ) - } - fun build(): HttpUrl = commonBuild() override fun toString(): String = commonToString() - internal fun parse(base: HttpUrl?, input: String): Builder = commonParse(base, input) + internal fun parse( + base: HttpUrl?, + input: String, + ): Builder = commonParse(base, input) } companion object { @@ -975,7 +1021,8 @@ class HttpUrl internal constructor( * @throws IllegalArgumentException If this is not a well-formed HTTP or HTTPS URL. */ @JvmStatic - @JvmName("get") fun String.toHttpUrl(): HttpUrl = commonToHttpUrl() + @JvmName("get") + fun String.toHttpUrl(): HttpUrl = commonToHttpUrl() /** * Returns a new `HttpUrl` representing `url` if it is a well-formed HTTP or HTTPS URL, or null @@ -1000,44 +1047,48 @@ class HttpUrl internal constructor( @JvmName("-deprecated_get") @Deprecated( message = "moved to extension function", - replaceWith = ReplaceWith( - expression = "url.toHttpUrl()", - imports = ["okhttp3.HttpUrl.Companion.toHttpUrl"] - ), - level = DeprecationLevel.ERROR + replaceWith = + ReplaceWith( + expression = "url.toHttpUrl()", + imports = ["okhttp3.HttpUrl.Companion.toHttpUrl"], + ), + level = DeprecationLevel.ERROR, ) fun get(url: String): HttpUrl = url.toHttpUrl() @JvmName("-deprecated_parse") @Deprecated( message = "moved to extension function", - replaceWith = ReplaceWith( - expression = "url.toHttpUrlOrNull()", - imports = ["okhttp3.HttpUrl.Companion.toHttpUrlOrNull"] - ), - level = DeprecationLevel.ERROR + replaceWith = + ReplaceWith( + expression = "url.toHttpUrlOrNull()", + imports = ["okhttp3.HttpUrl.Companion.toHttpUrlOrNull"], + ), + level = DeprecationLevel.ERROR, ) fun parse(url: String): HttpUrl? = url.toHttpUrlOrNull() @JvmName("-deprecated_get") @Deprecated( message = "moved to extension function", - replaceWith = ReplaceWith( - expression = "url.toHttpUrlOrNull()", - imports = ["okhttp3.HttpUrl.Companion.toHttpUrlOrNull"] - ), - level = DeprecationLevel.ERROR + replaceWith = + ReplaceWith( + expression = "url.toHttpUrlOrNull()", + imports = ["okhttp3.HttpUrl.Companion.toHttpUrlOrNull"], + ), + level = DeprecationLevel.ERROR, ) fun get(url: URL): HttpUrl? = url.toHttpUrlOrNull() @JvmName("-deprecated_get") @Deprecated( message = "moved to extension function", - replaceWith = ReplaceWith( - expression = "uri.toHttpUrlOrNull()", - imports = ["okhttp3.HttpUrl.Companion.toHttpUrlOrNull"] - ), - level = DeprecationLevel.ERROR + replaceWith = + ReplaceWith( + expression = "uri.toHttpUrlOrNull()", + imports = ["okhttp3.HttpUrl.Companion.toHttpUrlOrNull"], + ), + level = DeprecationLevel.ERROR, ) fun get(uri: URI): HttpUrl? = uri.toHttpUrlOrNull() } diff --git a/okhttp/src/main/kotlin/okhttp3/Interceptor.kt b/okhttp/src/main/kotlin/okhttp3/Interceptor.kt index 9c8814d61460..bfa1f582326c 100644 --- a/okhttp/src/main/kotlin/okhttp3/Interceptor.kt +++ b/okhttp/src/main/kotlin/okhttp3/Interceptor.kt @@ -71,8 +71,7 @@ fun interface Interceptor { * } * ``` */ - inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor = - Interceptor { block(it) } + inline operator fun invoke(crossinline block: (chain: Chain) -> Response): Interceptor = Interceptor { block(it) } } interface Chain { @@ -91,14 +90,23 @@ fun interface Interceptor { fun connectTimeoutMillis(): Int - fun withConnectTimeout(timeout: Int, unit: TimeUnit): Chain + fun withConnectTimeout( + timeout: Int, + unit: TimeUnit, + ): Chain fun readTimeoutMillis(): Int - fun withReadTimeout(timeout: Int, unit: TimeUnit): Chain + fun withReadTimeout( + timeout: Int, + unit: TimeUnit, + ): Chain fun writeTimeoutMillis(): Int - fun withWriteTimeout(timeout: Int, unit: TimeUnit): Chain + fun withWriteTimeout( + timeout: Int, + unit: TimeUnit, + ): Chain } } diff --git a/okhttp/src/main/kotlin/okhttp3/MediaType.kt b/okhttp/src/main/kotlin/okhttp3/MediaType.kt index 8980142e97b9..c57b4d20ab62 100644 --- a/okhttp/src/main/kotlin/okhttp3/MediaType.kt +++ b/okhttp/src/main/kotlin/okhttp3/MediaType.kt @@ -31,21 +31,17 @@ import okhttp3.internal.commonToString */ class MediaType internal constructor( internal val mediaType: String, - /** * Returns the high-level media type, such as "text", "image", "audio", "video", or "application". */ @get:JvmName("type") val type: String, - /** * Returns a specific media subtype, such as "plain" or "png", "mpeg", "mp4" or "xml". */ @get:JvmName("subtype") val subtype: String, - /** Alternating parameter names with their values, like `["charset", "utf-8"]`. */ - internal val parameterNamesAndValues: Array + internal val parameterNamesAndValues: Array, ) { - /** * Returns the charset of this media type, or [defaultValue] if either this media type doesn't * specify a charset, or if its charset is unsupported by the current runtime. @@ -70,7 +66,7 @@ class MediaType internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "type"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun type(): String = type @@ -78,7 +74,7 @@ class MediaType internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "subtype"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun subtype(): String = subtype @@ -110,22 +106,24 @@ class MediaType internal constructor( @JvmName("-deprecated_get") @Deprecated( message = "moved to extension function", - replaceWith = ReplaceWith( - expression = "mediaType.toMediaType()", - imports = ["okhttp3.MediaType.Companion.toMediaType"] - ), - level = DeprecationLevel.ERROR + replaceWith = + ReplaceWith( + expression = "mediaType.toMediaType()", + imports = ["okhttp3.MediaType.Companion.toMediaType"], + ), + level = DeprecationLevel.ERROR, ) fun get(mediaType: String): MediaType = mediaType.toMediaType() @JvmName("-deprecated_parse") @Deprecated( message = "moved to extension function", - replaceWith = ReplaceWith( - expression = "mediaType.toMediaTypeOrNull()", - imports = ["okhttp3.MediaType.Companion.toMediaTypeOrNull"] - ), - level = DeprecationLevel.ERROR + replaceWith = + ReplaceWith( + expression = "mediaType.toMediaTypeOrNull()", + imports = ["okhttp3.MediaType.Companion.toMediaTypeOrNull"], + ), + level = DeprecationLevel.ERROR, ) fun parse(mediaType: String): MediaType? = mediaType.toMediaTypeOrNull() } diff --git a/okhttp/src/main/kotlin/okhttp3/MultipartBody.kt b/okhttp/src/main/kotlin/okhttp3/MultipartBody.kt index 83eb3773d090..ce0771ac552d 100644 --- a/okhttp/src/main/kotlin/okhttp3/MultipartBody.kt +++ b/okhttp/src/main/kotlin/okhttp3/MultipartBody.kt @@ -33,7 +33,7 @@ import okio.ByteString.Companion.encodeUtf8 class MultipartBody internal constructor( private val boundaryByteString: ByteString, @get:JvmName("type") val type: MediaType, - @get:JvmName("parts") val parts: List + @get:JvmName("parts") val parts: List, ) : RequestBody() { private val contentType: MediaType = "$type; boundary=$boundary".toMediaType() private var contentLength = -1L @@ -60,7 +60,7 @@ class MultipartBody internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "type"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun type(): MediaType = type @@ -68,7 +68,7 @@ class MultipartBody internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "boundary"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun boundary(): String = boundary @@ -76,7 +76,7 @@ class MultipartBody internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "size"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun size(): Int = size @@ -84,7 +84,7 @@ class MultipartBody internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "parts"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun parts(): List = parts @@ -112,7 +112,7 @@ class MultipartBody internal constructor( @Throws(IOException::class) private fun writeOrCountBytes( sink: BufferedSink?, - countBytes: Boolean + countBytes: Boolean, ): Long { var sink = sink var byteCount = 0L @@ -181,14 +181,13 @@ class MultipartBody internal constructor( class Part private constructor( @get:JvmName("headers") val headers: Headers?, - @get:JvmName("body") val body: RequestBody + @get:JvmName("body") val body: RequestBody, ) { - @JvmName("-deprecated_headers") @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "headers"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun headers(): Headers? = headers @@ -196,7 +195,7 @@ class MultipartBody internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "body"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun body(): RequestBody = body @@ -205,82 +204,108 @@ class MultipartBody internal constructor( fun create(body: RequestBody): Part = create(null, body) @JvmStatic - fun create(headers: Headers?, body: RequestBody): Part { + fun create( + headers: Headers?, + body: RequestBody, + ): Part { require(headers?.get("Content-Type") == null) { "Unexpected header: Content-Type" } require(headers?.get("Content-Length") == null) { "Unexpected header: Content-Length" } return Part(headers, body) } @JvmStatic - fun createFormData(name: String, value: String): Part = - createFormData(name, null, value.toRequestBody()) + fun createFormData( + name: String, + value: String, + ): Part = createFormData(name, null, value.toRequestBody()) @JvmStatic - fun createFormData(name: String, filename: String?, body: RequestBody): Part { - val disposition = buildString { - append("form-data; name=") - appendQuotedString(name) - - if (filename != null) { - append("; filename=") - appendQuotedString(filename) + fun createFormData( + name: String, + filename: String?, + body: RequestBody, + ): Part { + val disposition = + buildString { + append("form-data; name=") + appendQuotedString(name) + + if (filename != null) { + append("; filename=") + appendQuotedString(filename) + } } - } - val headers = Headers.Builder() - .addUnsafeNonAscii("Content-Disposition", disposition) - .build() + val headers = + Headers.Builder() + .addUnsafeNonAscii("Content-Disposition", disposition) + .build() return create(headers, body) } } } - class Builder @JvmOverloads constructor(boundary: String = UUID.randomUUID().toString()) { - private val boundary: ByteString = boundary.encodeUtf8() - private var type = MIXED - private val parts = mutableListOf() - - /** - * Set the MIME type. Expected values for `type` are [MIXED] (the default), [ALTERNATIVE], - * [DIGEST], [PARALLEL] and [FORM]. - */ - fun setType(type: MediaType) = apply { - require(type.type == "multipart") { "multipart != $type" } - this.type = type - } + class Builder + @JvmOverloads + constructor(boundary: String = UUID.randomUUID().toString()) { + private val boundary: ByteString = boundary.encodeUtf8() + private var type = MIXED + private val parts = mutableListOf() + + /** + * Set the MIME type. Expected values for `type` are [MIXED] (the default), [ALTERNATIVE], + * [DIGEST], [PARALLEL] and [FORM]. + */ + fun setType(type: MediaType) = + apply { + require(type.type == "multipart") { "multipart != $type" } + this.type = type + } - /** Add a part to the body. */ - fun addPart(body: RequestBody) = apply { - addPart(Part.create(body)) - } + /** Add a part to the body. */ + fun addPart(body: RequestBody) = + apply { + addPart(Part.create(body)) + } - /** Add a part to the body. */ - fun addPart(headers: Headers?, body: RequestBody) = apply { - addPart(Part.create(headers, body)) - } + /** Add a part to the body. */ + fun addPart( + headers: Headers?, + body: RequestBody, + ) = apply { + addPart(Part.create(headers, body)) + } - /** Add a form data part to the body. */ - fun addFormDataPart(name: String, value: String) = apply { - addPart(Part.createFormData(name, value)) - } + /** Add a form data part to the body. */ + fun addFormDataPart( + name: String, + value: String, + ) = apply { + addPart(Part.createFormData(name, value)) + } - /** Add a form data part to the body. */ - fun addFormDataPart(name: String, filename: String?, body: RequestBody) = apply { - addPart(Part.createFormData(name, filename, body)) - } + /** Add a form data part to the body. */ + fun addFormDataPart( + name: String, + filename: String?, + body: RequestBody, + ) = apply { + addPart(Part.createFormData(name, filename, body)) + } - /** Add a part to the body. */ - fun addPart(part: Part) = apply { - parts += part - } + /** Add a part to the body. */ + fun addPart(part: Part) = + apply { + parts += part + } - /** Assemble the specified parts into a request body. */ - fun build(): MultipartBody { - check(parts.isNotEmpty()) { "Multipart body must have at least one part." } - return MultipartBody(boundary, type, parts.toImmutableList()) + /** Assemble the specified parts into a request body. */ + fun build(): MultipartBody { + check(parts.isNotEmpty()) { "Multipart body must have at least one part." } + return MultipartBody(boundary, type, parts.toImmutableList()) + } } - } companion object { /** diff --git a/okhttp/src/main/kotlin/okhttp3/MultipartReader.kt b/okhttp/src/main/kotlin/okhttp3/MultipartReader.kt index 2a7bf6beae60..88cf72f906a4 100644 --- a/okhttp/src/main/kotlin/okhttp3/MultipartReader.kt +++ b/okhttp/src/main/kotlin/okhttp3/MultipartReader.kt @@ -54,163 +54,169 @@ import okio.buffer * * [rfc_2046]: http://www.ietf.org/rfc/rfc2046.txt */ -class MultipartReader @Throws(IOException::class) constructor( - private val source: BufferedSource, - @get:JvmName("boundary") val boundary: String -) : Closeable { - /** This delimiter typically precedes the first part. */ - private val dashDashBoundary = Buffer() - .writeUtf8("--") - .writeUtf8(boundary) - .readByteString() - - /** - * This delimiter typically precedes all subsequent parts. It may also precede the first part - * if the body contains a preamble. - */ - private val crlfDashDashBoundary = Buffer() - .writeUtf8("\r\n--") - .writeUtf8(boundary) - .readByteString() - - private var partCount = 0 - private var closed = false - private var noMoreParts = false - - /** This is only part that's allowed to read from the underlying source. */ - private var currentPart: PartSource? = null - +class MultipartReader @Throws(IOException::class) - constructor(response: ResponseBody) : this( + constructor( + private val source: BufferedSource, + @get:JvmName("boundary") val boundary: String, + ) : Closeable { + /** This delimiter typically precedes the first part. */ + private val dashDashBoundary = + Buffer() + .writeUtf8("--") + .writeUtf8(boundary) + .readByteString() + + /** + * This delimiter typically precedes all subsequent parts. It may also precede the first part + * if the body contains a preamble. + */ + private val crlfDashDashBoundary = + Buffer() + .writeUtf8("\r\n--") + .writeUtf8(boundary) + .readByteString() + + private var partCount = 0 + private var closed = false + private var noMoreParts = false + + /** This is only part that's allowed to read from the underlying source. */ + private var currentPart: PartSource? = null + + @Throws(IOException::class) + constructor(response: ResponseBody) : this( source = response.source(), - boundary = response.contentType()?.parameter("boundary") - ?: throw ProtocolException("expected the Content-Type to have a boundary parameter") - ) - - @Throws(IOException::class) - fun nextPart(): Part? { - check(!closed) { "closed" } - - if (noMoreParts) return null - - // Read a boundary, skipping the remainder of the preceding part as necessary. - if (partCount == 0 && source.rangeEquals(0L, dashDashBoundary)) { - // This is the first part. Consume "--" followed by the boundary. - source.skip(dashDashBoundary.size.toLong()) - } else { - // This is a subsequent part or a preamble. Skip until "\r\n--" followed by the boundary. - while (true) { - val toSkip = currentPartBytesRemaining(maxResult = 8192) - if (toSkip == 0L) break - source.skip(toSkip) - } - source.skip(crlfDashDashBoundary.size.toLong()) - } - - // Read either \r\n or --\r\n to determine if there is another part. - var whitespace = false - afterBoundaryLoop@while (true) { - when (source.select(afterBoundaryOptions)) { - 0 -> { - // "\r\n": We've found a new part. - partCount++ - break@afterBoundaryLoop - } + boundary = + response.contentType()?.parameter("boundary") + ?: throw ProtocolException("expected the Content-Type to have a boundary parameter"), + ) - 1 -> { - // "--": No more parts. - if (whitespace) throw ProtocolException("unexpected characters after boundary") - if (partCount == 0) throw ProtocolException("expected at least 1 part") - noMoreParts = true - return null + @Throws(IOException::class) + fun nextPart(): Part? { + check(!closed) { "closed" } + + if (noMoreParts) return null + + // Read a boundary, skipping the remainder of the preceding part as necessary. + if (partCount == 0 && source.rangeEquals(0L, dashDashBoundary)) { + // This is the first part. Consume "--" followed by the boundary. + source.skip(dashDashBoundary.size.toLong()) + } else { + // This is a subsequent part or a preamble. Skip until "\r\n--" followed by the boundary. + while (true) { + val toSkip = currentPartBytesRemaining(maxResult = 8192) + if (toSkip == 0L) break + source.skip(toSkip) } + source.skip(crlfDashDashBoundary.size.toLong()) + } - 2, 3 -> { - // " " or "\t" Ignore whitespace and keep looking. - whitespace = true - continue@afterBoundaryLoop + // Read either \r\n or --\r\n to determine if there is another part. + var whitespace = false + afterBoundaryLoop@while (true) { + when (source.select(afterBoundaryOptions)) { + 0 -> { + // "\r\n": We've found a new part. + partCount++ + break@afterBoundaryLoop + } + + 1 -> { + // "--": No more parts. + if (whitespace) throw ProtocolException("unexpected characters after boundary") + if (partCount == 0) throw ProtocolException("expected at least 1 part") + noMoreParts = true + return null + } + + 2, 3 -> { + // " " or "\t" Ignore whitespace and keep looking. + whitespace = true + continue@afterBoundaryLoop + } + + -1 -> throw ProtocolException("unexpected characters after boundary") } - - -1 -> throw ProtocolException("unexpected characters after boundary") } - } - - // There's another part. Parse its headers and return it. - val headers = HeadersReader(source).readHeaders() - val partSource = PartSource() - currentPart = partSource - return Part(headers, partSource.buffer()) - } - - /** A single part in the stream. It is an error to read this after calling [nextPart]. */ - private inner class PartSource : Source { - private val timeout = Timeout() - override fun close() { - if (currentPart == this) { - currentPart = null - } + // There's another part. Parse its headers and return it. + val headers = HeadersReader(source).readHeaders() + val partSource = PartSource() + currentPart = partSource + return Part(headers, partSource.buffer()) } - override fun read(sink: Buffer, byteCount: Long): Long { - require(byteCount >= 0L) { "byteCount < 0: $byteCount" } - check(currentPart == this) { "closed" } + /** A single part in the stream. It is an error to read this after calling [nextPart]. */ + private inner class PartSource : Source { + private val timeout = Timeout() - source.timeout().intersectWith(timeout) { - return when (val limit = currentPartBytesRemaining(maxResult = byteCount)) { - 0L -> -1L // No more bytes in this part. - else -> source.read(sink, limit) + override fun close() { + if (currentPart == this) { + currentPart = null } } - error("unreachable") // TODO(jwilson): fix intersectWith() to return T. - } + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { + require(byteCount >= 0L) { "byteCount < 0: $byteCount" } + check(currentPart == this) { "closed" } + + source.timeout().intersectWith(timeout) { + return when (val limit = currentPartBytesRemaining(maxResult = byteCount)) { + 0L -> -1L // No more bytes in this part. + else -> source.read(sink, limit) + } + } - override fun timeout(): Timeout = timeout - } + error("unreachable") // TODO(jwilson): fix intersectWith() to return T. + } - /** - * Returns a value in [0..maxByteCount] with the number of bytes that can be read from [source] in - * the current part. If this returns 0 the current part is exhausted; otherwise it has at least - * one byte left to read. - */ - private fun currentPartBytesRemaining(maxResult: Long): Long { - source.require(crlfDashDashBoundary.size.toLong()) - - return when (val delimiterIndex = source.buffer.indexOf(crlfDashDashBoundary)) { - -1L -> minOf(maxResult, source.buffer.size - crlfDashDashBoundary.size + 1) - else -> minOf(maxResult, delimiterIndex) + override fun timeout(): Timeout = timeout } - } - - @Throws(IOException::class) - override fun close() { - if (closed) return - closed = true - currentPart = null - source.close() - } - /** A single part in a multipart body. */ - class Part( - @get:JvmName("headers") val headers: Headers, - @get:JvmName("body") val body: BufferedSource - ) : Closeable by body - - internal companion object { - /** These options follow the boundary. */ - val afterBoundaryOptions = Options.of( - // 0. "\r\n" More parts. - "\r\n".encodeUtf8(), - - // 1. "--" No more parts. - "--".encodeUtf8(), + /** + * Returns a value in [0..maxByteCount] with the number of bytes that can be read from [source] in + * the current part. If this returns 0 the current part is exhausted; otherwise it has at least + * one byte left to read. + */ + private fun currentPartBytesRemaining(maxResult: Long): Long { + source.require(crlfDashDashBoundary.size.toLong()) + + return when (val delimiterIndex = source.buffer.indexOf(crlfDashDashBoundary)) { + -1L -> minOf(maxResult, source.buffer.size - crlfDashDashBoundary.size + 1) + else -> minOf(maxResult, delimiterIndex) + } + } - // 2. " " Optional whitespace. Only used if there are more parts. - " ".encodeUtf8(), + @Throws(IOException::class) + override fun close() { + if (closed) return + closed = true + currentPart = null + source.close() + } - // 3. "\t" Optional whitespace. Only used if there are more parts. - "\t".encodeUtf8(), - ) + /** A single part in a multipart body. */ + class Part( + @get:JvmName("headers") val headers: Headers, + @get:JvmName("body") val body: BufferedSource, + ) : Closeable by body + + internal companion object { + /** These options follow the boundary. */ + val afterBoundaryOptions = + Options.of( + // 0. "\r\n" More parts. + "\r\n".encodeUtf8(), + // 1. "--" No more parts. + "--".encodeUtf8(), + // 2. " " Optional whitespace. Only used if there are more parts. + " ".encodeUtf8(), + // 3. "\t" Optional whitespace. Only used if there are more parts. + "\t".encodeUtf8(), + ) + } } -} diff --git a/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt b/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt index ad694ca4585a..bd06f28c3373 100644 --- a/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt +++ b/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt @@ -131,19 +131,21 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement * remain idle. */ open class OkHttpClient internal constructor( - builder: Builder + builder: Builder, ) : Call.Factory, WebSocket.Factory { + @get:JvmName("dispatcher") + val dispatcher: Dispatcher = builder.dispatcher - @get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher - - @get:JvmName("connectionPool") val connectionPool: ConnectionPool = builder.connectionPool + @get:JvmName("connectionPool") + val connectionPool: ConnectionPool = builder.connectionPool /** * Returns an immutable list of interceptors that observe the full span of each call: from before * the connection is established (if any) until after the response source is selected (either the * origin server, cache, or both). */ - @get:JvmName("interceptors") val interceptors: List = + @get:JvmName("interceptors") + val interceptors: List = builder.interceptors.toImmutableList() /** @@ -151,78 +153,104 @@ open class OkHttpClient internal constructor( * These interceptors must call [Interceptor.Chain.proceed] exactly once: it is an error for * a network interceptor to short-circuit or repeat a network request. */ - @get:JvmName("networkInterceptors") val networkInterceptors: List = + @get:JvmName("networkInterceptors") + val networkInterceptors: List = builder.networkInterceptors.toImmutableList() - @get:JvmName("eventListenerFactory") val eventListenerFactory: EventListener.Factory = + @get:JvmName("eventListenerFactory") + val eventListenerFactory: EventListener.Factory = builder.eventListenerFactory - @get:JvmName("retryOnConnectionFailure") val retryOnConnectionFailure: Boolean = + @get:JvmName("retryOnConnectionFailure") + val retryOnConnectionFailure: Boolean = builder.retryOnConnectionFailure - @get:JvmName("fastFallback") val fastFallback: Boolean = builder.fastFallback + @get:JvmName("fastFallback") + val fastFallback: Boolean = builder.fastFallback - @get:JvmName("authenticator") val authenticator: Authenticator = builder.authenticator + @get:JvmName("authenticator") + val authenticator: Authenticator = builder.authenticator - @get:JvmName("followRedirects") val followRedirects: Boolean = builder.followRedirects + @get:JvmName("followRedirects") + val followRedirects: Boolean = builder.followRedirects - @get:JvmName("followSslRedirects") val followSslRedirects: Boolean = builder.followSslRedirects + @get:JvmName("followSslRedirects") + val followSslRedirects: Boolean = builder.followSslRedirects - @get:JvmName("cookieJar") val cookieJar: CookieJar = builder.cookieJar + @get:JvmName("cookieJar") + val cookieJar: CookieJar = builder.cookieJar - @get:JvmName("cache") val cache: Cache? = builder.cache + @get:JvmName("cache") + val cache: Cache? = builder.cache - @get:JvmName("dns") val dns: Dns = builder.dns + @get:JvmName("dns") + val dns: Dns = builder.dns - @get:JvmName("proxy") val proxy: Proxy? = builder.proxy + @get:JvmName("proxy") + val proxy: Proxy? = builder.proxy - @get:JvmName("proxySelector") val proxySelector: ProxySelector = + @get:JvmName("proxySelector") + val proxySelector: ProxySelector = when { // Defer calls to ProxySelector.getDefault() because it can throw a SecurityException. builder.proxy != null -> NullProxySelector else -> builder.proxySelector ?: ProxySelector.getDefault() ?: NullProxySelector } - @get:JvmName("proxyAuthenticator") val proxyAuthenticator: Authenticator = + @get:JvmName("proxyAuthenticator") + val proxyAuthenticator: Authenticator = builder.proxyAuthenticator - @get:JvmName("socketFactory") val socketFactory: SocketFactory = builder.socketFactory + @get:JvmName("socketFactory") + val socketFactory: SocketFactory = builder.socketFactory private val sslSocketFactoryOrNull: SSLSocketFactory? - @get:JvmName("sslSocketFactory") val sslSocketFactory: SSLSocketFactory + @get:JvmName("sslSocketFactory") + val sslSocketFactory: SSLSocketFactory get() = sslSocketFactoryOrNull ?: throw IllegalStateException("CLEARTEXT-only client") - @get:JvmName("x509TrustManager") val x509TrustManager: X509TrustManager? + @get:JvmName("x509TrustManager") + val x509TrustManager: X509TrustManager? - @get:JvmName("connectionSpecs") val connectionSpecs: List = + @get:JvmName("connectionSpecs") + val connectionSpecs: List = builder.connectionSpecs - @get:JvmName("protocols") val protocols: List = builder.protocols + @get:JvmName("protocols") + val protocols: List = builder.protocols - @get:JvmName("hostnameVerifier") val hostnameVerifier: HostnameVerifier = builder.hostnameVerifier + @get:JvmName("hostnameVerifier") + val hostnameVerifier: HostnameVerifier = builder.hostnameVerifier - @get:JvmName("certificatePinner") val certificatePinner: CertificatePinner + @get:JvmName("certificatePinner") + val certificatePinner: CertificatePinner - @get:JvmName("certificateChainCleaner") val certificateChainCleaner: CertificateChainCleaner? + @get:JvmName("certificateChainCleaner") + val certificateChainCleaner: CertificateChainCleaner? /** * Default call timeout (in milliseconds). By default there is no timeout for complete calls, but * there is for the connect, write, and read actions within a call. */ - @get:JvmName("callTimeoutMillis") val callTimeoutMillis: Int = builder.callTimeout + @get:JvmName("callTimeoutMillis") + val callTimeoutMillis: Int = builder.callTimeout /** Default connect timeout (in milliseconds). The default is 10 seconds. */ - @get:JvmName("connectTimeoutMillis") val connectTimeoutMillis: Int = builder.connectTimeout + @get:JvmName("connectTimeoutMillis") + val connectTimeoutMillis: Int = builder.connectTimeout /** Default read timeout (in milliseconds). The default is 10 seconds. */ - @get:JvmName("readTimeoutMillis") val readTimeoutMillis: Int = builder.readTimeout + @get:JvmName("readTimeoutMillis") + val readTimeoutMillis: Int = builder.readTimeout /** Default write timeout (in milliseconds). The default is 10 seconds. */ - @get:JvmName("writeTimeoutMillis") val writeTimeoutMillis: Int = builder.writeTimeout + @get:JvmName("writeTimeoutMillis") + val writeTimeoutMillis: Int = builder.writeTimeout /** Web socket and HTTP/2 ping interval (in milliseconds). By default pings are not sent. */ - @get:JvmName("pingIntervalMillis") val pingIntervalMillis: Int = builder.pingInterval + @get:JvmName("pingIntervalMillis") + val pingIntervalMillis: Int = builder.pingInterval /** * Minimum outbound web socket message size (in bytes) that will be compressed. @@ -246,14 +274,16 @@ open class OkHttpClient internal constructor( this.sslSocketFactoryOrNull = builder.sslSocketFactoryOrNull this.certificateChainCleaner = builder.certificateChainCleaner!! this.x509TrustManager = builder.x509TrustManagerOrNull!! - this.certificatePinner = builder.certificatePinner - .withCertificateChainCleaner(certificateChainCleaner!!) + this.certificatePinner = + builder.certificatePinner + .withCertificateChainCleaner(certificateChainCleaner!!) } else { this.x509TrustManager = Platform.get().platformTrustManager() this.sslSocketFactoryOrNull = Platform.get().newSslSocketFactory(x509TrustManager!!) this.certificateChainCleaner = CertificateChainCleaner.get(x509TrustManager!!) - this.certificatePinner = builder.certificatePinner - .withCertificateChainCleaner(certificateChainCleaner!!) + this.certificatePinner = + builder.certificatePinner + .withCertificateChainCleaner(certificateChainCleaner!!) } verifyClientState() @@ -283,17 +313,21 @@ open class OkHttpClient internal constructor( override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false) /** Uses [request] to connect a new web socket. */ - override fun newWebSocket(request: Request, listener: WebSocketListener): WebSocket { - val webSocket = RealWebSocket( - taskRunner = taskRunner, - originalRequest = request, - listener = listener, - random = Random(), - pingIntervalMillis = pingIntervalMillis.toLong(), - // extensions is always null for clients: - extensions = null, - minimumDeflateSize = minWebSocketMessageToCompress - ) + override fun newWebSocket( + request: Request, + listener: WebSocketListener, + ): WebSocket { + val webSocket = + RealWebSocket( + taskRunner = taskRunner, + originalRequest = request, + listener = listener, + random = Random(), + pingIntervalMillis = pingIntervalMillis.toLong(), + // extensions is always null for clients: + extensions = null, + minimumDeflateSize = minWebSocketMessageToCompress, + ) webSocket.connect(this) return webSocket } @@ -304,7 +338,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "dispatcher"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun dispatcher(): Dispatcher = dispatcher @@ -312,7 +346,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "connectionPool"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun connectionPool(): ConnectionPool = connectionPool @@ -320,7 +354,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "interceptors"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun interceptors(): List = interceptors @@ -328,7 +362,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "networkInterceptors"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun networkInterceptors(): List = networkInterceptors @@ -336,7 +370,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "eventListenerFactory"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun eventListenerFactory(): EventListener.Factory = eventListenerFactory @@ -344,7 +378,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "retryOnConnectionFailure"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun retryOnConnectionFailure(): Boolean = retryOnConnectionFailure @@ -352,7 +386,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "authenticator"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun authenticator(): Authenticator = authenticator @@ -360,7 +394,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "followRedirects"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun followRedirects(): Boolean = followRedirects @@ -368,7 +402,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "followSslRedirects"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun followSslRedirects(): Boolean = followSslRedirects @@ -376,7 +410,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "cookieJar"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun cookieJar(): CookieJar = cookieJar @@ -384,7 +418,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "cache"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun cache(): Cache? = cache @@ -392,7 +426,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "dns"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun dns(): Dns = dns @@ -400,7 +434,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "proxy"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun proxy(): Proxy? = proxy @@ -408,7 +442,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "proxySelector"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun proxySelector(): ProxySelector = proxySelector @@ -416,7 +450,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "proxyAuthenticator"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun proxyAuthenticator(): Authenticator = proxyAuthenticator @@ -424,7 +458,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "socketFactory"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun socketFactory(): SocketFactory = socketFactory @@ -432,7 +466,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "sslSocketFactory"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun sslSocketFactory(): SSLSocketFactory = sslSocketFactory @@ -440,7 +474,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "connectionSpecs"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun connectionSpecs(): List = connectionSpecs @@ -448,7 +482,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "protocols"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun protocols(): List = protocols @@ -456,7 +490,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "hostnameVerifier"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun hostnameVerifier(): HostnameVerifier = hostnameVerifier @@ -464,7 +498,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "certificatePinner"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun certificatePinner(): CertificatePinner = certificatePinner @@ -472,7 +506,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "callTimeoutMillis"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun callTimeoutMillis(): Int = callTimeoutMillis @@ -480,7 +514,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "connectTimeoutMillis"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun connectTimeoutMillis(): Int = connectTimeoutMillis @@ -488,7 +522,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "readTimeoutMillis"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun readTimeoutMillis(): Int = readTimeoutMillis @@ -496,7 +530,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "writeTimeoutMillis"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun writeTimeoutMillis(): Int = writeTimeoutMillis @@ -504,7 +538,7 @@ open class OkHttpClient internal constructor( @Deprecated( message = "moved to val", replaceWith = ReplaceWith(expression = "pingIntervalMillis"), - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) fun pingIntervalMillis(): Int = pingIntervalMillis @@ -580,18 +614,20 @@ open class OkHttpClient internal constructor( /** * Sets the dispatcher used to set policy and execute asynchronous requests. Must not be null. */ - fun dispatcher(dispatcher: Dispatcher) = apply { - this.dispatcher = dispatcher - } + fun dispatcher(dispatcher: Dispatcher) = + apply { + this.dispatcher = dispatcher + } /** * Sets the connection pool used to recycle HTTP and HTTPS connections. * * If unset, a new connection pool will be used. */ - fun connectionPool(connectionPool: ConnectionPool) = apply { - this.connectionPool = connectionPool - } + fun connectionPool(connectionPool: ConnectionPool) = + apply { + this.connectionPool = connectionPool + } /** * Returns a modifiable list of interceptors that observe the full span of each call: from @@ -600,9 +636,10 @@ open class OkHttpClient internal constructor( */ fun interceptors(): MutableList = interceptors - fun addInterceptor(interceptor: Interceptor) = apply { - interceptors += interceptor - } + fun addInterceptor(interceptor: Interceptor) = + apply { + interceptors += interceptor + } @JvmName("-addInterceptor") // Prefix with '-' to prevent ambiguous overloads from Java. inline fun addInterceptor(crossinline block: (chain: Interceptor.Chain) -> Response) = @@ -615,9 +652,10 @@ open class OkHttpClient internal constructor( */ fun networkInterceptors(): MutableList = networkInterceptors - fun addNetworkInterceptor(interceptor: Interceptor) = apply { - networkInterceptors += interceptor - } + fun addNetworkInterceptor(interceptor: Interceptor) = + apply { + networkInterceptors += interceptor + } @JvmName("-addNetworkInterceptor") // Prefix with '-' to prevent ambiguous overloads from Java. inline fun addNetworkInterceptor(crossinline block: (chain: Interceptor.Chain) -> Response) = @@ -629,9 +667,10 @@ open class OkHttpClient internal constructor( * * @see EventListener for semantics and restrictions on listener implementations. */ - fun eventListener(eventListener: EventListener) = apply { - this.eventListenerFactory = eventListener.asFactory() - } + fun eventListener(eventListener: EventListener) = + apply { + this.eventListenerFactory = eventListener.asFactory() + } /** * Configure a factory to provide per-call scoped listeners that will receive analytic events @@ -639,9 +678,10 @@ open class OkHttpClient internal constructor( * * @see EventListener for semantics and restrictions on listener implementations. */ - fun eventListenerFactory(eventListenerFactory: EventListener.Factory) = apply { - this.eventListenerFactory = eventListenerFactory - } + fun eventListenerFactory(eventListenerFactory: EventListener.Factory) = + apply { + this.eventListenerFactory = eventListenerFactory + } /** * Configure this client to retry or not when a connectivity problem is encountered. By default, @@ -661,9 +701,10 @@ open class OkHttpClient internal constructor( * Set this to false to avoid retrying requests when doing so is destructive. In this case the * calling application should do its own recovery of connectivity failures. */ - fun retryOnConnectionFailure(retryOnConnectionFailure: Boolean) = apply { - this.retryOnConnectionFailure = retryOnConnectionFailure - } + fun retryOnConnectionFailure(retryOnConnectionFailure: Boolean) = + apply { + this.retryOnConnectionFailure = retryOnConnectionFailure + } /** * Configure this client to perform fast fallbacks by attempting multiple connections @@ -676,9 +717,10 @@ open class OkHttpClient internal constructor( * * [rfc_6555]: https://datatracker.ietf.org/doc/html/rfc6555 */ - fun fastFallback(fastFallback: Boolean) = apply { - this.fastFallback = fastFallback - } + fun fastFallback(fastFallback: Boolean) = + apply { + this.fastFallback = fastFallback + } /** * Sets the authenticator used to respond to challenges from origin servers. Use @@ -686,14 +728,16 @@ open class OkHttpClient internal constructor( * * If unset, the [no authentication will be attempted][Authenticator.NONE]. */ - fun authenticator(authenticator: Authenticator) = apply { - this.authenticator = authenticator - } + fun authenticator(authenticator: Authenticator) = + apply { + this.authenticator = authenticator + } /** Configure this client to follow redirects. If unset, redirects will be followed. */ - fun followRedirects(followRedirects: Boolean) = apply { - this.followRedirects = followRedirects - } + fun followRedirects(followRedirects: Boolean) = + apply { + this.followRedirects = followRedirects + } /** * Configure this client to allow protocol redirects from HTTPS to HTTP and from HTTP to HTTPS. @@ -701,9 +745,10 @@ open class OkHttpClient internal constructor( * * @param followProtocolRedirects whether to follow redirects between HTTPS and HTTP. */ - fun followSslRedirects(followProtocolRedirects: Boolean) = apply { - this.followSslRedirects = followProtocolRedirects - } + fun followSslRedirects(followProtocolRedirects: Boolean) = + apply { + this.followSslRedirects = followProtocolRedirects + } /** * Sets the handler that can accept cookies from incoming HTTP responses and provides cookies to @@ -711,42 +756,47 @@ open class OkHttpClient internal constructor( * * If unset, [no cookies][CookieJar.NO_COOKIES] will be accepted nor provided. */ - fun cookieJar(cookieJar: CookieJar) = apply { - this.cookieJar = cookieJar - } + fun cookieJar(cookieJar: CookieJar) = + apply { + this.cookieJar = cookieJar + } /** Sets the response cache to be used to read and write cached responses. */ - fun cache(cache: Cache?) = apply { - this.cache = cache - } + fun cache(cache: Cache?) = + apply { + this.cache = cache + } - internal fun taskRunner(taskRunner: TaskRunner) = apply { - this.taskRunner = taskRunner - } + internal fun taskRunner(taskRunner: TaskRunner) = + apply { + this.taskRunner = taskRunner + } /** * Sets the DNS service used to lookup IP addresses for hostnames. * * If unset, the [system-wide default][Dns.SYSTEM] DNS will be used. */ - fun dns(dns: Dns) = apply { - if (dns != this.dns) { - this.routeDatabase = null + fun dns(dns: Dns) = + apply { + if (dns != this.dns) { + this.routeDatabase = null + } + this.dns = dns } - this.dns = dns - } /** * Sets the HTTP proxy that will be used by connections created by this client. This takes * precedence over [proxySelector], which is only honored when this proxy is null (which it is * by default). To disable proxy use completely, call `proxy(Proxy.NO_PROXY)`. */ - fun proxy(proxy: Proxy?) = apply { - if (proxy != this.proxy) { - this.routeDatabase = null + fun proxy(proxy: Proxy?) = + apply { + if (proxy != this.proxy) { + this.routeDatabase = null + } + this.proxy = proxy } - this.proxy = proxy - } /** * Sets the proxy selection policy to be used if no [proxy][proxy] is specified explicitly. The @@ -755,13 +805,14 @@ open class OkHttpClient internal constructor( * * If unset, the [system-wide default][ProxySelector.getDefault] proxy selector will be used. */ - fun proxySelector(proxySelector: ProxySelector) = apply { - if (proxySelector != this.proxySelector) { - this.routeDatabase = null - } + fun proxySelector(proxySelector: ProxySelector) = + apply { + if (proxySelector != this.proxySelector) { + this.routeDatabase = null + } - this.proxySelector = proxySelector - } + this.proxySelector = proxySelector + } /** * Sets the authenticator used to respond to challenges from proxy servers. Use [authenticator] @@ -769,13 +820,14 @@ open class OkHttpClient internal constructor( * * If unset, the [no authentication will be attempted][Authenticator.NONE]. */ - fun proxyAuthenticator(proxyAuthenticator: Authenticator) = apply { - if (proxyAuthenticator != this.proxyAuthenticator) { - this.routeDatabase = null - } + fun proxyAuthenticator(proxyAuthenticator: Authenticator) = + apply { + if (proxyAuthenticator != this.proxyAuthenticator) { + this.routeDatabase = null + } - this.proxyAuthenticator = proxyAuthenticator - } + this.proxyAuthenticator = proxyAuthenticator + } /** * Sets the socket factory used to create connections. OkHttp only uses the parameterless @@ -784,15 +836,16 @@ open class OkHttpClient internal constructor( * * If unset, the [system-wide default][SocketFactory.getDefault] socket factory will be used. */ - fun socketFactory(socketFactory: SocketFactory) = apply { - require(socketFactory !is SSLSocketFactory) { "socketFactory instanceof SSLSocketFactory" } + fun socketFactory(socketFactory: SocketFactory) = + apply { + require(socketFactory !is SSLSocketFactory) { "socketFactory instanceof SSLSocketFactory" } - if (socketFactory != this.socketFactory) { - this.routeDatabase = null - } + if (socketFactory != this.socketFactory) { + this.routeDatabase = null + } - this.socketFactory = socketFactory - } + this.socketFactory = socketFactory + } /** * Sets the socket factory used to secure HTTPS connections. If unset, the system default will @@ -805,23 +858,24 @@ open class OkHttpClient internal constructor( */ @Deprecated( message = "Use the sslSocketFactory overload that accepts a X509TrustManager.", - level = DeprecationLevel.ERROR + level = DeprecationLevel.ERROR, ) - fun sslSocketFactory(sslSocketFactory: SSLSocketFactory) = apply { - if (sslSocketFactory != this.sslSocketFactoryOrNull) { - this.routeDatabase = null + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory) = + apply { + if (sslSocketFactory != this.sslSocketFactoryOrNull) { + this.routeDatabase = null + } + + this.sslSocketFactoryOrNull = sslSocketFactory + this.x509TrustManagerOrNull = + Platform.get().trustManager(sslSocketFactory) ?: throw IllegalStateException( + "Unable to extract the trust manager on ${Platform.get()}, " + + "sslSocketFactory is ${sslSocketFactory.javaClass}", + ) + this.certificateChainCleaner = + Platform.get().buildCertificateChainCleaner(x509TrustManagerOrNull!!) } - this.sslSocketFactoryOrNull = sslSocketFactory - this.x509TrustManagerOrNull = - Platform.get().trustManager(sslSocketFactory) ?: throw IllegalStateException( - "Unable to extract the trust manager on ${Platform.get()}, " + - "sslSocketFactory is ${sslSocketFactory.javaClass}" - ) - this.certificateChainCleaner = - Platform.get().buildCertificateChainCleaner(x509TrustManagerOrNull!!) - } - /** * Sets the socket factory and trust manager used to secure HTTPS connections. If unset, the * system defaults will be used. @@ -869,7 +923,7 @@ open class OkHttpClient internal constructor( */ fun sslSocketFactory( sslSocketFactory: SSLSocketFactory, - trustManager: X509TrustManager + trustManager: X509TrustManager, ) = apply { if (sslSocketFactory != this.sslSocketFactoryOrNull || trustManager != this.x509TrustManagerOrNull) { this.routeDatabase = null @@ -880,13 +934,14 @@ open class OkHttpClient internal constructor( this.x509TrustManagerOrNull = trustManager } - fun connectionSpecs(connectionSpecs: List) = apply { - if (connectionSpecs != this.connectionSpecs) { - this.routeDatabase = null - } + fun connectionSpecs(connectionSpecs: List) = + apply { + if (connectionSpecs != this.connectionSpecs) { + this.routeDatabase = null + } - this.connectionSpecs = connectionSpecs.toImmutableList() - } + this.connectionSpecs = connectionSpecs.toImmutableList() + } /** * Configure the protocols used by this client to communicate with remote servers. By default @@ -919,62 +974,65 @@ open class OkHttpClient internal constructor( * be supported. Otherwise the list must contain [Protocol.HTTP_1_1]. The list must * not contain null or [Protocol.HTTP_1_0]. */ - fun protocols(protocols: List) = apply { - // Create a private copy of the list. - val protocolsCopy = protocols.toMutableList() - - // Validate that the list has everything we require and nothing we forbid. - require(Protocol.H2_PRIOR_KNOWLEDGE in protocolsCopy || HTTP_1_1 in protocolsCopy) { - "protocols must contain h2_prior_knowledge or http/1.1: $protocolsCopy" - } - require(Protocol.H2_PRIOR_KNOWLEDGE !in protocolsCopy || protocolsCopy.size <= 1) { - "protocols containing h2_prior_knowledge cannot use other protocols: $protocolsCopy" - } - require(Protocol.HTTP_1_0 !in protocolsCopy) { - "protocols must not contain http/1.0: $protocolsCopy" - } - require(null !in (protocolsCopy as List)) { - "protocols must not contain null" + fun protocols(protocols: List) = + apply { + // Create a private copy of the list. + val protocolsCopy = protocols.toMutableList() + + // Validate that the list has everything we require and nothing we forbid. + require(Protocol.H2_PRIOR_KNOWLEDGE in protocolsCopy || HTTP_1_1 in protocolsCopy) { + "protocols must contain h2_prior_knowledge or http/1.1: $protocolsCopy" + } + require(Protocol.H2_PRIOR_KNOWLEDGE !in protocolsCopy || protocolsCopy.size <= 1) { + "protocols containing h2_prior_knowledge cannot use other protocols: $protocolsCopy" + } + require(Protocol.HTTP_1_0 !in protocolsCopy) { + "protocols must not contain http/1.0: $protocolsCopy" + } + require(null !in (protocolsCopy as List)) { + "protocols must not contain null" + } + + // Remove protocols that we no longer support. + @Suppress("DEPRECATION") + protocolsCopy.remove(Protocol.SPDY_3) + + if (protocolsCopy != this.protocols) { + this.routeDatabase = null + } + + // Assign as an unmodifiable list. This is effectively immutable. + this.protocols = Collections.unmodifiableList(protocolsCopy) } - // Remove protocols that we no longer support. - @Suppress("DEPRECATION") - protocolsCopy.remove(Protocol.SPDY_3) - - if (protocolsCopy != this.protocols) { - this.routeDatabase = null - } - - // Assign as an unmodifiable list. This is effectively immutable. - this.protocols = Collections.unmodifiableList(protocolsCopy) - } - /** * Sets the verifier used to confirm that response certificates apply to requested hostnames for * HTTPS connections. * * If unset, a default hostname verifier will be used. */ - fun hostnameVerifier(hostnameVerifier: HostnameVerifier) = apply { - if (hostnameVerifier != this.hostnameVerifier) { - this.routeDatabase = null - } + fun hostnameVerifier(hostnameVerifier: HostnameVerifier) = + apply { + if (hostnameVerifier != this.hostnameVerifier) { + this.routeDatabase = null + } - this.hostnameVerifier = hostnameVerifier - } + this.hostnameVerifier = hostnameVerifier + } /** * Sets the certificate pinner that constrains which certificates are trusted. By default HTTPS * connections rely on only the [SSL socket factory][sslSocketFactory] to establish trust. * Pinning certificates avoids the need to trust certificate authorities. */ - fun certificatePinner(certificatePinner: CertificatePinner) = apply { - if (certificatePinner != this.certificatePinner) { - this.routeDatabase = null - } + fun certificatePinner(certificatePinner: CertificatePinner) = + apply { + if (certificatePinner != this.certificatePinner) { + this.routeDatabase = null + } - this.certificatePinner = certificatePinner - } + this.certificatePinner = certificatePinner + } /** * Sets the default timeout for complete calls. A value of 0 means no timeout, otherwise values @@ -986,7 +1044,10 @@ open class OkHttpClient internal constructor( * * The default value is 0 which imposes no timeout. */ - fun callTimeout(timeout: Long, unit: TimeUnit) = apply { + fun callTimeout( + timeout: Long, + unit: TimeUnit, + ) = apply { callTimeout = checkDuration("timeout", timeout, unit) } @@ -1002,9 +1063,10 @@ open class OkHttpClient internal constructor( */ @SuppressLint("NewApi") @IgnoreJRERequirement - fun callTimeout(duration: Duration) = apply { - callTimeout(duration.toMillis(), MILLISECONDS) - } + fun callTimeout(duration: Duration) = + apply { + callTimeout(duration.toMillis(), MILLISECONDS) + } /** * Sets the default timeout for complete calls. A value of 0 means no timeout, otherwise values @@ -1016,9 +1078,10 @@ open class OkHttpClient internal constructor( * * The default value is 0 which imposes no timeout. */ - fun callTimeout(duration: KotlinDuration) = apply { - callTimeout = checkDuration("duration", duration) - } + fun callTimeout(duration: KotlinDuration) = + apply { + callTimeout = checkDuration("duration", duration) + } /** * Sets the default connect timeout for new connections. A value of 0 means no timeout, @@ -1027,7 +1090,10 @@ open class OkHttpClient internal constructor( * The connect timeout is applied when connecting a TCP socket to the target host. The default * value is 10 seconds. */ - fun connectTimeout(timeout: Long, unit: TimeUnit) = apply { + fun connectTimeout( + timeout: Long, + unit: TimeUnit, + ) = apply { connectTimeout = checkDuration("timeout", timeout, unit) } @@ -1040,9 +1106,10 @@ open class OkHttpClient internal constructor( */ @SuppressLint("NewApi") @IgnoreJRERequirement - fun connectTimeout(duration: Duration) = apply { - connectTimeout(duration.toMillis(), MILLISECONDS) - } + fun connectTimeout(duration: Duration) = + apply { + connectTimeout(duration.toMillis(), MILLISECONDS) + } /** * Sets the default connect timeout for new connections. A value of 0 means no timeout, @@ -1051,9 +1118,10 @@ open class OkHttpClient internal constructor( * The connect timeout is applied when connecting a TCP socket to the target host. The default * value is 10 seconds. */ - fun connectTimeout(duration: KotlinDuration) = apply { - connectTimeout = checkDuration("duration", duration) - } + fun connectTimeout(duration: KotlinDuration) = + apply { + connectTimeout = checkDuration("duration", duration) + } /** * Sets the default read timeout for new connections. A value of 0 means no timeout, otherwise @@ -1065,7 +1133,10 @@ open class OkHttpClient internal constructor( * @see Socket.setSoTimeout * @see Source.timeout */ - fun readTimeout(timeout: Long, unit: TimeUnit) = apply { + fun readTimeout( + timeout: Long, + unit: TimeUnit, + ) = apply { readTimeout = checkDuration("timeout", timeout, unit) } @@ -1081,9 +1152,10 @@ open class OkHttpClient internal constructor( */ @SuppressLint("NewApi") @IgnoreJRERequirement - fun readTimeout(duration: Duration) = apply { - readTimeout(duration.toMillis(), MILLISECONDS) - } + fun readTimeout(duration: Duration) = + apply { + readTimeout(duration.toMillis(), MILLISECONDS) + } /** * Sets the default read timeout for new connections. A value of 0 means no timeout, otherwise @@ -1095,9 +1167,10 @@ open class OkHttpClient internal constructor( * @see Socket.setSoTimeout * @see Source.timeout */ - fun readTimeout(duration: KotlinDuration) = apply { - readTimeout = checkDuration("duration", duration) - } + fun readTimeout(duration: KotlinDuration) = + apply { + readTimeout = checkDuration("duration", duration) + } /** * Sets the default write timeout for new connections. A value of 0 means no timeout, otherwise @@ -1108,7 +1181,10 @@ open class OkHttpClient internal constructor( * * @see Sink.timeout */ - fun writeTimeout(timeout: Long, unit: TimeUnit) = apply { + fun writeTimeout( + timeout: Long, + unit: TimeUnit, + ) = apply { writeTimeout = checkDuration("timeout", timeout, unit) } @@ -1123,9 +1199,10 @@ open class OkHttpClient internal constructor( */ @SuppressLint("NewApi") @IgnoreJRERequirement - fun writeTimeout(duration: Duration) = apply { - writeTimeout(duration.toMillis(), MILLISECONDS) - } + fun writeTimeout(duration: Duration) = + apply { + writeTimeout(duration.toMillis(), MILLISECONDS) + } /** * Sets the default write timeout for new connections. A value of 0 means no timeout, otherwise @@ -1136,9 +1213,10 @@ open class OkHttpClient internal constructor( * * @see Sink.timeout */ - fun writeTimeout(duration: KotlinDuration) = apply { - writeTimeout = checkDuration("duration", duration) - } + fun writeTimeout(duration: KotlinDuration) = + apply { + writeTimeout = checkDuration("duration", duration) + } /** * Sets the interval between HTTP/2 and web socket pings initiated by this client. Use this to @@ -1153,7 +1231,10 @@ open class OkHttpClient internal constructor( * * The default value of 0 disables client-initiated pings. */ - fun pingInterval(interval: Long, unit: TimeUnit) = apply { + fun pingInterval( + interval: Long, + unit: TimeUnit, + ) = apply { pingInterval = checkDuration("interval", interval, unit) } @@ -1172,9 +1253,10 @@ open class OkHttpClient internal constructor( */ @SuppressLint("NewApi") @IgnoreJRERequirement - fun pingInterval(duration: Duration) = apply { - pingInterval(duration.toMillis(), MILLISECONDS) - } + fun pingInterval(duration: Duration) = + apply { + pingInterval(duration.toMillis(), MILLISECONDS) + } /** * Sets the interval between HTTP/2 and web socket pings initiated by this client. Use this to @@ -1189,9 +1271,10 @@ open class OkHttpClient internal constructor( * * The default value of 0 disables client-initiated pings. */ - fun pingInterval(duration: KotlinDuration) = apply { - pingInterval = checkDuration("duration", duration) - } + fun pingInterval(duration: KotlinDuration) = + apply { + pingInterval = checkDuration("duration", duration) + } /** * Sets minimum outbound web socket message size (in bytes) that will be compressed. @@ -1200,13 +1283,14 @@ open class OkHttpClient internal constructor( * * 1024 by default. */ - fun minWebSocketMessageToCompress(bytes: Long) = apply { - require(bytes >= 0) { - "minWebSocketMessageToCompress must be positive: $bytes" - } + fun minWebSocketMessageToCompress(bytes: Long) = + apply { + require(bytes >= 0) { + "minWebSocketMessageToCompress must be positive: $bytes" + } - this.minWebSocketMessageToCompress = bytes - } + this.minWebSocketMessageToCompress = bytes + } fun build(): OkHttpClient = OkHttpClient(this) } @@ -1214,9 +1298,10 @@ open class OkHttpClient internal constructor( companion object { internal val DEFAULT_PROTOCOLS = immutableListOf(HTTP_2, HTTP_1_1) - internal val DEFAULT_CONNECTION_SPECS = immutableListOf( - ConnectionSpec.MODERN_TLS, - ConnectionSpec.CLEARTEXT, - ) + internal val DEFAULT_CONNECTION_SPECS = + immutableListOf( + ConnectionSpec.MODERN_TLS, + ConnectionSpec.CLEARTEXT, + ) } } diff --git a/okhttp/src/main/kotlin/okhttp3/Protocol.kt b/okhttp/src/main/kotlin/okhttp3/Protocol.kt index 19521f4722c0..91f9cfdcdcda 100644 --- a/okhttp/src/main/kotlin/okhttp3/Protocol.kt +++ b/okhttp/src/main/kotlin/okhttp3/Protocol.kt @@ -91,7 +91,8 @@ enum class Protocol(private val protocol: String) { * HTTP/3 is not natively supported by OkHttp, but provided to allow a theoretical interceptor * that provides support. */ - HTTP_3("h3"); + HTTP_3("h3"), + ; /** * Returns the string used to identify this protocol for ALPN, like "http/1.1", "spdy/3.1" or diff --git a/okhttp/src/main/kotlin/okhttp3/Request.kt b/okhttp/src/main/kotlin/okhttp3/Request.kt index 1976fd536641..8121b75b6143 100644 --- a/okhttp/src/main/kotlin/okhttp3/Request.kt +++ b/okhttp/src/main/kotlin/okhttp3/Request.kt @@ -84,8 +84,8 @@ class Request internal constructor(builder: Builder) { body != null -> "POST" else -> "GET" }, - body - ) + body, + ), ) fun header(name: String): String? = commonHeader(name) @@ -123,7 +123,8 @@ class Request internal constructor(builder: Builder) { * Returns the cache control directives for this response. This is never null, even if this * response contains no `Cache-Control` header. */ - @get:JvmName("cacheControl") val cacheControl: CacheControl + @get:JvmName("cacheControl") + val cacheControl: CacheControl get() { var result = lazyCacheControl if (result == null) { @@ -135,37 +136,42 @@ class Request internal constructor(builder: Builder) { @JvmName("-deprecated_url") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "url"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "url"), + level = DeprecationLevel.ERROR, + ) fun url(): HttpUrl = url @JvmName("-deprecated_method") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "method"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "method"), + level = DeprecationLevel.ERROR, + ) fun method(): String = method @JvmName("-deprecated_headers") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "headers"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "headers"), + level = DeprecationLevel.ERROR, + ) fun headers(): Headers = headers @JvmName("-deprecated_body") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "body"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "body"), + level = DeprecationLevel.ERROR, + ) fun body(): RequestBody? = body @JvmName("-deprecated_cacheControl") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "cacheControl"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "cacheControl"), + level = DeprecationLevel.ERROR, + ) fun cacheControl(): CacheControl = cacheControl override fun toString(): String = commonToString() @@ -175,6 +181,7 @@ class Request internal constructor(builder: Builder) { internal var method: String internal var headers: Headers.Builder internal var body: RequestBody? = null + /** A mutable map of tags, or an immutable empty map if we don't have any. */ internal var tags = mapOf, Any>() @@ -187,16 +194,18 @@ class Request internal constructor(builder: Builder) { this.url = request.url this.method = request.method this.body = request.body - this.tags = when { - request.tags.isEmpty() -> mapOf() - else -> request.tags.toMutableMap() - } + this.tags = + when { + request.tags.isEmpty() -> mapOf() + else -> request.tags.toMutableMap() + } this.headers = request.headers.newBuilder() } - open fun url(url: HttpUrl): Builder = apply { - this.url = url - } + open fun url(url: HttpUrl): Builder = + apply { + this.url = url + } /** * Sets the URL target of this request. @@ -219,7 +228,10 @@ class Request internal constructor(builder: Builder) { * Sets the header named [name] to [value]. If this request already has any headers * with that name, they are all replaced. */ - open fun header(name: String, value: String) = commonHeader(name, value) + open fun header( + name: String, + value: String, + ) = commonHeader(name, value) /** * Adds a header with [name] and [value]. Prefer this method for multiply-valued @@ -228,7 +240,10 @@ class Request internal constructor(builder: Builder) { * Note that for some headers including `Content-Length` and `Content-Encoding`, * OkHttp may replace [value] with a header derived from the request body. */ - open fun addHeader(name: String, value: String) = commonAddHeader(name, value) + open fun addHeader( + name: String, + value: String, + ) = commonAddHeader(name, value) /** Removes all headers named [name] on this builder. */ open fun removeHeader(name: String) = commonRemoveHeader(name) @@ -256,7 +271,10 @@ class Request internal constructor(builder: Builder) { open fun patch(body: RequestBody): Builder = commonPatch(body) - open fun method(method: String, body: RequestBody?): Builder = commonMethod(method, body) + open fun method( + method: String, + body: RequestBody?, + ): Builder = commonMethod(method, body) /** * Attaches [tag] to the request using [T] as a key. Tags can be read from a request using @@ -275,7 +293,10 @@ class Request internal constructor(builder: Builder) { * Use this API to attach timing, debugging, or other application data to a request so that * you may read it in interceptors, event listeners, or callbacks. */ - fun tag(type: KClass, tag: T?): Builder = commonTag(type, type.cast(tag)) + fun tag( + type: KClass, + tag: T?, + ): Builder = commonTag(type, type.cast(tag)) /** Attaches [tag] to the request using `Object.class` as a key. */ open fun tag(tag: Any?): Builder = commonTag(Any::class, tag) @@ -287,7 +308,10 @@ class Request internal constructor(builder: Builder) { * Use this API to attach timing, debugging, or other application data to a request so that * you may read it in interceptors, event listeners, or callbacks. */ - open fun tag(type: Class, tag: T?) = commonTag(type.kotlin, tag) + open fun tag( + type: Class, + tag: T?, + ) = commonTag(type.kotlin, tag) open fun build(): Request = Request(this) } diff --git a/okhttp/src/main/kotlin/okhttp3/RequestBody.kt b/okhttp/src/main/kotlin/okhttp3/RequestBody.kt index bcdc43252932..33e0d377b90f 100644 --- a/okhttp/src/main/kotlin/okhttp3/RequestBody.kt +++ b/okhttp/src/main/kotlin/okhttp3/RequestBody.kt @@ -33,7 +33,6 @@ import okio.buffer import okio.source abstract class RequestBody { - /** Returns the Content-Type header for this body. */ abstract fun contentType(): MediaType? @@ -116,8 +115,7 @@ abstract class RequestBody { @JvmStatic @JvmName("create") - fun ByteString.toRequestBody(contentType: MediaType? = null): RequestBody = - commonToRequestBody(contentType) + fun ByteString.toRequestBody(contentType: MediaType? = null): RequestBody = commonToRequestBody(contentType) /** Returns a new request body that transmits this. */ @JvmStatic @@ -164,7 +162,10 @@ abstract class RequestBody { /** Returns a new request body that transmits the content of this. */ @JvmStatic @JvmName("create") - fun Path.asRequestBody(fileSystem: FileSystem, contentType: MediaType? = null): RequestBody { + fun Path.asRequestBody( + fileSystem: FileSystem, + contentType: MediaType? = null, + ): RequestBody { return object : RequestBody() { override fun contentType() = contentType @@ -178,52 +179,66 @@ abstract class RequestBody { @JvmStatic @Deprecated( - message = "Moved to extension function. Put the 'content' argument first to fix Java", - replaceWith = ReplaceWith( - expression = "content.toRequestBody(contentType)", - imports = ["okhttp3.RequestBody.Companion.toRequestBody"] + message = "Moved to extension function. Put the 'content' argument first to fix Java", + replaceWith = + ReplaceWith( + expression = "content.toRequestBody(contentType)", + imports = ["okhttp3.RequestBody.Companion.toRequestBody"], ), - level = DeprecationLevel.WARNING) - fun create(contentType: MediaType?, content: String): RequestBody = content.toRequestBody(contentType) + level = DeprecationLevel.WARNING, + ) + fun create( + contentType: MediaType?, + content: String, + ): RequestBody = content.toRequestBody(contentType) @JvmStatic @Deprecated( - message = "Moved to extension function. Put the 'content' argument first to fix Java", - replaceWith = ReplaceWith( - expression = "content.toRequestBody(contentType)", - imports = ["okhttp3.RequestBody.Companion.toRequestBody"] + message = "Moved to extension function. Put the 'content' argument first to fix Java", + replaceWith = + ReplaceWith( + expression = "content.toRequestBody(contentType)", + imports = ["okhttp3.RequestBody.Companion.toRequestBody"], ), - level = DeprecationLevel.WARNING) + level = DeprecationLevel.WARNING, + ) fun create( contentType: MediaType?, - content: ByteString + content: ByteString, ): RequestBody = content.toRequestBody(contentType) @JvmOverloads @JvmStatic @Deprecated( - message = "Moved to extension function. Put the 'content' argument first to fix Java", - replaceWith = ReplaceWith( - expression = "content.toRequestBody(contentType, offset, byteCount)", - imports = ["okhttp3.RequestBody.Companion.toRequestBody"] + message = "Moved to extension function. Put the 'content' argument first to fix Java", + replaceWith = + ReplaceWith( + expression = "content.toRequestBody(contentType, offset, byteCount)", + imports = ["okhttp3.RequestBody.Companion.toRequestBody"], ), - level = DeprecationLevel.WARNING) + level = DeprecationLevel.WARNING, + ) fun create( contentType: MediaType?, content: ByteArray, offset: Int = 0, - byteCount: Int = content.size + byteCount: Int = content.size, ): RequestBody = content.toRequestBody(contentType, offset, byteCount) @JvmStatic @Deprecated( - message = "Moved to extension function. Put the 'file' argument first to fix Java", - replaceWith = ReplaceWith( - expression = "file.asRequestBody(contentType)", - imports = ["okhttp3.RequestBody.Companion.asRequestBody"] + message = "Moved to extension function. Put the 'file' argument first to fix Java", + replaceWith = + ReplaceWith( + expression = "file.asRequestBody(contentType)", + imports = ["okhttp3.RequestBody.Companion.asRequestBody"], ), - level = DeprecationLevel.WARNING) - fun create(contentType: MediaType?, file: File): RequestBody= file.asRequestBody(contentType) + level = DeprecationLevel.WARNING, + ) + fun create( + contentType: MediaType?, + file: File, + ): RequestBody = file.asRequestBody(contentType) /** * Returns a gzip version of the RequestBody, with compressed payload. diff --git a/okhttp/src/main/kotlin/okhttp3/Response.kt b/okhttp/src/main/kotlin/okhttp3/Response.kt index 3f3ba4a8cc5d..948bbb89a9e4 100644 --- a/okhttp/src/main/kotlin/okhttp3/Response.kt +++ b/okhttp/src/main/kotlin/okhttp3/Response.kt @@ -66,25 +66,19 @@ class Response internal constructor( * [priorResponse] objects, which have its own [priorResponse]. */ @get:JvmName("request") val request: Request, - /** Returns the HTTP protocol, such as [Protocol.HTTP_1_1] or [Protocol.HTTP_1_0]. */ @get:JvmName("protocol") val protocol: Protocol, - /** Returns the HTTP status message. */ @get:JvmName("message") val message: String, - /** Returns the HTTP status code. */ @get:JvmName("code") val code: Int, - /** * Returns the TLS handshake of the connection that carried this response, or null if the * response was received without TLS. */ @get:JvmName("handshake") val handshake: Handshake?, - /** Returns the HTTP headers. */ @get:JvmName("headers") val headers: Headers, - /** * Returns a non-null value if this response was passed to [Callback.onResponse] or returned * from [Call.execute]. Response bodies must be [closed][ResponseBody] and may @@ -94,21 +88,18 @@ class Response internal constructor( * and [priorResponse]. */ @get:JvmName("body") val body: ResponseBody, - /** * Returns the raw response received from the network. Will be null if this response didn't use * the network, such as when the response is fully cached. The body of the returned response * should not be read. */ @get:JvmName("networkResponse") val networkResponse: Response?, - /** * Returns the raw response received from the cache. Will be null if this response didn't use * the cache. For conditional get requests the cache response and network response may both be * non-null. The body of the returned response should not be read. */ @get:JvmName("cacheResponse") val cacheResponse: Response?, - /** * Returns the response for the HTTP redirect or authorization challenge that triggered this * response, or null if this response wasn't triggered by an automatic retry. The body of the @@ -116,47 +107,45 @@ class Response internal constructor( * client. */ @get:JvmName("priorResponse") val priorResponse: Response?, - /** * Returns a [timestamp][System.currentTimeMillis] taken immediately before OkHttp * transmitted the initiating request over the network. If this response is being served from the * cache then this is the timestamp of the original request. */ @get:JvmName("sentRequestAtMillis") val sentRequestAtMillis: Long, - /** * Returns a [timestamp][System.currentTimeMillis] taken immediately after OkHttp * received this response's headers from the network. If this response is being served from the * cache then this is the timestamp of the original response. */ @get:JvmName("receivedResponseAtMillis") val receivedResponseAtMillis: Long, - @get:JvmName("exchange") internal val exchange: Exchange?, - - private var trailersFn: (() -> Headers) + private var trailersFn: (() -> Headers), ) : Closeable { - internal var lazyCacheControl: CacheControl? = null @JvmName("-deprecated_request") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "request"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "request"), + level = DeprecationLevel.ERROR, + ) fun request(): Request = request @JvmName("-deprecated_protocol") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "protocol"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "protocol"), + level = DeprecationLevel.ERROR, + ) fun protocol(): Protocol = protocol @JvmName("-deprecated_code") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "code"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "code"), + level = DeprecationLevel.ERROR, + ) fun code(): Int = code /** @@ -167,28 +156,34 @@ class Response internal constructor( @JvmName("-deprecated_message") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "message"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "message"), + level = DeprecationLevel.ERROR, + ) fun message(): String = message @JvmName("-deprecated_handshake") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "handshake"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "handshake"), + level = DeprecationLevel.ERROR, + ) fun handshake(): Handshake? = handshake fun headers(name: String): List = commonHeaders(name) @JvmOverloads - fun header(name: String, defaultValue: String? = null): String? = commonHeader(name, defaultValue) + fun header( + name: String, + defaultValue: String? = null, + ): String? = commonHeader(name, defaultValue) @JvmName("-deprecated_headers") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "headers"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "headers"), + level = DeprecationLevel.ERROR, + ) fun headers(): Headers = headers /** @@ -220,9 +215,10 @@ class Response internal constructor( @JvmName("-deprecated_body") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "body"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "body"), + level = DeprecationLevel.ERROR, + ) fun body() = body fun newBuilder(): Builder = commonNewBuilder() @@ -232,23 +228,26 @@ class Response internal constructor( @JvmName("-deprecated_networkResponse") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "networkResponse"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "networkResponse"), + level = DeprecationLevel.ERROR, + ) fun networkResponse(): Response? = networkResponse @JvmName("-deprecated_cacheResponse") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "cacheResponse"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "cacheResponse"), + level = DeprecationLevel.ERROR, + ) fun cacheResponse(): Response? = cacheResponse @JvmName("-deprecated_priorResponse") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "priorResponse"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "priorResponse"), + level = DeprecationLevel.ERROR, + ) fun priorResponse(): Response? = priorResponse /** @@ -264,11 +263,11 @@ class Response internal constructor( */ fun challenges(): List { return headers.parseChallenges( - when (code) { - HTTP_UNAUTHORIZED -> "WWW-Authenticate" - HTTP_PROXY_AUTH -> "Proxy-Authenticate" - else -> return emptyList() - } + when (code) { + HTTP_UNAUTHORIZED -> "WWW-Authenticate" + HTTP_PROXY_AUTH -> "Proxy-Authenticate" + else -> return emptyList() + }, ) } @@ -276,28 +275,32 @@ class Response internal constructor( * Returns the cache control directives for this response. This is never null, even if this * response contains no `Cache-Control` header. */ - @get:JvmName("cacheControl") val cacheControl: CacheControl + @get:JvmName("cacheControl") + val cacheControl: CacheControl get() = commonCacheControl @JvmName("-deprecated_cacheControl") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "cacheControl"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "cacheControl"), + level = DeprecationLevel.ERROR, + ) fun cacheControl(): CacheControl = cacheControl @JvmName("-deprecated_sentRequestAtMillis") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "sentRequestAtMillis"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "sentRequestAtMillis"), + level = DeprecationLevel.ERROR, + ) fun sentRequestAtMillis(): Long = sentRequestAtMillis @JvmName("-deprecated_receivedResponseAtMillis") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "receivedResponseAtMillis"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "receivedResponseAtMillis"), + level = DeprecationLevel.ERROR, + ) fun receivedResponseAtMillis(): Long = receivedResponseAtMillis /** @@ -349,27 +352,34 @@ class Response internal constructor( open fun request(request: Request) = commonRequest(request) - open fun protocol(protocol: Protocol) =commonProtocol(protocol) + open fun protocol(protocol: Protocol) = commonProtocol(protocol) open fun code(code: Int) = commonCode(code) open fun message(message: String) = commonMessage(message) - open fun handshake(handshake: Handshake?) = apply { - this.handshake = handshake - } + open fun handshake(handshake: Handshake?) = + apply { + this.handshake = handshake + } /** * Sets the header named [name] to [value]. If this request already has any headers * with that name, they are all replaced. */ - open fun header(name: String, value: String) = commonHeader(name, value) + open fun header( + name: String, + value: String, + ) = commonHeader(name, value) /** * Adds a header with [name] to [value]. Prefer this method for multiply-valued * headers like "Set-Cookie". */ - open fun addHeader(name: String, value: String) = commonAddHeader(name, value) + open fun addHeader( + name: String, + value: String, + ) = commonAddHeader(name, value) /** Removes all headers named [name] on this builder. */ open fun removeHeader(name: String) = commonRemoveHeader(name) @@ -387,13 +397,15 @@ class Response internal constructor( open fun trailers(trailersFn: (() -> Headers)): Builder = commonTrailers(trailersFn) - open fun sentRequestAtMillis(sentRequestAtMillis: Long) = apply { - this.sentRequestAtMillis = sentRequestAtMillis - } + open fun sentRequestAtMillis(sentRequestAtMillis: Long) = + apply { + this.sentRequestAtMillis = sentRequestAtMillis + } - open fun receivedResponseAtMillis(receivedResponseAtMillis: Long) = apply { - this.receivedResponseAtMillis = receivedResponseAtMillis - } + open fun receivedResponseAtMillis(receivedResponseAtMillis: Long) = + apply { + this.receivedResponseAtMillis = receivedResponseAtMillis + } internal fun initExchange(exchange: Exchange) { this.exchange = exchange @@ -403,20 +415,20 @@ class Response internal constructor( open fun build(): Response { check(code >= 0) { "code < 0: $code" } return Response( - checkNotNull(request) { "request == null" }, - checkNotNull(protocol) { "protocol == null" }, - checkNotNull(message) { "message == null" }, - code, - handshake, - headers.build(), - body, - networkResponse, - cacheResponse, - priorResponse, - sentRequestAtMillis, - receivedResponseAtMillis, - exchange, - trailersFn + checkNotNull(request) { "request == null" }, + checkNotNull(protocol) { "protocol == null" }, + checkNotNull(message) { "message == null" }, + code, + handshake, + headers.build(), + body, + networkResponse, + cacheResponse, + priorResponse, + sentRequestAtMillis, + receivedResponseAtMillis, + exchange, + trailersFn, ) } } diff --git a/okhttp/src/main/kotlin/okhttp3/ResponseBody.kt b/okhttp/src/main/kotlin/okhttp3/ResponseBody.kt index 555ee961dc56..a01f68afc926 100644 --- a/okhttp/src/main/kotlin/okhttp3/ResponseBody.kt +++ b/okhttp/src/main/kotlin/okhttp3/ResponseBody.kt @@ -149,9 +149,10 @@ abstract class ResponseBody : Closeable { * * Otherwise the response bytes are decoded as UTF-8. */ - fun charStream(): Reader = reader ?: BomAwareReader(source(), charset()).also { - reader = it - } + fun charStream(): Reader = + reader ?: BomAwareReader(source(), charset()).also { + reader = it + } /** * Returns the response as a string. @@ -170,9 +171,10 @@ abstract class ResponseBody : Closeable { * possibility for your response. */ @Throws(IOException::class) - fun string(): String = source().use { source -> - source.readString(charset = source.readBomAsCharset(charset())) - } + fun string(): String = + source().use { source -> + source.readString(charset = source.readBomAsCharset(charset())) + } private fun charset() = contentType().charsetOrUtf8() @@ -180,21 +182,26 @@ abstract class ResponseBody : Closeable { internal class BomAwareReader( private val source: BufferedSource, - private val charset: Charset + private val charset: Charset, ) : Reader() { - private var closed: Boolean = false private var delegate: Reader? = null @Throws(IOException::class) - override fun read(cbuf: CharArray, off: Int, len: Int): Int { + override fun read( + cbuf: CharArray, + off: Int, + len: Int, + ): Int { if (closed) throw IOException("Stream closed") - val finalDelegate = delegate ?: InputStreamReader( + val finalDelegate = + delegate ?: InputStreamReader( source.inputStream(), - source.readBomAsCharset(charset)).also { - delegate = it - } + source.readBomAsCharset(charset), + ).also { + delegate = it + } return finalDelegate.read(cbuf, off, len) } @@ -242,46 +249,63 @@ abstract class ResponseBody : Closeable { @JvmStatic @Deprecated( - message = "Moved to extension function. Put the 'content' argument first to fix Java", - replaceWith = ReplaceWith( - expression = "content.toResponseBody(contentType)", - imports = ["okhttp3.ResponseBody.Companion.toResponseBody"] + message = "Moved to extension function. Put the 'content' argument first to fix Java", + replaceWith = + ReplaceWith( + expression = "content.toResponseBody(contentType)", + imports = ["okhttp3.ResponseBody.Companion.toResponseBody"], ), - level = DeprecationLevel.WARNING) - fun create(contentType: MediaType?, content: String): ResponseBody = content.toResponseBody(contentType) + level = DeprecationLevel.WARNING, + ) + fun create( + contentType: MediaType?, + content: String, + ): ResponseBody = content.toResponseBody(contentType) @JvmStatic @Deprecated( - message = "Moved to extension function. Put the 'content' argument first to fix Java", - replaceWith = ReplaceWith( - expression = "content.toResponseBody(contentType)", - imports = ["okhttp3.ResponseBody.Companion.toResponseBody"] + message = "Moved to extension function. Put the 'content' argument first to fix Java", + replaceWith = + ReplaceWith( + expression = "content.toResponseBody(contentType)", + imports = ["okhttp3.ResponseBody.Companion.toResponseBody"], ), - level = DeprecationLevel.WARNING) - fun create(contentType: MediaType?, content: ByteArray): ResponseBody = content.toResponseBody(contentType) + level = DeprecationLevel.WARNING, + ) + fun create( + contentType: MediaType?, + content: ByteArray, + ): ResponseBody = content.toResponseBody(contentType) @JvmStatic @Deprecated( - message = "Moved to extension function. Put the 'content' argument first to fix Java", - replaceWith = ReplaceWith( - expression = "content.toResponseBody(contentType)", - imports = ["okhttp3.ResponseBody.Companion.toResponseBody"] + message = "Moved to extension function. Put the 'content' argument first to fix Java", + replaceWith = + ReplaceWith( + expression = "content.toResponseBody(contentType)", + imports = ["okhttp3.ResponseBody.Companion.toResponseBody"], ), - level = DeprecationLevel.WARNING) - fun create(contentType: MediaType?, content: ByteString): ResponseBody = content.toResponseBody(contentType) + level = DeprecationLevel.WARNING, + ) + fun create( + contentType: MediaType?, + content: ByteString, + ): ResponseBody = content.toResponseBody(contentType) @JvmStatic @Deprecated( - message = "Moved to extension function. Put the 'content' argument first to fix Java", - replaceWith = ReplaceWith( - expression = "content.asResponseBody(contentType, contentLength)", - imports = ["okhttp3.ResponseBody.Companion.asResponseBody"] + message = "Moved to extension function. Put the 'content' argument first to fix Java", + replaceWith = + ReplaceWith( + expression = "content.asResponseBody(contentType, contentLength)", + imports = ["okhttp3.ResponseBody.Companion.asResponseBody"], ), - level = DeprecationLevel.WARNING) + level = DeprecationLevel.WARNING, + ) fun create( contentType: MediaType?, contentLength: Long, - content: BufferedSource + content: BufferedSource, ): ResponseBody = content.asResponseBody(contentType, contentLength) } } diff --git a/okhttp/src/main/kotlin/okhttp3/Route.kt b/okhttp/src/main/kotlin/okhttp3/Route.kt index bfd9093dd2f0..97b81878b86a 100644 --- a/okhttp/src/main/kotlin/okhttp3/Route.kt +++ b/okhttp/src/main/kotlin/okhttp3/Route.kt @@ -39,28 +39,30 @@ class Route( * is null, the proxy selector is used. */ @get:JvmName("proxy") val proxy: Proxy, - @get:JvmName("socketAddress") val socketAddress: InetSocketAddress + @get:JvmName("socketAddress") val socketAddress: InetSocketAddress, ) { - @JvmName("-deprecated_address") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "address"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "address"), + level = DeprecationLevel.ERROR, + ) fun address(): Address = address @JvmName("-deprecated_proxy") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "proxy"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "proxy"), + level = DeprecationLevel.ERROR, + ) fun proxy(): Proxy = proxy @JvmName("-deprecated_socketAddress") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "socketAddress"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "socketAddress"), + level = DeprecationLevel.ERROR, + ) fun socketAddress(): InetSocketAddress = socketAddress /** @@ -77,9 +79,9 @@ class Route( override fun equals(other: Any?): Boolean { return other is Route && - other.address == address && - other.proxy == proxy && - other.socketAddress == socketAddress + other.address == address && + other.proxy == proxy && + other.socketAddress == socketAddress } override fun hashCode(): Int { diff --git a/okhttp/src/main/kotlin/okhttp3/TlsVersion.kt b/okhttp/src/main/kotlin/okhttp3/TlsVersion.kt index 5bd4b491e1b0..1017f5e4c2f2 100644 --- a/okhttp/src/main/kotlin/okhttp3/TlsVersion.kt +++ b/okhttp/src/main/kotlin/okhttp3/TlsVersion.kt @@ -20,24 +20,26 @@ package okhttp3 * [javax.net.ssl.SSLSocket.setEnabledProtocols]. */ enum class TlsVersion( - @get:JvmName("javaName") val javaName: String + @get:JvmName("javaName") val javaName: String, ) { TLS_1_3("TLSv1.3"), // 2016. TLS_1_2("TLSv1.2"), // 2008. TLS_1_1("TLSv1.1"), // 2006. TLS_1_0("TLSv1"), // 1999. - SSL_3_0("SSLv3"); // 1996. + SSL_3_0("SSLv3"), // 1996. + ; @JvmName("-deprecated_javaName") @Deprecated( - message = "moved to val", - replaceWith = ReplaceWith(expression = "javaName"), - level = DeprecationLevel.ERROR) + message = "moved to val", + replaceWith = ReplaceWith(expression = "javaName"), + level = DeprecationLevel.ERROR, + ) fun javaName(): String = javaName companion object { @JvmStatic - fun forJavaName(javaName: String): TlsVersion { + fun forJavaName(javaName: String): TlsVersion { return when (javaName) { "TLSv1.3" -> TLS_1_3 "TLSv1.2" -> TLS_1_2 diff --git a/okhttp/src/main/kotlin/okhttp3/WebSocket.kt b/okhttp/src/main/kotlin/okhttp3/WebSocket.kt index ac731e62e1b1..64a38d87aa71 100644 --- a/okhttp/src/main/kotlin/okhttp3/WebSocket.kt +++ b/okhttp/src/main/kotlin/okhttp3/WebSocket.kt @@ -101,7 +101,10 @@ interface WebSocket { * @param reason Reason for shutting down, no longer than 123 bytes of UTF-8 encoded data (**not** characters) or null. * @throws IllegalArgumentException if [code] is invalid or [reason] is too long. */ - fun close(code: Int, reason: String?): Boolean + fun close( + code: Int, + reason: String?, + ): Boolean /** * Immediately and violently release resources held by this web socket, discarding any enqueued @@ -116,6 +119,9 @@ interface WebSocket { * notified. The caller must either close or cancel the returned web socket when it is no longer * in use. */ - fun newWebSocket(request: Request, listener: WebSocketListener): WebSocket + fun newWebSocket( + request: Request, + listener: WebSocketListener, + ): WebSocket } } diff --git a/okhttp/src/main/kotlin/okhttp3/WebSocketListener.kt b/okhttp/src/main/kotlin/okhttp3/WebSocketListener.kt index 56bfef9749df..a8aea8479f15 100644 --- a/okhttp/src/main/kotlin/okhttp3/WebSocketListener.kt +++ b/okhttp/src/main/kotlin/okhttp3/WebSocketListener.kt @@ -22,28 +22,45 @@ abstract class WebSocketListener { * Invoked when a web socket has been accepted by the remote peer and may begin transmitting * messages. */ - open fun onOpen(webSocket: WebSocket, response: Response) { + open fun onOpen( + webSocket: WebSocket, + response: Response, + ) { } /** Invoked when a text (type `0x1`) message has been received. */ - open fun onMessage(webSocket: WebSocket, text: String) { + open fun onMessage( + webSocket: WebSocket, + text: String, + ) { } /** Invoked when a binary (type `0x2`) message has been received. */ - open fun onMessage(webSocket: WebSocket, bytes: ByteString) { + open fun onMessage( + webSocket: WebSocket, + bytes: ByteString, + ) { } /** * Invoked when the remote peer has indicated that no more incoming messages will be transmitted. */ - open fun onClosing(webSocket: WebSocket, code: Int, reason: String) { + open fun onClosing( + webSocket: WebSocket, + code: Int, + reason: String, + ) { } /** * Invoked when both peers have indicated that no more messages will be transmitted and the * connection has been successfully released. No further calls to this listener will be made. */ - open fun onClosed(webSocket: WebSocket, code: Int, reason: String) { + open fun onClosed( + webSocket: WebSocket, + code: Int, + reason: String, + ) { } /** @@ -51,6 +68,10 @@ abstract class WebSocketListener { * network. Both outgoing and incoming messages may have been lost. No further calls to this * listener will be made. */ - open fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + open fun onFailure( + webSocket: WebSocket, + t: Throwable, + response: Response?, + ) { } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt index c91ba7a2eac4..d35103a34ff3 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import kotlin.time.DurationUnit @@ -24,40 +25,50 @@ import okhttp3.Headers internal fun CacheControl.commonToString(): String { var result = headerValue if (result == null) { - result = buildString { - if (noCache) append("no-cache, ") - if (noStore) append("no-store, ") - if (maxAgeSeconds != -1) append("max-age=").append(maxAgeSeconds).append(", ") - if (sMaxAgeSeconds != -1) append("s-maxage=").append(sMaxAgeSeconds).append(", ") - if (isPrivate) append("private, ") - if (isPublic) append("public, ") - if (mustRevalidate) append("must-revalidate, ") - if (maxStaleSeconds != -1) append("max-stale=").append(maxStaleSeconds).append(", ") - if (minFreshSeconds != -1) append("min-fresh=").append(minFreshSeconds).append(", ") - if (onlyIfCached) append("only-if-cached, ") - if (noTransform) append("no-transform, ") - if (immutable) append("immutable, ") - if (isEmpty()) return "" - deleteRange(length - 2, length) - } + result = + buildString { + if (noCache) append("no-cache, ") + if (noStore) append("no-store, ") + if (maxAgeSeconds != -1) append("max-age=").append(maxAgeSeconds).append(", ") + if (sMaxAgeSeconds != -1) append("s-maxage=").append(sMaxAgeSeconds).append(", ") + if (isPrivate) append("private, ") + if (isPublic) append("public, ") + if (mustRevalidate) append("must-revalidate, ") + if (maxStaleSeconds != -1) append("max-stale=").append(maxStaleSeconds).append(", ") + if (minFreshSeconds != -1) append("min-fresh=").append(minFreshSeconds).append(", ") + if (onlyIfCached) append("only-if-cached, ") + if (noTransform) append("no-transform, ") + if (immutable) append("immutable, ") + if (isEmpty()) return "" + deleteRange(length - 2, length) + } headerValue = result } return result } -internal fun CacheControl.Builder.commonMaxAge(maxAge: Int, timeUnit: DurationUnit) = apply { +internal fun CacheControl.Builder.commonMaxAge( + maxAge: Int, + timeUnit: DurationUnit, +) = apply { require(maxAge >= 0) { "maxAge < 0: $maxAge" } val maxAgeSecondsLong = maxAge.toDuration(timeUnit).inWholeSeconds this.maxAgeSeconds = maxAgeSecondsLong.commonClampToInt() } -internal fun CacheControl.Builder.commonMaxStale(maxStale: Int, timeUnit: DurationUnit) = apply { +internal fun CacheControl.Builder.commonMaxStale( + maxStale: Int, + timeUnit: DurationUnit, +) = apply { require(maxStale >= 0) { "maxStale < 0: $maxStale" } val maxStaleSecondsLong = maxStale.toDuration(timeUnit).inWholeSeconds this.maxStaleSeconds = maxStaleSecondsLong.commonClampToInt() } -internal fun CacheControl.Builder.commonMinFresh(minFresh: Int, timeUnit: DurationUnit) = apply { +internal fun CacheControl.Builder.commonMinFresh( + minFresh: Int, + timeUnit: DurationUnit, +) = apply { require(minFresh >= 0) { "minFresh < 0: $minFresh" } val minFreshSecondsLong = minFresh.toDuration(timeUnit).inWholeSeconds this.minFreshSeconds = minFreshSecondsLong.commonClampToInt() @@ -70,15 +81,16 @@ internal fun Long.commonClampToInt(): Int { } } -internal fun CacheControl.Companion.commonForceNetwork() = CacheControl.Builder() - .noCache() - .build() - +internal fun CacheControl.Companion.commonForceNetwork() = + CacheControl.Builder() + .noCache() + .build() -internal fun CacheControl.Companion.commonForceCache() = CacheControl.Builder() - .onlyIfCached() - .maxStale(Int.MAX_VALUE, DurationUnit.SECONDS) - .build() +internal fun CacheControl.Companion.commonForceCache() = + CacheControl.Builder() + .onlyIfCached() + .maxStale(Int.MAX_VALUE, DurationUnit.SECONDS) + .build() internal fun CacheControl.Builder.commonBuild(): CacheControl { return CacheControl( @@ -94,29 +106,34 @@ internal fun CacheControl.Builder.commonBuild(): CacheControl { onlyIfCached = onlyIfCached, noTransform = noTransform, immutable = immutable, - headerValue = null + headerValue = null, ) } -internal fun CacheControl.Builder.commonNoCache() = apply { - this.noCache = true -} +internal fun CacheControl.Builder.commonNoCache() = + apply { + this.noCache = true + } -internal fun CacheControl.Builder.commonNoStore() = apply { - this.noStore = true -} +internal fun CacheControl.Builder.commonNoStore() = + apply { + this.noStore = true + } -internal fun CacheControl.Builder.commonOnlyIfCached() = apply { - this.onlyIfCached = true -} +internal fun CacheControl.Builder.commonOnlyIfCached() = + apply { + this.onlyIfCached = true + } -internal fun CacheControl.Builder.commonNoTransform() = apply { - this.noTransform = true -} +internal fun CacheControl.Builder.commonNoTransform() = + apply { + this.noTransform = true + } -internal fun CacheControl.Builder.commonImmutable() = apply { - this.immutable = true -} +internal fun CacheControl.Builder.commonImmutable() = + apply { + this.immutable = true + } internal fun CacheControl.Companion.commonParse(headers: Headers): CacheControl { var noCache = false @@ -244,7 +261,7 @@ internal fun CacheControl.Companion.commonParse(headers: Headers): CacheControl onlyIfCached = onlyIfCached, noTransform = noTransform, immutable = immutable, - headerValue = headerValue + headerValue = headerValue, ) } @@ -252,7 +269,10 @@ internal fun CacheControl.Companion.commonParse(headers: Headers): CacheControl * Returns the next index in this at or after [startIndex] that is a character from * [characters]. Returns the input length if none of the requested characters can be found. */ -private fun String.indexOfElement(characters: String, startIndex: Int = 0): Int { +private fun String.indexOfElement( + characters: String, + startIndex: Int = 0, +): Int { for (i in startIndex until length) { if (this[i] in characters) { return i diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-ChallengeCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-ChallengeCommon.kt index 46b49f88968c..285f4e9aea77 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-ChallengeCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-ChallengeCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import okhttp3.Challenge diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-HeadersCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-HeadersCommon.kt index cf799e96bb0c..001461a3a426 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-HeadersCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-HeadersCommon.kt @@ -15,13 +15,15 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import okhttp3.Headers internal fun Headers.commonName(index: Int): String = namesAndValues.getOrNull(index * 2) ?: throw IndexOutOfBoundsException("name[$index]") -internal fun Headers.commonValue(index: Int): String = namesAndValues.getOrNull(index * 2 + 1) ?: throw IndexOutOfBoundsException("value[$index]") +internal fun Headers.commonValue(index: Int): String = + namesAndValues.getOrNull(index * 2 + 1) ?: throw IndexOutOfBoundsException("value[$index]") internal fun Headers.commonValues(name: String): List { var result: MutableList? = null @@ -63,7 +65,10 @@ internal fun Headers.commonToString(): String { } } -internal fun commonHeadersGet(namesAndValues: Array, name: String): String? { +internal fun commonHeadersGet( + namesAndValues: Array, + name: String, +): String? { for (i in namesAndValues.size - 2 downTo 0 step 2) { if (name.equals(namesAndValues[i], ignoreCase = true)) { return namesAndValues[i + 1] @@ -72,40 +77,51 @@ internal fun commonHeadersGet(namesAndValues: Array, name: String): Stri return null } -internal fun Headers.Builder.commonAdd(name: String, value: String) = apply { +internal fun Headers.Builder.commonAdd( + name: String, + value: String, +) = apply { headersCheckName(name) headersCheckValue(value, name) commonAddLenient(name, value) } -internal fun Headers.Builder.commonAddAll(headers: Headers) = apply { - for (i in 0 until headers.size) { - commonAddLenient(headers.name(i), headers.value(i)) +internal fun Headers.Builder.commonAddAll(headers: Headers) = + apply { + for (i in 0 until headers.size) { + commonAddLenient(headers.name(i), headers.value(i)) + } } -} -internal fun Headers.Builder.commonAddLenient(name: String, value: String) = apply { +internal fun Headers.Builder.commonAddLenient( + name: String, + value: String, +) = apply { namesAndValues.add(name) namesAndValues.add(value.trim()) } -internal fun Headers.Builder.commonRemoveAll(name: String) = apply { - var i = 0 - while (i < namesAndValues.size) { - if (name.equals(namesAndValues[i], ignoreCase = true)) { - namesAndValues.removeAt(i) // name - namesAndValues.removeAt(i) // value - i -= 2 +internal fun Headers.Builder.commonRemoveAll(name: String) = + apply { + var i = 0 + while (i < namesAndValues.size) { + if (name.equals(namesAndValues[i], ignoreCase = true)) { + namesAndValues.removeAt(i) // name + namesAndValues.removeAt(i) // value + i -= 2 + } + i += 2 } - i += 2 } -} /** * Set a field with the specified value. If the field is not found, it is added. If the field is * found, the existing values are replaced. */ -internal fun Headers.Builder.commonSet(name: String, value: String) = apply { +internal fun Headers.Builder.commonSet( + name: String, + value: String, +) = apply { headersCheckName(name) headersCheckValue(value, name) removeAll(name) @@ -134,7 +150,10 @@ internal fun headersCheckName(name: String) { } } -internal fun headersCheckValue(value: String, name: String) { +internal fun headersCheckValue( + value: String, + name: String, +) { for (i in value.indices) { val c = value[i] require(c == '\t' || c in '\u0020'..'\u007e') { @@ -144,13 +163,14 @@ internal fun headersCheckValue(value: String, name: String) { } } -private fun Char.charCode() = code.toString(16).let { - if (it.length < 2) { - "0$it" - } else { - it +private fun Char.charCode() = + code.toString(16).let { + if (it.length < 2) { + "0$it" + } else { + it + } } -} internal fun commonHeadersOf(vararg inputNamesAndValues: String): Headers { require(inputNamesAndValues.size % 2 == 0) { "Expected alternating header names and values" } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-HostnamesCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-HostnamesCommon.kt index bd6525edb03d..ef8b6b688d14 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-HostnamesCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-HostnamesCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import okhttp3.internal.idn.IDNA_MAPPING_TABLE @@ -45,10 +46,11 @@ internal fun String.containsInvalidLabelLengths(): Boolean { var labelStart = 0 while (true) { val dot = indexOf('.', startIndex = labelStart) - val labelLength = when (dot) { - -1 -> length - labelStart - else -> dot - labelStart - } + val labelLength = + when (dot) { + -1 -> length - labelStart + else -> dot - labelStart + } if (labelLength !in 1..63) return true if (dot == -1) break if (dot == length - 1) break // Trailing '.' is allowed. @@ -78,7 +80,11 @@ internal fun String.containsInvalidHostnameAsciiCodes(): Boolean { } /** Decodes an IPv6 address like 1111:2222:3333:4444:5555:6666:7777:8888 or ::1. */ -internal fun decodeIpv6(input: String, pos: Int, limit: Int): ByteArray? { +internal fun decodeIpv6( + input: String, + pos: Int, + limit: Int, +): ByteArray? { val address = ByteArray(16) var b = 0 var compress = -1 @@ -151,7 +157,7 @@ internal fun decodeIpv4Suffix( pos: Int, limit: Int, address: ByteArray, - addressOffset: Int + addressOffset: Int, ): Boolean { var b = addressOffset @@ -283,11 +289,14 @@ internal fun String.toCanonicalHost(): String? { // If the input contains a :, it’s an IPv6 address. if (":" in host) { // If the input is encased in square braces "[...]", drop 'em. - val inetAddressByteArray = (if (host.startsWith("[") && host.endsWith("]")) { - decodeIpv6(host, 1, host.length - 1) - } else { - decodeIpv6(host, 0, host.length) - }) ?: return null + val inetAddressByteArray = + ( + if (host.startsWith("[") && host.endsWith("]")) { + decodeIpv6(host, 1, host.length - 1) + } else { + decodeIpv6(host, 0, host.length) + } + ) ?: return null val address = canonicalizeInetAddress(inetAddressByteArray) if (address.size == 16) return inet6AddressToAscii(address) @@ -310,7 +319,7 @@ internal fun idnToAscii(host: String): String? { // 1. Map, from bufferA to bufferB. while (!bufferA.exhausted()) { val codePoint = bufferA.readUtf8CodePoint() - if(!IDNA_MAPPING_TABLE.map(codePoint, bufferB)) return null + if (!IDNA_MAPPING_TABLE.map(codePoint, bufferB)) return null } // 2. Normalize, from bufferB to bufferA. @@ -332,4 +341,3 @@ internal fun idnToAscii(host: String): String? { return Punycode.encode(decoded) } - diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-HttpUrlCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-HttpUrlCommon.kt index 01b476228c62..fc89e9007e98 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-HttpUrlCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-HttpUrlCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import kotlin.jvm.JvmStatic @@ -23,7 +24,6 @@ import okhttp3.internal.HttpUrlCommon.writePercentDecoded import okio.Buffer internal object CommonHttpUrl { - internal val HEX_DIGITS = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F') private const val USERNAME_ENCODE_SET = " \"':;<=>@[]^`{}|/\\?#" @@ -172,7 +172,6 @@ internal object CommonHttpUrl { .toString() } - fun HttpUrl.commonResolve(link: String): HttpUrl? = newBuilder(link)?.build() fun HttpUrl.commonNewBuilder(): HttpUrl.Builder { @@ -206,7 +205,6 @@ internal object CommonHttpUrl { fun HttpUrl.commonToString(): String = url - /** Returns 80 if `scheme.equals("http")`, 443 if `scheme.equals("https")` and -1 otherwise. */ @JvmStatic fun commonDefaultPort(scheme: String): Int { @@ -217,54 +215,62 @@ internal object CommonHttpUrl { } } - /** * @param scheme either "http" or "https". */ - fun HttpUrl.Builder.commonScheme(scheme: String) = apply { - when { - scheme.equals("http", ignoreCase = true) -> this.scheme = "http" - scheme.equals("https", ignoreCase = true) -> this.scheme = "https" - else -> throw IllegalArgumentException("unexpected scheme: $scheme") + fun HttpUrl.Builder.commonScheme(scheme: String) = + apply { + when { + scheme.equals("http", ignoreCase = true) -> this.scheme = "http" + scheme.equals("https", ignoreCase = true) -> this.scheme = "https" + else -> throw IllegalArgumentException("unexpected scheme: $scheme") + } } - } - fun HttpUrl.Builder.commonUsername(username: String) = apply { - this.encodedUsername = username.canonicalize(encodeSet = USERNAME_ENCODE_SET) - } + fun HttpUrl.Builder.commonUsername(username: String) = + apply { + this.encodedUsername = username.canonicalize(encodeSet = USERNAME_ENCODE_SET) + } - fun HttpUrl.Builder.commonEncodedUsername(encodedUsername: String) = apply { - this.encodedUsername = encodedUsername.canonicalize( - encodeSet = USERNAME_ENCODE_SET, - alreadyEncoded = true - ) - } + fun HttpUrl.Builder.commonEncodedUsername(encodedUsername: String) = + apply { + this.encodedUsername = + encodedUsername.canonicalize( + encodeSet = USERNAME_ENCODE_SET, + alreadyEncoded = true, + ) + } - fun HttpUrl.Builder.commonPassword(password: String) = apply { - this.encodedPassword = password.canonicalize(encodeSet = PASSWORD_ENCODE_SET) - } + fun HttpUrl.Builder.commonPassword(password: String) = + apply { + this.encodedPassword = password.canonicalize(encodeSet = PASSWORD_ENCODE_SET) + } - fun HttpUrl.Builder.commonEncodedPassword(encodedPassword: String) = apply { - this.encodedPassword = encodedPassword.canonicalize( - encodeSet = PASSWORD_ENCODE_SET, - alreadyEncoded = true - ) - } + fun HttpUrl.Builder.commonEncodedPassword(encodedPassword: String) = + apply { + this.encodedPassword = + encodedPassword.canonicalize( + encodeSet = PASSWORD_ENCODE_SET, + alreadyEncoded = true, + ) + } /** * @param host either a regular hostname, International Domain Name, IPv4 address, or IPv6 * address. */ - fun HttpUrl.Builder.commonHost(host: String) = apply { - val encoded = host.percentDecode().toCanonicalHost() - ?: throw IllegalArgumentException("unexpected host: $host") - this.host = encoded - } + fun HttpUrl.Builder.commonHost(host: String) = + apply { + val encoded = + host.percentDecode().toCanonicalHost() + ?: throw IllegalArgumentException("unexpected host: $host") + this.host = encoded + } internal fun String.percentDecode( pos: Int = 0, limit: Int = length, - plusIsSpace: Boolean = false + plusIsSpace: Boolean = false, ): String { for (i in pos until limit) { val c = this[i] @@ -281,15 +287,16 @@ internal object CommonHttpUrl { return substring(pos, limit) } - fun HttpUrl.Builder.commonPort(port: Int) = apply { - require(port in 1..65535) { "unexpected port: $port" } - this.port = port - } - + fun HttpUrl.Builder.commonPort(port: Int) = + apply { + require(port in 1..65535) { "unexpected port: $port" } + this.port = port + } - fun HttpUrl.Builder.commonAddPathSegment(pathSegment: String) = apply { - push(pathSegment, 0, pathSegment.length, addTrailingSlash = false, alreadyEncoded = false) - } + fun HttpUrl.Builder.commonAddPathSegment(pathSegment: String) = + apply { + push(pathSegment, 0, pathSegment.length, addTrailingSlash = false, alreadyEncoded = false) + } /** * Adds a set of path segments separated by a slash (either `\` or `/`). If `pathSegments` @@ -297,10 +304,16 @@ internal object CommonHttpUrl { */ fun HttpUrl.Builder.commonAddPathSegments(pathSegments: String): HttpUrl.Builder = commonAddPathSegments(pathSegments, false) - fun HttpUrl.Builder.commonAddEncodedPathSegment(encodedPathSegment: String) = apply { - push(encodedPathSegment, 0, encodedPathSegment.length, addTrailingSlash = false, - alreadyEncoded = true) - } + fun HttpUrl.Builder.commonAddEncodedPathSegment(encodedPathSegment: String) = + apply { + push( + encodedPathSegment, + 0, + encodedPathSegment.length, + addTrailingSlash = false, + alreadyEncoded = true, + ) + } /** * Adds a set of encoded path segments separated by a slash (either `\` or `/`). If @@ -309,7 +322,10 @@ internal object CommonHttpUrl { fun HttpUrl.Builder.commonAddEncodedPathSegments(encodedPathSegments: String): HttpUrl.Builder = commonAddPathSegments(encodedPathSegments, true) - private fun HttpUrl.Builder.commonAddPathSegments(pathSegments: String, alreadyEncoded: Boolean) = apply { + private fun HttpUrl.Builder.commonAddPathSegments( + pathSegments: String, + alreadyEncoded: Boolean, + ) = apply { var offset = 0 do { val segmentEnd = pathSegments.delimiterOffset("/\\", offset, pathSegments.length) @@ -319,7 +335,10 @@ internal object CommonHttpUrl { } while (offset <= pathSegments.length) } - fun HttpUrl.Builder.commonSetPathSegment(index: Int, pathSegment: String) = apply { + fun HttpUrl.Builder.commonSetPathSegment( + index: Int, + pathSegment: String, + ) = apply { val canonicalPathSegment = pathSegment.canonicalize(encodeSet = PATH_SEGMENT_ENCODE_SET) require(!isDot(canonicalPathSegment) && !isDotDot(canonicalPathSegment)) { "unexpected path segment: $pathSegment" @@ -327,99 +346,134 @@ internal object CommonHttpUrl { encodedPathSegments[index] = canonicalPathSegment } - fun HttpUrl.Builder.commonSetEncodedPathSegment(index: Int, encodedPathSegment: String) = apply { - val canonicalPathSegment = encodedPathSegment.canonicalize( - encodeSet = PATH_SEGMENT_ENCODE_SET, - alreadyEncoded = true - ) + fun HttpUrl.Builder.commonSetEncodedPathSegment( + index: Int, + encodedPathSegment: String, + ) = apply { + val canonicalPathSegment = + encodedPathSegment.canonicalize( + encodeSet = PATH_SEGMENT_ENCODE_SET, + alreadyEncoded = true, + ) encodedPathSegments[index] = canonicalPathSegment require(!isDot(canonicalPathSegment) && !isDotDot(canonicalPathSegment)) { "unexpected path segment: $encodedPathSegment" } } - fun HttpUrl.Builder.commonRemovePathSegment(index: Int) = apply { - encodedPathSegments.removeAt(index) - if (encodedPathSegments.isEmpty()) { - encodedPathSegments.add("") // Always leave at least one '/'. + fun HttpUrl.Builder.commonRemovePathSegment(index: Int) = + apply { + encodedPathSegments.removeAt(index) + if (encodedPathSegments.isEmpty()) { + encodedPathSegments.add("") // Always leave at least one '/'. + } } - } - fun HttpUrl.Builder.commonEncodedPath(encodedPath: String) = apply { - require(encodedPath.startsWith("/")) { "unexpected encodedPath: $encodedPath" } - resolvePath(encodedPath, 0, encodedPath.length) - } + fun HttpUrl.Builder.commonEncodedPath(encodedPath: String) = + apply { + require(encodedPath.startsWith("/")) { "unexpected encodedPath: $encodedPath" } + resolvePath(encodedPath, 0, encodedPath.length) + } - fun HttpUrl.Builder.commonQuery(query: String?) = apply { - this.encodedQueryNamesAndValues = query?.canonicalize( - encodeSet = QUERY_ENCODE_SET, - plusIsSpace = true - )?.toQueryNamesAndValues() - } + fun HttpUrl.Builder.commonQuery(query: String?) = + apply { + this.encodedQueryNamesAndValues = + query?.canonicalize( + encodeSet = QUERY_ENCODE_SET, + plusIsSpace = true, + )?.toQueryNamesAndValues() + } - fun HttpUrl.Builder.commonEncodedQuery(encodedQuery: String?) = apply { - this.encodedQueryNamesAndValues = encodedQuery?.canonicalize( - encodeSet = QUERY_ENCODE_SET, - alreadyEncoded = true, - plusIsSpace = true - )?.toQueryNamesAndValues() - } + fun HttpUrl.Builder.commonEncodedQuery(encodedQuery: String?) = + apply { + this.encodedQueryNamesAndValues = + encodedQuery?.canonicalize( + encodeSet = QUERY_ENCODE_SET, + alreadyEncoded = true, + plusIsSpace = true, + )?.toQueryNamesAndValues() + } /** Encodes the query parameter using UTF-8 and adds it to this URL's query string. */ - fun HttpUrl.Builder.commonAddQueryParameter(name: String, value: String?) = apply { + fun HttpUrl.Builder.commonAddQueryParameter( + name: String, + value: String?, + ) = apply { if (encodedQueryNamesAndValues == null) encodedQueryNamesAndValues = mutableListOf() - encodedQueryNamesAndValues!!.add(name.canonicalize( - encodeSet = QUERY_COMPONENT_ENCODE_SET, - plusIsSpace = true - )) - encodedQueryNamesAndValues!!.add(value?.canonicalize( - encodeSet = QUERY_COMPONENT_ENCODE_SET, - plusIsSpace = true - )) + encodedQueryNamesAndValues!!.add( + name.canonicalize( + encodeSet = QUERY_COMPONENT_ENCODE_SET, + plusIsSpace = true, + ), + ) + encodedQueryNamesAndValues!!.add( + value?.canonicalize( + encodeSet = QUERY_COMPONENT_ENCODE_SET, + plusIsSpace = true, + ), + ) } /** Adds the pre-encoded query parameter to this URL's query string. */ - fun HttpUrl.Builder.commonAddEncodedQueryParameter(encodedName: String, encodedValue: String?) = apply { + fun HttpUrl.Builder.commonAddEncodedQueryParameter( + encodedName: String, + encodedValue: String?, + ) = apply { if (encodedQueryNamesAndValues == null) encodedQueryNamesAndValues = mutableListOf() - encodedQueryNamesAndValues!!.add(encodedName.canonicalize( - encodeSet = QUERY_COMPONENT_REENCODE_SET, - alreadyEncoded = true, - plusIsSpace = true - )) - encodedQueryNamesAndValues!!.add(encodedValue?.canonicalize( - encodeSet = QUERY_COMPONENT_REENCODE_SET, - alreadyEncoded = true, - plusIsSpace = true - )) - } - - fun HttpUrl.Builder.commonSetQueryParameter(name: String, value: String?) = apply { + encodedQueryNamesAndValues!!.add( + encodedName.canonicalize( + encodeSet = QUERY_COMPONENT_REENCODE_SET, + alreadyEncoded = true, + plusIsSpace = true, + ), + ) + encodedQueryNamesAndValues!!.add( + encodedValue?.canonicalize( + encodeSet = QUERY_COMPONENT_REENCODE_SET, + alreadyEncoded = true, + plusIsSpace = true, + ), + ) + } + + fun HttpUrl.Builder.commonSetQueryParameter( + name: String, + value: String?, + ) = apply { removeAllQueryParameters(name) addQueryParameter(name, value) } - fun HttpUrl.Builder.commonSetEncodedQueryParameter(encodedName: String, encodedValue: String?) = apply { + fun HttpUrl.Builder.commonSetEncodedQueryParameter( + encodedName: String, + encodedValue: String?, + ) = apply { removeAllEncodedQueryParameters(encodedName) addEncodedQueryParameter(encodedName, encodedValue) } - fun HttpUrl.Builder.commonRemoveAllQueryParameters(name: String) = apply { - if (encodedQueryNamesAndValues == null) return this - val nameToRemove = name.canonicalize( - encodeSet = QUERY_COMPONENT_ENCODE_SET, - plusIsSpace = true - ) - commonRemoveAllCanonicalQueryParameters(nameToRemove) - } - - fun HttpUrl.Builder.commonRemoveAllEncodedQueryParameters(encodedName: String) = apply { - if (encodedQueryNamesAndValues == null) return this - commonRemoveAllCanonicalQueryParameters(encodedName.canonicalize( - encodeSet = QUERY_COMPONENT_REENCODE_SET, - alreadyEncoded = true, - plusIsSpace = true - )) - } + fun HttpUrl.Builder.commonRemoveAllQueryParameters(name: String) = + apply { + if (encodedQueryNamesAndValues == null) return this + val nameToRemove = + name.canonicalize( + encodeSet = QUERY_COMPONENT_ENCODE_SET, + plusIsSpace = true, + ) + commonRemoveAllCanonicalQueryParameters(nameToRemove) + } + + fun HttpUrl.Builder.commonRemoveAllEncodedQueryParameters(encodedName: String) = + apply { + if (encodedQueryNamesAndValues == null) return this + commonRemoveAllCanonicalQueryParameters( + encodedName.canonicalize( + encodeSet = QUERY_COMPONENT_REENCODE_SET, + alreadyEncoded = true, + plusIsSpace = true, + ), + ) + } fun HttpUrl.Builder.commonRemoveAllCanonicalQueryParameters(canonicalName: String) { for (i in encodedQueryNamesAndValues!!.size - 2 downTo 0 step 2) { @@ -434,21 +488,24 @@ internal object CommonHttpUrl { } } - fun HttpUrl.Builder.commonFragment(fragment: String?) = apply { - this.encodedFragment = fragment?.canonicalize( - encodeSet = FRAGMENT_ENCODE_SET, - unicodeAllowed = true - ) - } - - fun HttpUrl.Builder.commonEncodedFragment(encodedFragment: String?) = apply { - this.encodedFragment = encodedFragment?.canonicalize( - encodeSet = FRAGMENT_ENCODE_SET, - alreadyEncoded = true, - unicodeAllowed = true - ) - } + fun HttpUrl.Builder.commonFragment(fragment: String?) = + apply { + this.encodedFragment = + fragment?.canonicalize( + encodeSet = FRAGMENT_ENCODE_SET, + unicodeAllowed = true, + ) + } + fun HttpUrl.Builder.commonEncodedFragment(encodedFragment: String?) = + apply { + this.encodedFragment = + encodedFragment?.canonicalize( + encodeSet = FRAGMENT_ENCODE_SET, + alreadyEncoded = true, + unicodeAllowed = true, + ) + } /** Adds a path segment. If the input is ".." or equivalent, this pops a path segment. */ internal fun HttpUrl.Builder.push( @@ -456,14 +513,15 @@ internal object CommonHttpUrl { pos: Int, limit: Int, addTrailingSlash: Boolean, - alreadyEncoded: Boolean + alreadyEncoded: Boolean, ) { - val segment = input.canonicalize( - pos = pos, - limit = limit, - encodeSet = PATH_SEGMENT_ENCODE_SET, - alreadyEncoded = alreadyEncoded - ) + val segment = + input.canonicalize( + pos = pos, + limit = limit, + encodeSet = PATH_SEGMENT_ENCODE_SET, + alreadyEncoded = alreadyEncoded, + ) if (isDot(segment)) { return // Skip '.' path segments. } @@ -513,7 +571,11 @@ internal object CommonHttpUrl { } } - internal fun HttpUrl.Builder.resolvePath(input: String, startPos: Int, limit: Int) { + internal fun HttpUrl.Builder.resolvePath( + input: String, + startPos: Int, + limit: Int, + ) { var pos = startPos // Read a delimiter. if (pos == limit) { @@ -578,13 +640,14 @@ internal object CommonHttpUrl { pathSegments = encodedPathSegments.map { it.percentDecode() }, queryNamesAndValues = encodedQueryNamesAndValues?.map { it?.percentDecode(plusIsSpace = true) }, fragment = encodedFragment?.percentDecode(), - url = toString() + url = toString(), ) } internal fun HttpUrl.Builder.effectivePort(): Int { return if (port != -1) port else HttpUrl.defaultPort(scheme!!) } + internal fun HttpUrl.Builder.commonToString(): String { return buildString { if (scheme != null) { @@ -644,7 +707,10 @@ internal object CommonHttpUrl { } } - internal fun HttpUrl.Builder.commonParse(base: HttpUrl?, input: String): HttpUrl.Builder { + internal fun HttpUrl.Builder.commonParse( + base: HttpUrl?, + input: String, + ): HttpUrl.Builder { var pos = input.indexOfFirstNonAsciiWhitespace() val limit = input.indexOfLastNonAsciiWhitespace(pos) @@ -660,15 +726,18 @@ internal object CommonHttpUrl { this.scheme = "http" pos += "http:".length } - else -> throw IllegalArgumentException("Expected URL scheme 'http' or 'https' but was '" + - input.substring(0, schemeDelimiterOffset) + "'") + else -> throw IllegalArgumentException( + "Expected URL scheme 'http' or 'https' but was '" + + input.substring(0, schemeDelimiterOffset) + "'", + ) } } else if (base != null) { this.scheme = base.scheme } else { val truncated = if (input.length > 6) input.take(6) + "..." else input throw IllegalArgumentException( - "Expected URL scheme 'http' or 'https' but no scheme was found for $truncated") + "Expected URL scheme 'http' or 'https' but no scheme was found for $truncated", + ) } // Authority. @@ -688,44 +757,49 @@ internal object CommonHttpUrl { pos += slashCount authority@ while (true) { val componentDelimiterOffset = input.delimiterOffset("@/\\?#", pos, limit) - val c = if (componentDelimiterOffset != limit) { - input[componentDelimiterOffset].code - } else { - -1 - } + val c = + if (componentDelimiterOffset != limit) { + input[componentDelimiterOffset].code + } else { + -1 + } when (c) { '@'.code -> { // User info precedes. if (!hasPassword) { val passwordColonOffset = input.delimiterOffset(':', pos, componentDelimiterOffset) - val canonicalUsername = input.canonicalize( - pos = pos, - limit = passwordColonOffset, - encodeSet = USERNAME_ENCODE_SET, - alreadyEncoded = true - ) - this.encodedUsername = if (hasUsername) { - this.encodedUsername + "%40" + canonicalUsername - } else { - canonicalUsername - } + val canonicalUsername = + input.canonicalize( + pos = pos, + limit = passwordColonOffset, + encodeSet = USERNAME_ENCODE_SET, + alreadyEncoded = true, + ) + this.encodedUsername = + if (hasUsername) { + this.encodedUsername + "%40" + canonicalUsername + } else { + canonicalUsername + } if (passwordColonOffset != componentDelimiterOffset) { hasPassword = true - this.encodedPassword = input.canonicalize( - pos = passwordColonOffset + 1, - limit = componentDelimiterOffset, - encodeSet = PASSWORD_ENCODE_SET, - alreadyEncoded = true - ) + this.encodedPassword = + input.canonicalize( + pos = passwordColonOffset + 1, + limit = componentDelimiterOffset, + encodeSet = PASSWORD_ENCODE_SET, + alreadyEncoded = true, + ) } hasUsername = true } else { - this.encodedPassword = this.encodedPassword + "%40" + input.canonicalize( - pos = pos, - limit = componentDelimiterOffset, - encodeSet = PASSWORD_ENCODE_SET, - alreadyEncoded = true - ) + this.encodedPassword = this.encodedPassword + "%40" + + input.canonicalize( + pos = pos, + limit = componentDelimiterOffset, + encodeSet = PASSWORD_ENCODE_SET, + alreadyEncoded = true, + ) } pos = componentDelimiterOffset + 1 } @@ -737,8 +811,10 @@ internal object CommonHttpUrl { host = input.percentDecode(pos = pos, limit = portColonOffset).toCanonicalHost() port = parsePort(input, portColonOffset + 1, componentDelimiterOffset) require(port != -1) { - "Invalid URL port: \"${input.substring(portColonOffset + 1, - componentDelimiterOffset)}\"" + "Invalid URL port: \"${input.substring( + portColonOffset + 1, + componentDelimiterOffset, + )}\"" } } else { host = input.percentDecode(pos = pos, limit = portColonOffset).toCanonicalHost() @@ -773,36 +849,43 @@ internal object CommonHttpUrl { // Query. if (pos < limit && input[pos] == '?') { val queryDelimiterOffset = input.delimiterOffset('#', pos, limit) - this.encodedQueryNamesAndValues = input.canonicalize( - pos = pos + 1, - limit = queryDelimiterOffset, - encodeSet = QUERY_ENCODE_SET, - alreadyEncoded = true, - plusIsSpace = true - ).toQueryNamesAndValues() + this.encodedQueryNamesAndValues = + input.canonicalize( + pos = pos + 1, + limit = queryDelimiterOffset, + encodeSet = QUERY_ENCODE_SET, + alreadyEncoded = true, + plusIsSpace = true, + ).toQueryNamesAndValues() pos = queryDelimiterOffset } // Fragment. if (pos < limit && input[pos] == '#') { - this.encodedFragment = input.canonicalize( - pos = pos + 1, - limit = limit, - encodeSet = FRAGMENT_ENCODE_SET, - alreadyEncoded = true, - unicodeAllowed = true - ) + this.encodedFragment = + input.canonicalize( + pos = pos + 1, + limit = limit, + encodeSet = FRAGMENT_ENCODE_SET, + alreadyEncoded = true, + unicodeAllowed = true, + ) } return this } + internal const val INVALID_HOST = "Invalid URL host" /** * Returns the index of the ':' in `input` that is after scheme characters. Returns -1 if * `input` does not have a scheme that starts at `pos`. */ - internal fun schemeDelimiterOffset(input: String, pos: Int, limit: Int): Int { + internal fun schemeDelimiterOffset( + input: String, + pos: Int, + limit: Int, + ): Int { if (limit - pos < 2) return -1 val c0 = input[pos] @@ -825,7 +908,10 @@ internal object CommonHttpUrl { } /** Returns the number of '/' and '\' slashes in this, starting at `pos`. */ - internal fun String.slashCount(pos: Int, limit: Int): Int { + internal fun String.slashCount( + pos: Int, + limit: Int, + ): Int { var slashCount = 0 for (i in pos until limit) { val c = this[i] @@ -839,7 +925,11 @@ internal object CommonHttpUrl { } /** Finds the first ':' in `input`, skipping characters between square braces "[...]". */ - internal fun portColonOffset(input: String, pos: Int, limit: Int): Int { + internal fun portColonOffset( + input: String, + pos: Int, + limit: Int, + ): Int { var i = pos while (i < limit) { when (input[i]) { @@ -855,7 +945,11 @@ internal object CommonHttpUrl { return limit // No colon. } - internal fun parsePort(input: String, pos: Int, limit: Int): Int { + internal fun parsePort( + input: String, + pos: Int, + limit: Int, + ): Int { return try { // Canonicalize the port string to skip '\n' etc. val portString = input.canonicalize(pos = pos, limit = limit, encodeSet = "") @@ -866,14 +960,17 @@ internal object CommonHttpUrl { } } - internal fun String.isPercentEncoded(pos: Int, limit: Int): Boolean { + internal fun String.isPercentEncoded( + pos: Int, + limit: Int, + ): Boolean { return pos + 2 < limit && this[pos] == '%' && this[pos + 1].parseHexDigit() != -1 && this[pos + 2].parseHexDigit() != -1 } - internal fun String.commonToHttpUrl(): HttpUrl = HttpUrl.Builder().parse(null, this).build() + internal fun String.commonToHttpUrl(): HttpUrl = HttpUrl.Builder().parse(null, this).build() internal fun String.commonToHttpUrlOrNull(): HttpUrl? { return try { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-HttpUrlJvm.kt b/okhttp/src/main/kotlin/okhttp3/internal/-HttpUrlJvm.kt index 285c448679df..640fce4fb877 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-HttpUrlJvm.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-HttpUrlJvm.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import java.nio.charset.Charset @@ -24,7 +25,6 @@ import okhttp3.internal.JvmHttpUrl.canonicalizeWithCharset import okio.Buffer internal object JvmHttpUrl { - internal fun Buffer.writeCanonicalized( input: String, pos: Int, @@ -34,15 +34,18 @@ internal object JvmHttpUrl { strict: Boolean, plusIsSpace: Boolean, unicodeAllowed: Boolean, - charset: Charset? + charset: Charset?, ) { var encodedCharBuffer: Buffer? = null // Lazily allocated. var codePoint: Int var i = pos while (i < limit) { codePoint = input.codePointAt(i) - if (alreadyEncoded && (codePoint == '\t'.code || codePoint == '\n'.code || - codePoint == '\u000c'.code || codePoint == '\r'.code)) { + if (alreadyEncoded && ( + codePoint == '\t'.code || codePoint == '\n'.code || + codePoint == '\u000c'.code || codePoint == '\r'.code + ) + ) { // Skip this character. } else if (codePoint == ' '.code && encodeSet === FORM_ENCODE_SET) { // Encode ' ' as '+'. @@ -55,7 +58,8 @@ internal object JvmHttpUrl { codePoint >= 0x80 && !unicodeAllowed || codePoint.toChar() in encodeSet || codePoint == '%'.code && - (!alreadyEncoded || strict && !input.isPercentEncoded(i, limit))) { + (!alreadyEncoded || strict && !input.isPercentEncoded(i, limit)) + ) { // Percent encode this character. if (encodedCharBuffer == null) { encodedCharBuffer = Buffer() @@ -109,7 +113,7 @@ internal object JvmHttpUrl { strict: Boolean = false, plusIsSpace: Boolean = false, unicodeAllowed: Boolean = false, - charset: Charset? = null + charset: Charset? = null, ): String { var codePoint: Int var i = pos @@ -121,7 +125,8 @@ internal object JvmHttpUrl { codePoint.toChar() in encodeSet || codePoint == '%'.code && (!alreadyEncoded || strict && !isPercentEncoded(i, limit)) || - codePoint == '+'.code && plusIsSpace) { + codePoint == '+'.code && plusIsSpace + ) { // Slow path: the character at i requires encoding! val out = Buffer() out.writeUtf8(this, pos, i) @@ -134,7 +139,7 @@ internal object JvmHttpUrl { strict = strict, plusIsSpace = plusIsSpace, unicodeAllowed = unicodeAllowed, - charset = charset + charset = charset, ) return out.readUtf8() } @@ -151,7 +156,7 @@ internal object HttpUrlCommon { encoded: String, pos: Int, limit: Int, - plusIsSpace: Boolean + plusIsSpace: Boolean, ) { var codePoint: Int var i = pos @@ -175,6 +180,7 @@ internal object HttpUrlCommon { i += Character.charCount(codePoint) } } + internal fun String.canonicalize( pos: Int = 0, limit: Int = length, @@ -191,7 +197,7 @@ internal object HttpUrlCommon { alreadyEncoded = alreadyEncoded, strict = strict, plusIsSpace = plusIsSpace, - unicodeAllowed = unicodeAllowed + unicodeAllowed = unicodeAllowed, ) } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-MediaTypeCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-MediaTypeCommon.kt index 26bfa772c423..03fdb0f958a5 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-MediaTypeCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-MediaTypeCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import okhttp3.MediaType @@ -44,8 +45,9 @@ private val PARAMETER = Regex(";\\s*(?:$TOKEN=(?:$TOKEN|$QUOTED))?") * @throws IllegalArgumentException if this is not a well-formed media type. */ internal fun String.commonToMediaType(): MediaType { - val typeSubtype: MatchResult = TYPE_SUBTYPE.matchAtPolyfill(this, 0) - ?: throw IllegalArgumentException("No subtype found for: \"$this\"") + val typeSubtype: MatchResult = + TYPE_SUBTYPE.matchAtPolyfill(this, 0) + ?: throw IllegalArgumentException("No subtype found for: \"$this\"") val type = typeSubtype.groupValues[1].lowercase() val subtype = typeSubtype.groupValues[2].lowercase() @@ -64,17 +66,18 @@ internal fun String.commonToMediaType(): MediaType { } val token = parameter.groups[2]?.value - val value = when { - token == null -> { - // Value is "double-quoted". That's valid and our regex group already strips the quotes. - parameter.groups[3]!!.value - } - token.startsWith("'") && token.endsWith("'") && token.length > 2 -> { - // If the token is 'single-quoted' it's invalid! But we're lenient and strip the quotes. - token.substring(1, token.length - 1) + val value = + when { + token == null -> { + // Value is "double-quoted". That's valid and our regex group already strips the quotes. + parameter.groups[3]!!.value + } + token.startsWith("'") && token.endsWith("'") && token.length > 2 -> { + // If the token is 'single-quoted' it's invalid! But we're lenient and strip the quotes. + token.substring(1, token.length - 1) + } + else -> token } - else -> token - } parameterNamesAndValues += name parameterNamesAndValues += value diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-NormalizeJvm.kt b/okhttp/src/main/kotlin/okhttp3/internal/-NormalizeJvm.kt index ee73bef04566..360a7982dab1 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-NormalizeJvm.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-NormalizeJvm.kt @@ -14,10 +14,10 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import java.text.Normalizer import java.text.Normalizer.Form.NFC -internal fun normalizeNfc(string: String): String = - Normalizer.normalize(string, NFC) +internal fun normalizeNfc(string: String): String = Normalizer.normalize(string, NFC) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-RequestBodyCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-RequestBodyCommon.kt index 432e76b99ea2..c003f1f05d70 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-RequestBodyCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-RequestBodyCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import okhttp3.MediaType @@ -24,7 +25,7 @@ import okio.ByteString fun ByteArray.commonToRequestBody( contentType: MediaType?, offset: Int, - byteCount: Int + byteCount: Int, ): RequestBody { checkOffsetAndCount(size.toLong(), offset.toLong(), byteCount.toLong()) return object : RequestBody() { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-RequestCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-RequestCommon.kt index ce3bcb111880..0cbe9a09fe36 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-RequestCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-RequestCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import kotlin.reflect.KClass @@ -51,22 +52,29 @@ internal fun canonicalUrl(url: String): String { } } - -fun Request.Builder.commonHeader(name: String, value: String) = apply { +fun Request.Builder.commonHeader( + name: String, + value: String, +) = apply { headers[name] = value } -fun Request.Builder.commonAddHeader(name: String, value: String) = apply { +fun Request.Builder.commonAddHeader( + name: String, + value: String, +) = apply { headers.add(name, value) } -fun Request.Builder.commonRemoveHeader(name: String) = apply { - headers.removeAll(name) -} +fun Request.Builder.commonRemoveHeader(name: String) = + apply { + headers.removeAll(name) + } -fun Request.Builder.commonHeaders(headers: Headers) = apply { - this.headers = headers.newBuilder() -} +fun Request.Builder.commonHeaders(headers: Headers) = + apply { + this.headers = headers.newBuilder() + } fun Request.Builder.commonCacheControl(cacheControl: CacheControl): Request.Builder { val value = cacheControl.toString() @@ -88,57 +96,66 @@ fun Request.Builder.commonPut(body: RequestBody): Request.Builder = method("PUT" fun Request.Builder.commonPatch(body: RequestBody): Request.Builder = method("PATCH", body) -fun Request.Builder.commonMethod(method: String, body: RequestBody?): Request.Builder = apply { - require(method.isNotEmpty()) { - "method.isEmpty() == true" - } - if (body == null) { - require(!HttpMethod.requiresRequestBody(method)) { - "method $method must have a request body." +fun Request.Builder.commonMethod( + method: String, + body: RequestBody?, +): Request.Builder = + apply { + require(method.isNotEmpty()) { + "method.isEmpty() == true" } - } else { - require(HttpMethod.permitsRequestBody(method)) { - "method $method must not have a request body." + if (body == null) { + require(!HttpMethod.requiresRequestBody(method)) { + "method $method must have a request body." + } + } else { + require(HttpMethod.permitsRequestBody(method)) { + "method $method must not have a request body." + } } + this.method = method + this.body = body } - this.method = method - this.body = body -} -fun Request.Builder.commonTag(type: KClass, tag: T?) = apply { +fun Request.Builder.commonTag( + type: KClass, + tag: T?, +) = apply { if (tag == null) { if (tags.isNotEmpty()) { (tags as MutableMap).remove(type) } } else { - val mutableTags: MutableMap, Any> = when { - tags.isEmpty() -> mutableMapOf, Any>().also { tags = it } - else -> tags as MutableMap, Any> - } + val mutableTags: MutableMap, Any> = + when { + tags.isEmpty() -> mutableMapOf, Any>().also { tags = it } + else -> tags as MutableMap, Any> + } mutableTags[type] = tag } } -fun Request.commonToString(): String = buildString { - append("Request{method=") - append(method) - append(", url=") - append(url) - if (headers.size != 0) { - append(", headers=[") - headers.forEachIndexed { index, (name, value) -> - if (index > 0) { - append(", ") +fun Request.commonToString(): String = + buildString { + append("Request{method=") + append(method) + append(", url=") + append(url) + if (headers.size != 0) { + append(", headers=[") + headers.forEachIndexed { index, (name, value) -> + if (index > 0) { + append(", ") + } + append(name) + append(':') + append(if (isSensitiveHeader(name)) "██" else value) } - append(name) - append(':') - append(if (isSensitiveHeader(name)) "██" else value) + append(']') } - append(']') - } - if (tags.isNotEmpty()) { - append(", tags=") - append(tags) + if (tags.isNotEmpty()) { + append(", tags=") + append(tags) + } + append('}') } - append('}') -} diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-ResponseBodyCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-ResponseBodyCommon.kt index e2a951f4db75..924e64bcda36 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-ResponseBodyCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-ResponseBodyCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import okhttp3.MediaType @@ -31,7 +32,7 @@ internal fun ResponseBody.commonByteString() = commonConsumeSource(BufferedSourc internal inline fun ResponseBody.commonConsumeSource( consumer: (BufferedSource) -> T, - sizeMapper: (T) -> Int + sizeMapper: (T) -> Int, ): T { val contentLength = contentLength() if (contentLength > Int.MAX_VALUE) { @@ -62,11 +63,12 @@ internal fun ByteString.commonToResponseBody(contentType: MediaType?): ResponseB internal fun BufferedSource.commonAsResponseBody( contentType: MediaType?, - contentLength: Long -): ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? = contentType + contentLength: Long, +): ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? = contentType - override fun contentLength(): Long = contentLength + override fun contentLength(): Long = contentLength - override fun source(): BufferedSource = this@commonAsResponseBody -} + override fun source(): BufferedSource = this@commonAsResponseBody + } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt index 62dd823aa18c..4f68f6403dd6 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import kotlin.jvm.JvmOverloads @@ -40,13 +41,19 @@ import okio.buffer internal class UnreadableResponseBody( private val mediaType: MediaType?, private val contentLength: Long, -): ResponseBody(), Source { +) : ResponseBody(), Source { override fun contentType() = mediaType + override fun contentLength() = contentLength + override fun source() = buffer() - override fun read(sink: Buffer, byteCount: Long): Long { - throw IllegalStateException(""" + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { + throw IllegalStateException( + """ |Unreadable ResponseBody! These Response objects have bodies that are stripped: | * Response.cacheResponse | * Response.networkResponse @@ -54,7 +61,7 @@ internal class UnreadableResponseBody( | * EventSourceListener | * WebSocketListener |(It is safe to call contentType() and contentLength() on these response bodies.) - """.trimMargin() + """.trimMargin(), ) } @@ -76,7 +83,10 @@ val Response.commonIsSuccessful: Boolean fun Response.commonHeaders(name: String): List = headers.values(name) @JvmOverloads -fun Response.commonHeader(name: String, defaultValue: String?): String? = headers[name] ?: defaultValue +fun Response.commonHeader( + name: String, + defaultValue: String?, +): String? = headers[name] ?: defaultValue @Throws(IOException::class) fun Response.commonPeekBody(byteCount: Long): ResponseBody { @@ -90,10 +100,11 @@ fun Response.commonPeekBody(byteCount: Long): ResponseBody { fun Response.commonNewBuilder(): Response.Builder = Response.Builder(this) val Response.commonIsRedirect: Boolean - get() = when (code) { - HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> true - else -> false - } + get() = + when (code) { + HTTP_PERM_REDIRECT, HTTP_TEMP_REDIRECT, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER -> true + else -> false + } val Response.commonCacheControl: CacheControl get() { @@ -109,60 +120,78 @@ fun Response.commonClose() { body.close() } -fun Response.commonToString(): String = - "Response{protocol=$protocol, code=$code, message=$message, url=${request.url}}" +fun Response.commonToString(): String = "Response{protocol=$protocol, code=$code, message=$message, url=${request.url}}" -fun Response.Builder.commonRequest(request: Request) = apply { - this.request = request -} +fun Response.Builder.commonRequest(request: Request) = + apply { + this.request = request + } -fun Response.Builder.commonProtocol(protocol: Protocol) = apply { - this.protocol = protocol -} +fun Response.Builder.commonProtocol(protocol: Protocol) = + apply { + this.protocol = protocol + } -fun Response.Builder.commonCode(code: Int) = apply { - this.code = code -} +fun Response.Builder.commonCode(code: Int) = + apply { + this.code = code + } -fun Response.Builder.commonMessage(message: String) = apply { - this.message = message -} +fun Response.Builder.commonMessage(message: String) = + apply { + this.message = message + } -fun Response.Builder.commonHeader(name: String, value: String) = apply { +fun Response.Builder.commonHeader( + name: String, + value: String, +) = apply { headers[name] = value } -fun Response.Builder.commonAddHeader(name: String, value: String) = apply { +fun Response.Builder.commonAddHeader( + name: String, + value: String, +) = apply { headers.add(name, value) } -fun Response.Builder.commonRemoveHeader(name: String) = apply { - headers.removeAll(name) -} +fun Response.Builder.commonRemoveHeader(name: String) = + apply { + headers.removeAll(name) + } -fun Response.Builder.commonHeaders(headers: Headers) = apply { - this.headers = headers.newBuilder() -} +fun Response.Builder.commonHeaders(headers: Headers) = + apply { + this.headers = headers.newBuilder() + } -fun Response.Builder.commonTrailers(trailersFn: (() -> Headers)) = apply { - this.trailersFn = trailersFn -} +fun Response.Builder.commonTrailers(trailersFn: (() -> Headers)) = + apply { + this.trailersFn = trailersFn + } -fun Response.Builder.commonBody(body: ResponseBody) = apply { - this.body = body -} +fun Response.Builder.commonBody(body: ResponseBody) = + apply { + this.body = body + } -fun Response.Builder.commonNetworkResponse(networkResponse: Response?) = apply { - checkSupportResponse("networkResponse", networkResponse) - this.networkResponse = networkResponse -} +fun Response.Builder.commonNetworkResponse(networkResponse: Response?) = + apply { + checkSupportResponse("networkResponse", networkResponse) + this.networkResponse = networkResponse + } -fun Response.Builder.commonCacheResponse(cacheResponse: Response?) = apply { - checkSupportResponse("cacheResponse", cacheResponse) - this.cacheResponse = cacheResponse -} +fun Response.Builder.commonCacheResponse(cacheResponse: Response?) = + apply { + checkSupportResponse("cacheResponse", cacheResponse) + this.cacheResponse = cacheResponse + } -private fun checkSupportResponse(name: String, response: Response?) { +private fun checkSupportResponse( + name: String, + response: Response?, +) { response?.apply { require(networkResponse == null) { "$name.networkResponse != null" } require(cacheResponse == null) { "$name.cacheResponse != null" } @@ -170,6 +199,7 @@ private fun checkSupportResponse(name: String, response: Response?) { } } -fun Response.Builder.commonPriorResponse(priorResponse: Response?) = apply { - this.priorResponse = priorResponse -} +fun Response.Builder.commonPriorResponse(priorResponse: Response?) = + apply { + this.priorResponse = priorResponse + } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt index 18f701887403..3db8d43a9c2a 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import okhttp3.Headers @@ -35,7 +36,10 @@ import okio.Path import okio.use // TODO: migrate callers to [Regex.matchAt] when that API is not experimental. -internal fun Regex.matchAtPolyfill(input: CharSequence, index: Int): MatchResult? { +internal fun Regex.matchAtPolyfill( + input: CharSequence, + index: Int, +): MatchResult? { val candidate = find(input, index) ?: return null if (candidate.range.first != index) return null // Didn't match where it should have. return candidate @@ -45,22 +49,19 @@ internal fun Regex.matchAtPolyfill(input: CharSequence, index: Int): MatchResult val EMPTY_BYTE_ARRAY: ByteArray = ByteArray(0) /** Byte order marks. */ -internal val UNICODE_BOMS = Options.of( - // UTF-8. - "efbbbf".decodeHex(), - - // UTF-16BE. - "feff".decodeHex(), - - // UTF-16LE. - "fffe".decodeHex(), - - // UTF-32BE. - "0000ffff".decodeHex(), - - // UTF-32LE. - "ffff0000".decodeHex(), -) +internal val UNICODE_BOMS = + Options.of( + // UTF-8. + "efbbbf".decodeHex(), + // UTF-16BE. + "feff".decodeHex(), + // UTF-16LE. + "fffe".decodeHex(), + // UTF-32BE. + "0000ffff".decodeHex(), + // UTF-32LE. + "ffff0000".decodeHex(), + ) /** * Returns an array containing only elements found in this array and also in [other]. The returned @@ -68,7 +69,7 @@ internal val UNICODE_BOMS = Options.of( */ internal fun Array.intersect( other: Array, - comparator: Comparator + comparator: Comparator, ): Array { val result = mutableListOf() for (a in this) { @@ -90,7 +91,7 @@ internal fun Array.intersect( */ internal fun Array.hasIntersection( other: Array?, - comparator: Comparator + comparator: Comparator, ): Boolean { if (isEmpty() || other == null || other.isEmpty()) { return false @@ -105,8 +106,10 @@ internal fun Array.hasIntersection( return false } -internal fun Array.indexOf(value: String, comparator: Comparator): Int = - indexOfFirst { comparator.compare(it, value) == 0 } +internal fun Array.indexOf( + value: String, + comparator: Comparator, +): Int = indexOfFirst { comparator.compare(it, value) == 0 } @Suppress("UNCHECKED_CAST") internal fun Array.concat(value: String): Array { @@ -118,7 +121,7 @@ internal fun Array.concat(value: String): Array { /** Increments [startIndex] until this string is not ASCII whitespace. Stops at [endIndex]. */ internal fun String.indexOfFirstNonAsciiWhitespace( startIndex: Int = 0, - endIndex: Int = length + endIndex: Int = length, ): Int { for (i in startIndex until endIndex) { when (this[i]) { @@ -134,7 +137,7 @@ internal fun String.indexOfFirstNonAsciiWhitespace( */ internal fun String.indexOfLastNonAsciiWhitespace( startIndex: Int = 0, - endIndex: Int = length + endIndex: Int = length, ): Int { for (i in endIndex - 1 downTo startIndex) { when (this[i]) { @@ -145,9 +148,11 @@ internal fun String.indexOfLastNonAsciiWhitespace( return startIndex } - /** Equivalent to `string.substring(startIndex, endIndex).trim()`. */ -fun String.trimSubstring(startIndex: Int = 0, endIndex: Int = length): String { +fun String.trimSubstring( + startIndex: Int = 0, + endIndex: Int = length, +): String { val start = indexOfFirstNonAsciiWhitespace(startIndex, endIndex) val end = indexOfLastNonAsciiWhitespace(start, endIndex) return substring(start, end) @@ -160,7 +165,7 @@ fun String.trimSubstring(startIndex: Int = 0, endIndex: Int = length): String { fun String.delimiterOffset( delimiters: String, startIndex: Int = 0, - endIndex: Int = length + endIndex: Int = length, ): Int { for (i in startIndex until endIndex) { if (this[i] in delimiters) return i @@ -175,7 +180,7 @@ fun String.delimiterOffset( fun String.delimiterOffset( delimiter: Char, startIndex: Int = 0, - endIndex: Int = length + endIndex: Int = length, ): Int { for (i in startIndex until endIndex) { if (this[i] == delimiter) return i @@ -205,15 +210,18 @@ internal fun isSensitiveHeader(name: String): Boolean { name.equals("Set-Cookie", ignoreCase = true) } -internal fun Char.parseHexDigit(): Int = when (this) { - in '0'..'9' -> this - '0' - in 'a'..'f' -> this - 'a' + 10 - in 'A'..'F' -> this - 'A' + 10 - else -> -1 -} +internal fun Char.parseHexDigit(): Int = + when (this) { + in '0'..'9' -> this - '0' + in 'a'..'f' -> this - 'a' + 10 + in 'A'..'F' -> this - 'A' + 10 + else -> -1 + } internal infix fun Byte.and(mask: Int): Int = toInt() and mask + internal infix fun Short.and(mask: Int): Int = toInt() and mask + internal infix fun Int.and(mask: Long): Long = toLong() and mask @Throws(IOException::class) @@ -225,9 +233,11 @@ internal fun BufferedSink.writeMedium(medium: Int) { @Throws(IOException::class) internal fun BufferedSource.readMedium(): Int { - return (readByte() and 0xff shl 16 - or (readByte() and 0xff shl 8) - or (readByte() and 0xff)) + return ( + readByte() and 0xff shl 16 + or (readByte() and 0xff shl 8) + or (readByte() and 0xff) + ) } /** Run [block] until it either throws an [IOException] or completes. */ @@ -331,11 +341,12 @@ internal fun FileSystem.deleteIfExists(path: Path) { /** Tolerant delete, try to clear as many files as possible even after a failure. */ internal fun FileSystem.deleteContents(directory: Path) { var exception: IOException? = null - val files = try { - list(directory) - } catch (fnfe: FileNotFoundException) { - return - } + val files = + try { + list(directory) + } catch (fnfe: FileNotFoundException) { + return + } for (file in files) { try { if (metadata(file).isDirectory) { @@ -358,9 +369,10 @@ internal fun MutableList.addIfAbsent(element: E) { if (!contains(element)) add(element) } -internal fun Exception.withSuppressed(suppressed: List): Throwable = apply { - for (e in suppressed) addSuppressed(e) -} +internal fun Exception.withSuppressed(suppressed: List): Throwable = + apply { + for (e in suppressed) addSuppressed(e) + } internal inline fun Iterable.filterList(predicate: T.() -> Boolean): List { var result: List = emptyList() @@ -375,7 +387,11 @@ internal inline fun Iterable.filterList(predicate: T.() -> Boolean): List internal const val USER_AGENT: String = "okhttp/${CONST_VERSION}" -internal fun checkOffsetAndCount(arrayLength: Long, offset: Long, count: Long) { +internal fun checkOffsetAndCount( + arrayLength: Long, + offset: Long, + count: Long, +) { if (offset or count < 0L || offset > arrayLength || arrayLength - offset < count) { throw ArrayIndexOutOfBoundsException("length=$arrayLength, offset=$offset, count=$offset") } @@ -385,7 +401,10 @@ val commonEmptyHeaders: Headers = Headers.headersOf() val commonEmptyRequestBody: RequestBody = EMPTY_BYTE_ARRAY.toRequestBody() val commonEmptyResponse: ResponseBody = EMPTY_BYTE_ARRAY.toResponseBody() -internal fun interleave(a: Iterable, b: Iterable): List { +internal fun interleave( + a: Iterable, + b: Iterable, +): List { val ia = a.iterator() val ib = b.iterator() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt b/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt index ee21dfe5d220..e903752cf032 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import java.io.IOException @@ -50,8 +51,10 @@ import okio.Source @JvmField internal val EMPTY_HEADERS: Headers = commonEmptyHeaders + @JvmField internal val EMPTY_REQUEST: RequestBody = commonEmptyRequestBody + @JvmField internal val EMPTY_RESPONSE: ResponseBody = commonEmptyResponse @@ -61,19 +64,21 @@ internal val UTC: TimeZone = TimeZone.getTimeZone("GMT")!! internal fun threadFactory( name: String, - daemon: Boolean -): ThreadFactory = ThreadFactory { runnable -> - Thread(runnable, name).apply { - isDaemon = daemon + daemon: Boolean, +): ThreadFactory = + ThreadFactory { runnable -> + Thread(runnable, name).apply { + isDaemon = daemon + } } -} internal fun HttpUrl.toHostHeader(includeDefaultPort: Boolean = false): String { - val host = if (":" in host) { - "[$host]" - } else { - host - } + val host = + if (":" in host) { + "[$host]" + } else { + host + } return if (includeDefaultPort || port != commonDefaultPort(scheme)) { "$host:$port" } else { @@ -82,7 +87,10 @@ internal fun HttpUrl.toHostHeader(includeDefaultPort: Boolean = false): String { } /** Returns a [Locale.US] formatted [String]. */ -internal fun format(format: String, vararg args: Any): String { +internal fun format( + format: String, + vararg args: Any, +): String { return String.format(Locale.US, format, *args) } @@ -99,7 +107,11 @@ internal fun BufferedSource.readBomAsCharset(default: Charset): Charset { } } -internal fun checkDuration(name: String, duration: Long, unit: TimeUnit): Int { +internal fun checkDuration( + name: String, + duration: Long, + unit: TimeUnit, +): Int { check(duration >= 0L) { "$name < 0" } val millis = unit.toMillis(duration) require(millis <= Integer.MAX_VALUE) { "$name too large" } @@ -107,7 +119,10 @@ internal fun checkDuration(name: String, duration: Long, unit: TimeUnit): Int { return millis.toInt() } -internal fun checkDuration(name: String, duration: Duration): Int { +internal fun checkDuration( + name: String, + duration: Duration, +): Int { check(!duration.isNegative()) { "$name < 0" } val millis = duration.inWholeMilliseconds require(millis <= Integer.MAX_VALUE) { "$name too large" } @@ -123,12 +138,14 @@ internal fun List
.toHeaders(): Headers { return builder.build() } -internal fun Headers.toHeaderList(): List
= (0 until size).map { - Header(name(it), value(it)) -} +internal fun Headers.toHeaderList(): List
= + (0 until size).map { + Header(name(it), value(it)) + } /** Returns true if an HTTP request for this URL and [other] can reuse a connection. */ -internal fun HttpUrl.canReuseConnectionFor(other: HttpUrl): Boolean = host == other.host && +internal fun HttpUrl.canReuseConnectionFor(other: HttpUrl): Boolean = + host == other.host && port == other.port && scheme == other.scheme @@ -139,13 +156,17 @@ internal fun EventListener.asFactory() = EventListener.Factory { this } * deadline if one exists already. */ @Throws(IOException::class) -internal fun Source.skipAll(duration: Int, timeUnit: TimeUnit): Boolean { +internal fun Source.skipAll( + duration: Int, + timeUnit: TimeUnit, +): Boolean { val nowNs = System.nanoTime() - val originalDurationNs = if (timeout().hasDeadline()) { - timeout().deadlineNanoTime() - nowNs - } else { - Long.MAX_VALUE - } + val originalDurationNs = + if (timeout().hasDeadline()) { + timeout().deadlineNanoTime() - nowNs + } else { + Long.MAX_VALUE + } timeout().deadlineNanoTime(nowNs + minOf(originalDurationNs, timeUnit.toNanos(duration.toLong()))) return try { val skipBuffer = Buffer() @@ -169,11 +190,15 @@ internal fun Source.skipAll(duration: Int, timeUnit: TimeUnit): Boolean { * source is helpful, such as when doing so completes a cache body or frees a socket connection for * reuse. */ -internal fun Source.discard(timeout: Int, timeUnit: TimeUnit): Boolean = try { - this.skipAll(timeout, timeUnit) -} catch (_: IOException) { - false -} +internal fun Source.discard( + timeout: Int, + timeUnit: TimeUnit, +): Boolean = + try { + this.skipAll(timeout, timeUnit) + } catch (_: IOException) { + false + } internal fun Socket.peerName(): String { val address = remoteSocketAddress @@ -205,7 +230,10 @@ internal fun Socket.isHealthy(source: BufferedSource): Boolean { } } -internal inline fun threadName(name: String, block: () -> Unit) { +internal inline fun threadName( + name: String, + block: () -> Unit, +) { val currentThread = Thread.currentThread() val oldName = currentThread.name currentThread.name = name @@ -272,7 +300,11 @@ internal inline fun Any.notify() = (this as Object).notify() @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "NOTHING_TO_INLINE") internal inline fun Any.notifyAll() = (this as Object).notifyAll() -internal fun readFieldOrNull(instance: Any, fieldType: Class, fieldName: String): T? { +internal fun readFieldOrNull( + instance: Any, + fieldType: Class, + fieldName: String, +): T? { var c: Class<*> = instance.javaClass while (c != Any::class.java) { try { @@ -307,7 +339,7 @@ internal val assertionsEnabled: Boolean = OkHttpClient::class.java.desiredAssert */ @JvmField internal val okHttpName: String = - OkHttpClient::class.java.name.removePrefix("okhttp3.").removeSuffix("Client") + OkHttpClient::class.java.name.removePrefix("okhttp3.").removeSuffix("Client") @Suppress("NOTHING_TO_INLINE") internal inline fun ReentrantLock.assertHeld() { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt b/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt index e253b636b22c..cdf6fb62cfcf 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt @@ -24,7 +24,11 @@ import okhttp3.internal.connection.RealConnection import okio.FileSystem import okio.Path -internal fun buildCache(file: Path, maxSize: Long, fileSystem: FileSystem): Cache { +internal fun buildCache( + file: Path, + maxSize: Long, + fileSystem: FileSystem, +): Cache { return Cache(file, maxSize, fileSystem) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt b/okhttp/src/main/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt index 244f05efaf8a..c139128d8c88 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt @@ -33,7 +33,10 @@ import okhttp3.Route */ class JavaNetAuthenticator(private val defaultDns: Dns = Dns.SYSTEM) : okhttp3.Authenticator { @Throws(IOException::class) - override fun authenticate(route: Route?, response: Response): Request? { + override fun authenticate( + route: Route?, + response: Response, + ): Request? { val challenges = response.challenges() val request = response.request val url = request.url @@ -46,9 +49,10 @@ class JavaNetAuthenticator(private val defaultDns: Dns = Dns.SYSTEM) : okhttp3.A } val dns = route?.address?.dns ?: defaultDns - val auth = if (proxyAuthorization) { - val proxyAddress = proxy.address() as InetSocketAddress - Authenticator.requestPasswordAuthentication( + val auth = + if (proxyAuthorization) { + val proxyAddress = proxy.address() as InetSocketAddress + Authenticator.requestPasswordAuthentication( proxyAddress.hostName, proxy.connectToInetAddress(url, dns), proxyAddress.port, @@ -56,10 +60,10 @@ class JavaNetAuthenticator(private val defaultDns: Dns = Dns.SYSTEM) : okhttp3.A challenge.realm, challenge.scheme, url.toUrl(), - Authenticator.RequestorType.PROXY - ) - } else { - Authenticator.requestPasswordAuthentication( + Authenticator.RequestorType.PROXY, + ) + } else { + Authenticator.requestPasswordAuthentication( url.host, proxy.connectToInetAddress(url, dns), url.port, @@ -67,17 +71,21 @@ class JavaNetAuthenticator(private val defaultDns: Dns = Dns.SYSTEM) : okhttp3.A challenge.realm, challenge.scheme, url.toUrl(), - Authenticator.RequestorType.SERVER - ) - } + Authenticator.RequestorType.SERVER, + ) + } if (auth != null) { val credentialHeader = if (proxyAuthorization) "Proxy-Authorization" else "Authorization" - val credential = Credentials.basic( - auth.userName, String(auth.password), challenge.charset) + val credential = + Credentials.basic( + auth.userName, + String(auth.password), + challenge.charset, + ) return request.newBuilder() - .header(credentialHeader, credential) - .build() + .header(credentialHeader, credential) + .build() } } @@ -85,7 +93,10 @@ class JavaNetAuthenticator(private val defaultDns: Dns = Dns.SYSTEM) : okhttp3.A } @Throws(IOException::class) - private fun Proxy.connectToInetAddress(url: HttpUrl, dns: Dns): InetAddress { + private fun Proxy.connectToInetAddress( + url: HttpUrl, + dns: Dns, + ): InetAddress { return when (type()) { Proxy.Type.DIRECT -> dns.lookup(url.host).first() else -> (address() as InetSocketAddress).address diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheInterceptor.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheInterceptor.kt index fb6bbd98a94f..e86c2470ba0c 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheInterceptor.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheInterceptor.kt @@ -41,7 +41,6 @@ import okio.buffer /** Serves requests from the cache and writes responses to the cache. */ class CacheInterceptor(internal val cache: Cache?) : Interceptor { - @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val call = chain.call() @@ -64,24 +63,24 @@ class CacheInterceptor(internal val cache: Cache?) : Interceptor { // If we're forbidden from using the network and the cache is insufficient, fail. if (networkRequest == null && cacheResponse == null) { return Response.Builder() - .request(chain.request()) - .protocol(Protocol.HTTP_1_1) - .code(HTTP_GATEWAY_TIMEOUT) - .message("Unsatisfiable Request (only-if-cached)") - .sentRequestAtMillis(-1L) - .receivedResponseAtMillis(System.currentTimeMillis()) - .build().also { - listener.satisfactionFailure(call, it) - } + .request(chain.request()) + .protocol(Protocol.HTTP_1_1) + .code(HTTP_GATEWAY_TIMEOUT) + .message("Unsatisfiable Request (only-if-cached)") + .sentRequestAtMillis(-1L) + .receivedResponseAtMillis(System.currentTimeMillis()) + .build().also { + listener.satisfactionFailure(call, it) + } } // If we don't need the network, we're done. if (networkRequest == null) { return cacheResponse!!.newBuilder() - .cacheResponse(cacheResponse.stripBody()) - .build().also { - listener.cacheHit(call, it) - } + .cacheResponse(cacheResponse.stripBody()) + .build().also { + listener.cacheHit(call, it) + } } if (cacheResponse != null) { @@ -103,7 +102,8 @@ class CacheInterceptor(internal val cache: Cache?) : Interceptor { // If we have a cache response too, then we're doing a conditional get. if (cacheResponse != null) { if (networkResponse?.code == HTTP_NOT_MODIFIED) { - val response = cacheResponse.newBuilder() + val response = + cacheResponse.newBuilder() .headers(combine(cacheResponse.headers, networkResponse.headers)) .sentRequestAtMillis(networkResponse.sentRequestAtMillis) .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis) @@ -125,7 +125,8 @@ class CacheInterceptor(internal val cache: Cache?) : Interceptor { } } - val response = networkResponse!!.newBuilder() + val response = + networkResponse!!.newBuilder() .cacheResponse(cacheResponse?.stripBody()) .networkResponse(networkResponse.stripBody()) .build() @@ -160,7 +161,10 @@ class CacheInterceptor(internal val cache: Cache?) : Interceptor { * may never exhaust the source stream and therefore not complete the cached response. */ @Throws(IOException::class) - private fun cacheWritingResponse(cacheRequest: CacheRequest?, response: Response): Response { + private fun cacheWritingResponse( + cacheRequest: CacheRequest?, + response: Response, + ): Response { // Some apps return a null body; for compatibility we treat that like a null cache request. if (cacheRequest == null) return response val cacheBodyUnbuffered = cacheRequest.body() @@ -168,58 +172,66 @@ class CacheInterceptor(internal val cache: Cache?) : Interceptor { val source = response.body.source() val cacheBody = cacheBodyUnbuffered.buffer() - val cacheWritingSource = object : Source { - private var cacheRequestClosed = false - - @Throws(IOException::class) - override fun read(sink: Buffer, byteCount: Long): Long { - val bytesRead: Long - try { - bytesRead = source.read(sink, byteCount) - } catch (e: IOException) { - if (!cacheRequestClosed) { - cacheRequestClosed = true - cacheRequest.abort() // Failed to write a complete cache response. + val cacheWritingSource = + object : Source { + private var cacheRequestClosed = false + + @Throws(IOException::class) + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { + val bytesRead: Long + try { + bytesRead = source.read(sink, byteCount) + } catch (e: IOException) { + if (!cacheRequestClosed) { + cacheRequestClosed = true + cacheRequest.abort() // Failed to write a complete cache response. + } + throw e } - throw e - } - if (bytesRead == -1L) { - if (!cacheRequestClosed) { - cacheRequestClosed = true - cacheBody.close() // The cache response is complete! + if (bytesRead == -1L) { + if (!cacheRequestClosed) { + cacheRequestClosed = true + cacheBody.close() // The cache response is complete! + } + return -1 } - return -1 - } - sink.copyTo(cacheBody.buffer, sink.size - bytesRead, bytesRead) - cacheBody.emitCompleteSegments() - return bytesRead - } + sink.copyTo(cacheBody.buffer, sink.size - bytesRead, bytesRead) + cacheBody.emitCompleteSegments() + return bytesRead + } - override fun timeout(): Timeout = source.timeout() + override fun timeout(): Timeout = source.timeout() - @Throws(IOException::class) - override fun close() { - if (!cacheRequestClosed && - !discard(ExchangeCodec.DISCARD_STREAM_TIMEOUT_MILLIS, MILLISECONDS)) { - cacheRequestClosed = true - cacheRequest.abort() + @Throws(IOException::class) + override fun close() { + if (!cacheRequestClosed && + !discard(ExchangeCodec.DISCARD_STREAM_TIMEOUT_MILLIS, MILLISECONDS) + ) { + cacheRequestClosed = true + cacheRequest.abort() + } + source.close() } - source.close() } - } val contentType = response.header("Content-Type") val contentLength = response.body.contentLength() return response.newBuilder() - .body(RealResponseBody(contentType, contentLength, cacheWritingSource.buffer())) - .build() + .body(RealResponseBody(contentType, contentLength, cacheWritingSource.buffer())) + .build() } companion object { /** Combines cached headers with a network headers as defined by RFC 7234, 4.3.4. */ - private fun combine(cachedHeaders: Headers, networkHeaders: Headers): Headers { + private fun combine( + cachedHeaders: Headers, + networkHeaders: Headers, + ): Headers { val result = Headers.Builder() for (index in 0 until cachedHeaders.size) { @@ -230,8 +242,9 @@ class CacheInterceptor(internal val cache: Cache?) : Interceptor { continue } if (isContentSpecificHeader(fieldName) || - !isEndToEnd(fieldName) || - networkHeaders[fieldName] == null) { + !isEndToEnd(fieldName) || + networkHeaders[fieldName] == null + ) { result.addLenient(fieldName, value) } } @@ -252,13 +265,13 @@ class CacheInterceptor(internal val cache: Cache?) : Interceptor { */ private fun isEndToEnd(fieldName: String): Boolean { return !"Connection".equals(fieldName, ignoreCase = true) && - !"Keep-Alive".equals(fieldName, ignoreCase = true) && - !"Proxy-Authenticate".equals(fieldName, ignoreCase = true) && - !"Proxy-Authorization".equals(fieldName, ignoreCase = true) && - !"TE".equals(fieldName, ignoreCase = true) && - !"Trailers".equals(fieldName, ignoreCase = true) && - !"Transfer-Encoding".equals(fieldName, ignoreCase = true) && - !"Upgrade".equals(fieldName, ignoreCase = true) + !"Keep-Alive".equals(fieldName, ignoreCase = true) && + !"Proxy-Authenticate".equals(fieldName, ignoreCase = true) && + !"Proxy-Authorization".equals(fieldName, ignoreCase = true) && + !"TE".equals(fieldName, ignoreCase = true) && + !"Trailers".equals(fieldName, ignoreCase = true) && + !"Transfer-Encoding".equals(fieldName, ignoreCase = true) && + !"Upgrade".equals(fieldName, ignoreCase = true) } /** @@ -267,8 +280,8 @@ class CacheInterceptor(internal val cache: Cache?) : Interceptor { */ private fun isContentSpecificHeader(fieldName: String): Boolean { return "Content-Length".equals(fieldName, ignoreCase = true) || - "Content-Encoding".equals(fieldName, ignoreCase = true) || - "Content-Type".equals(fieldName, ignoreCase = true) + "Content-Encoding".equals(fieldName, ignoreCase = true) || + "Content-Type".equals(fieldName, ignoreCase = true) } } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt index 917de871b6d9..7e447cc57dfb 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt @@ -47,13 +47,12 @@ class CacheStrategy internal constructor( /** The request to send on the network, or null if this call doesn't use the network. */ val networkRequest: Request?, /** The cached response to return or validate; or null if this call doesn't use a cache. */ - val cacheResponse: Response? + val cacheResponse: Response?, ) { - class Factory( private val nowMillis: Long, internal val request: Request, - private val cacheResponse: Response? + private val cacheResponse: Response?, ) { /** The server's time when the cached response was served, if known. */ private var servedDate: Date? = null @@ -219,7 +218,8 @@ class CacheStrategy internal constructor( val conditionalRequestHeaders = request.headers.newBuilder() conditionalRequestHeaders.addLenient(conditionName, conditionValue!!) - val conditionalRequest = request.newBuilder() + val conditionalRequest = + request.newBuilder() .headers(conditionalRequestHeaders.build()) .build() return CacheStrategy(conditionalRequest, cacheResponse) @@ -260,17 +260,19 @@ class CacheStrategy internal constructor( */ private fun cacheResponseAge(): Long { val servedDate = this.servedDate - val apparentReceivedAge = if (servedDate != null) { - maxOf(0, receivedResponseMillis - servedDate.time) - } else { - 0 - } + val apparentReceivedAge = + if (servedDate != null) { + maxOf(0, receivedResponseMillis - servedDate.time) + } else { + 0 + } - val receivedAge = if (ageSeconds != -1) { - maxOf(apparentReceivedAge, SECONDS.toMillis(ageSeconds.toLong())) - } else { - apparentReceivedAge - } + val receivedAge = + if (ageSeconds != -1) { + maxOf(apparentReceivedAge, SECONDS.toMillis(ageSeconds.toLong())) + } else { + apparentReceivedAge + } val responseDuration = maxOf(0, receivedResponseMillis - sentRequestMillis) val residentDuration = maxOf(0, nowMillis - receivedResponseMillis) @@ -283,12 +285,15 @@ class CacheStrategy internal constructor( * response cache won't be used. */ private fun hasConditions(request: Request): Boolean = - request.header("If-Modified-Since") != null || request.header("If-None-Match") != null + request.header("If-Modified-Since") != null || request.header("If-None-Match") != null } companion object { /** Returns true if [response] can be stored to later serve another request. */ - fun isCacheable(response: Response, request: Request): Boolean { + fun isCacheable( + response: Response, + request: Request, + ): Boolean { // Always go to network for uncacheable response codes (RFC 7231 section 6.1), This // implementation doesn't support caching partial content. when (response.code) { @@ -302,19 +307,22 @@ class CacheStrategy internal constructor( HTTP_GONE, HTTP_REQ_TOO_LONG, HTTP_NOT_IMPLEMENTED, - HTTP_PERM_REDIRECT -> { + HTTP_PERM_REDIRECT, + -> { // These codes can be cached unless headers forbid it. } HTTP_MOVED_TEMP, - HTTP_TEMP_REDIRECT -> { + HTTP_TEMP_REDIRECT, + -> { // These codes can only be cached with the right response headers. // http://tools.ietf.org/html/rfc7234#section-3 // s-maxage is not checked because OkHttp is a private cache that should ignore s-maxage. if (response.header("Expires") == null && - response.cacheControl.maxAgeSeconds == -1 && - !response.cacheControl.isPublic && - !response.cacheControl.isPrivate) { + response.cacheControl.maxAgeSeconds == -1 && + !response.cacheControl.isPublic && + !response.cacheControl.isPrivate + ) { return false } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt index 9c3886d5a321..e581cd068b90 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt @@ -86,31 +86,31 @@ import okio.buffer */ class DiskLruCache( fileSystem: FileSystem, - /** Returns the directory where this cache stores its data. */ val directory: Path, - private val appVersion: Int, - internal val valueCount: Int, - /** Returns the maximum number of bytes that this cache should use to store its data. */ maxSize: Long, - /** Used for asynchronous journal rebuilds. */ - taskRunner: TaskRunner + taskRunner: TaskRunner, ) : Closeable, Flushable { - internal val fileSystem: FileSystem = object : ForwardingFileSystem(fileSystem) { - override fun sink(file: Path, mustCreate: Boolean): Sink { - file.parent?.let { - createDirectories(it) + internal val fileSystem: FileSystem = + object : ForwardingFileSystem(fileSystem) { + override fun sink( + file: Path, + mustCreate: Boolean, + ): Sink { + file.parent?.let { + createDirectories(it) + } + return super.sink(file, mustCreate) } - return super.sink(file, mustCreate) } - } /** The maximum number of bytes that this cache should use to store its data. */ - @get:Synchronized @set:Synchronized var maxSize: Long = maxSize + @get:Synchronized @set:Synchronized + var maxSize: Long = maxSize set(value) { field = value if (initialized) { @@ -182,34 +182,35 @@ class DiskLruCache( private var nextSequenceNumber: Long = 0 private val cleanupQueue = taskRunner.newQueue() - private val cleanupTask = object : Task("$okHttpName Cache") { - override fun runOnce(): Long { - synchronized(this@DiskLruCache) { - if (!initialized || closed) { - return -1L // Nothing to do. - } + private val cleanupTask = + object : Task("$okHttpName Cache") { + override fun runOnce(): Long { + synchronized(this@DiskLruCache) { + if (!initialized || closed) { + return -1L // Nothing to do. + } - try { - trimToSize() - } catch (_: IOException) { - mostRecentTrimFailed = true - } + try { + trimToSize() + } catch (_: IOException) { + mostRecentTrimFailed = true + } - try { - if (journalRebuildRequired()) { - rebuildJournal() - redundantOpCount = 0 + try { + if (journalRebuildRequired()) { + rebuildJournal() + redundantOpCount = 0 + } + } catch (_: IOException) { + mostRecentRebuildFailed = true + journalWriter?.closeQuietly() + journalWriter = blackholeSink().buffer() } - } catch (_: IOException) { - mostRecentRebuildFailed = true - journalWriter?.closeQuietly() - journalWriter = blackholeSink().buffer() - } - return -1L + return -1L + } } } - } init { require(maxSize > 0L) { "maxSize <= 0" } @@ -220,7 +221,8 @@ class DiskLruCache( this.journalFileBackup = directory / JOURNAL_FILE_BACKUP } - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun initialize() { this.assertThreadHoldsLock() @@ -249,9 +251,10 @@ class DiskLruCache( return } catch (journalIsCorrupt: IOException) { Platform.get().log( - "DiskLruCache $directory is corrupt: ${journalIsCorrupt.message}, removing", - WARN, - journalIsCorrupt) + "DiskLruCache $directory is corrupt: ${journalIsCorrupt.message}, removing", + WARN, + journalIsCorrupt, + ) } // The cache is corrupted, attempt to delete the contents of the directory. This can throw and @@ -278,12 +281,14 @@ class DiskLruCache( val blank = readUtf8LineStrict() if (MAGIC != magic || - VERSION_1 != version || - appVersion.toString() != appVersionString || - valueCount.toString() != valueCountString || - blank.isNotEmpty()) { + VERSION_1 != version || + appVersion.toString() != appVersionString || + valueCount.toString() != valueCountString || + blank.isNotEmpty() + ) { throw IOException( - "unexpected journal header: [$magic, $version, $valueCountString, $blank]") + "unexpected journal header: [$magic, $version, $valueCountString, $blank]", + ) } var lineCount = 0 @@ -311,10 +316,11 @@ class DiskLruCache( @Throws(FileNotFoundException::class) private fun newJournalWriter(): BufferedSink { val fileSink = fileSystem.appendingSink(journalFile) - val faultHidingSink = FaultHidingSink(fileSink) { - this@DiskLruCache.assertThreadHoldsLock() - hasJournalErrors = true - } + val faultHidingSink = + FaultHidingSink(fileSink) { + this@DiskLruCache.assertThreadHoldsLock() + hasJournalErrors = true + } return faultHidingSink.buffer() } @@ -344,7 +350,8 @@ class DiskLruCache( when { secondSpace != -1 && firstSpace == CLEAN.length && line.startsWith(CLEAN) -> { - val parts = line.substring(secondSpace + 1) + val parts = + line.substring(secondSpace + 1) .split(' ') entry.readable = true entry.currentEditor = null @@ -392,7 +399,8 @@ class DiskLruCache( * Creates a new journal that omits redundant information. This replaces the current journal if it * exists. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) internal fun rebuildJournal() { journalWriter?.close() @@ -435,7 +443,8 @@ class DiskLruCache( * Returns a snapshot of the entry named [key], or null if it doesn't exist is not currently * readable. If a value is returned, it is moved to the head of the LRU queue. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) operator fun get(key: String): Snapshot? { initialize() @@ -446,9 +455,9 @@ class DiskLruCache( redundantOpCount++ journalWriter!!.writeUtf8(READ) - .writeByte(' '.code) - .writeUtf8(key) - .writeByte('\n'.code) + .writeByte(' '.code) + .writeUtf8(key) + .writeByte('\n'.code) if (journalRebuildRequired()) { cleanupQueue.schedule(cleanupTask) } @@ -457,16 +466,21 @@ class DiskLruCache( } /** Returns an editor for the entry named [key], or null if another edit is in progress. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) @JvmOverloads - fun edit(key: String, expectedSequenceNumber: Long = ANY_SEQUENCE_NUMBER): Editor? { + fun edit( + key: String, + expectedSequenceNumber: Long = ANY_SEQUENCE_NUMBER, + ): Editor? { initialize() checkNotClosed() validateKey(key) var entry: Entry? = lruEntries[key] if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && - (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { + (entry == null || entry.sequenceNumber != expectedSequenceNumber) + ) { return null // Snapshot is stale. } @@ -491,9 +505,9 @@ class DiskLruCache( // Flush the journal before creating files to prevent file leaks. val journalWriter = this.journalWriter!! journalWriter.writeUtf8(DIRTY) - .writeByte(' '.code) - .writeUtf8(key) - .writeByte('\n'.code) + .writeByte(' '.code) + .writeUtf8(key) + .writeByte('\n'.code) journalWriter.flush() if (hasJournalErrors) { @@ -513,14 +527,19 @@ class DiskLruCache( * Returns the number of bytes currently being used to store the values in this cache. This may be * greater than the max size if a background deletion is pending. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun size(): Long { initialize() return size } - @Synchronized @Throws(IOException::class) - internal fun completeEdit(editor: Editor, success: Boolean) { + @Synchronized + @Throws(IOException::class) + internal fun completeEdit( + editor: Editor, + success: Boolean, + ) { val entry = editor.entry check(entry.currentEditor == editor) @@ -593,7 +612,7 @@ class DiskLruCache( private fun journalRebuildRequired(): Boolean { val redundantOpCompactThreshold = 2000 return redundantOpCount >= redundantOpCompactThreshold && - redundantOpCount >= lruEntries.size + redundantOpCount >= lruEntries.size } /** @@ -602,7 +621,8 @@ class DiskLruCache( * * @return true if an entry was removed. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun remove(key: String): Boolean { initialize() @@ -664,7 +684,8 @@ class DiskLruCache( } /** Force buffered operations to the filesystem. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) override fun flush() { if (!initialized) return @@ -676,7 +697,8 @@ class DiskLruCache( @Synchronized fun isClosed(): Boolean = closed /** Closes this cache. Stored values will remain on the filesystem. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) override fun close() { if (!initialized || closed) { closed = true @@ -729,7 +751,8 @@ class DiskLruCache( * Deletes all stored values from the cache. In-flight edits will complete normally but their * values will not be stored. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun evictAll() { initialize() // Copying for concurrent iteration. @@ -756,7 +779,8 @@ class DiskLruCache( * **The caller must [close][Snapshot.close]** each snapshot returned by [Iterator.next]. Failing * to do so leaks open files! */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun snapshots(): MutableIterator { initialize() return object : MutableIterator { @@ -812,7 +836,7 @@ class DiskLruCache( private val key: String, private val sequenceNumber: Long, private val sources: List, - private val lengths: LongArray + private val lengths: LongArray, ) : Closeable { fun key(): String = key @@ -936,9 +960,8 @@ class DiskLruCache( } internal inner class Entry internal constructor( - internal val key: String + internal val key: String, ) { - /** Lengths of this entry's files. */ internal val lengths: LongArray = LongArray(valueCount) internal val cleanFiles = mutableListOf() @@ -1047,6 +1070,7 @@ class DiskLruCache( lockingSourceCount++ return object : ForwardingSource(fileSource) { private var closed = false + override fun close() { super.close() if (!closed) { @@ -1065,15 +1089,25 @@ class DiskLruCache( companion object { @JvmField val JOURNAL_FILE = "journal" + @JvmField val JOURNAL_FILE_TEMP = "journal.tmp" + @JvmField val JOURNAL_FILE_BACKUP = "journal.bkp" + @JvmField val MAGIC = "libcore.io.DiskLruCache" + @JvmField val VERSION_1 = "1" + @JvmField val ANY_SEQUENCE_NUMBER: Long = -1 + @JvmField val LEGAL_KEY_PATTERN = "[a-z0-9_-]{1,120}".toRegex() + @JvmField val CLEAN = "CLEAN" + @JvmField val DIRTY = "DIRTY" + @JvmField val REMOVE = "REMOVE" + @JvmField val READ = "READ" } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/FaultHidingSink.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache/FaultHidingSink.kt index d1a61d1bfee5..f1ce00e31c95 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/cache/FaultHidingSink.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache/FaultHidingSink.kt @@ -23,11 +23,14 @@ import okio.Sink /** A sink that never throws IOExceptions, even if the underlying sink does. */ internal open class FaultHidingSink( delegate: Sink, - val onException: (IOException) -> Unit + val onException: (IOException) -> Unit, ) : ForwardingSink(delegate) { private var hasErrors = false - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { if (hasErrors) { source.skip(byteCount) return diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache2/FileOperator.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache2/FileOperator.kt index e695dfaff89b..1d10221046ab 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/cache2/FileOperator.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache2/FileOperator.kt @@ -30,12 +30,15 @@ import okio.Buffer * each [FileOperator] should not be. */ internal class FileOperator( - private val fileChannel: FileChannel + private val fileChannel: FileChannel, ) { - /** Write [byteCount] bytes from [source] to the file at [pos]. */ @Throws(IOException::class) - fun write(pos: Long, source: Buffer, byteCount: Long) { + fun write( + pos: Long, + source: Buffer, + byteCount: Long, + ) { if (byteCount < 0L || byteCount > source.size) { throw IndexOutOfBoundsException() } @@ -54,7 +57,11 @@ internal class FileOperator( * caller's responsibility to make sure there are sufficient bytes to read: if there aren't this * method throws an `EOFException`. */ - fun read(pos: Long, sink: Buffer, byteCount: Long) { + fun read( + pos: Long, + sink: Buffer, + byteCount: Long, + ) { if (byteCount < 0L) { throw IndexOutOfBoundsException() } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache2/Relay.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache2/Relay.kt index b321347eeb45..6ae6e61809a1 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/cache2/Relay.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache2/Relay.kt @@ -52,21 +52,17 @@ class Relay private constructor( * are permitted. */ var file: RandomAccessFile?, - /** * Null once the file has a complete copy of the upstream bytes. Only the [upstreamReader] thread * may access this source. */ var upstream: Source?, - /** The number of bytes consumed from [upstream]. Guarded by this. */ var upstreamPos: Long, - /** User-supplied additional data persisted with the source data. */ private val metadata: ByteString, - /** The maximum size of [buffer]. */ - val bufferMaxSize: Long + val bufferMaxSize: Long, ) { /** The thread that currently has access to upstream. Possibly null. Guarded by this. */ var upstreamReader: Thread? = null @@ -96,14 +92,15 @@ class Relay private constructor( private fun writeHeader( prefix: ByteString, upstreamSize: Long, - metadataSize: Long + metadataSize: Long, ) { - val header = Buffer().apply { - write(prefix) - writeLong(upstreamSize) - writeLong(metadataSize) - require(size == FILE_HEADER_SIZE) - } + val header = + Buffer().apply { + write(prefix) + writeLong(upstreamSize) + writeLong(metadataSize) + require(size == FILE_HEADER_SIZE) + } val fileOperator = FileOperator(file!!.channel) fileOperator.write(0, header, FILE_HEADER_SIZE) @@ -184,43 +181,47 @@ class Relay private constructor( * block until that read completes. It is possible to time out while waiting for that. */ @Throws(IOException::class) - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { check(fileOperator != null) - val source: Int = synchronized(this@Relay) { - // We need new data from upstream. - while (true) { - val upstreamPos = this@Relay.upstreamPos - if (sourcePos != upstreamPos) break - - // No more data upstream. We're done. - if (complete) return -1L - - // Another thread is already reading. Wait for that. - if (upstreamReader != null) { - timeout.waitUntilNotified(this@Relay) - continue + val source: Int = + synchronized(this@Relay) { + // We need new data from upstream. + while (true) { + val upstreamPos = this@Relay.upstreamPos + if (sourcePos != upstreamPos) break + + // No more data upstream. We're done. + if (complete) return -1L + + // Another thread is already reading. Wait for that. + if (upstreamReader != null) { + timeout.waitUntilNotified(this@Relay) + continue + } + + // We will do the read. + upstreamReader = Thread.currentThread() + return@synchronized SOURCE_UPSTREAM } - // We will do the read. - upstreamReader = Thread.currentThread() - return@synchronized SOURCE_UPSTREAM - } + val bufferPos = upstreamPos - buffer.size - val bufferPos = upstreamPos - buffer.size + // Bytes of the read precede the buffer. Read from the file. + if (sourcePos < bufferPos) { + return@synchronized SOURCE_FILE + } - // Bytes of the read precede the buffer. Read from the file. - if (sourcePos < bufferPos) { - return@synchronized SOURCE_FILE + // The buffer has the data we need. Read from there and return immediately. + val bytesToRead = minOf(byteCount, upstreamPos - sourcePos) + buffer.copyTo(sink, sourcePos - bufferPos, bytesToRead) + sourcePos += bytesToRead + return bytesToRead } - // The buffer has the data we need. Read from there and return immediately. - val bytesToRead = minOf(byteCount, upstreamPos - sourcePos) - buffer.copyTo(sink, sourcePos - bufferPos, bytesToRead) - sourcePos += bytesToRead - return bytesToRead - } - // Read from the file. if (source == SOURCE_FILE) { val bytesToRead = minOf(byteCount, upstreamPos - sourcePos) @@ -247,7 +248,10 @@ class Relay private constructor( // Append the upstream bytes to the file. fileOperator!!.write( - FILE_HEADER_SIZE + upstreamPos, upstreamBuffer.clone(), upstreamBytesRead) + FILE_HEADER_SIZE + upstreamPos, + upstreamBuffer.clone(), + upstreamBytesRead, + ) synchronized(this@Relay) { // Append new upstream bytes into the buffer. Trim it to its max size. @@ -297,6 +301,7 @@ class Relay private constructor( private const val SOURCE_FILE = 2 @JvmField val PREFIX_CLEAN = "OkHttp cache v1\n".encodeUtf8() + @JvmField val PREFIX_DIRTY = "OkHttp DIRTY :(\n".encodeUtf8() private const val FILE_HEADER_SIZE = 32L @@ -312,7 +317,7 @@ class Relay private constructor( file: File, upstream: Source, metadata: ByteString, - bufferMaxSize: Long + bufferMaxSize: Long, ): Relay { val randomAccessFile = RandomAccessFile(file, "rw") val result = Relay(randomAccessFile, upstream, 0L, metadata, bufferMaxSize) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/Task.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/Task.kt index 29345fb63677..947182a7eee2 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/Task.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/Task.kt @@ -48,7 +48,7 @@ package okhttp3.internal.concurrent */ abstract class Task( val name: String, - val cancelable: Boolean = true + val cancelable: Boolean = true, ) { // Guarded by the TaskRunner. internal var queue: TaskQueue? = null diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskLogger.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskLogger.kt index 3fe18aa64926..f27e8e3618fe 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskLogger.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskLogger.kt @@ -21,7 +21,7 @@ import java.util.logging.Logger internal inline fun Logger.taskLog( task: Task, queue: TaskQueue, - messageBlock: () -> String + messageBlock: () -> String, ) { if (isLoggable(Level.FINE)) { log(task, queue, messageBlock()) @@ -31,7 +31,7 @@ internal inline fun Logger.taskLog( internal inline fun Logger.logElapsed( task: Task, queue: TaskQueue, - block: () -> T + block: () -> T, ): T { var startNs = -1L val loggingEnabled = isLoggable(Level.FINE) @@ -57,7 +57,11 @@ internal inline fun Logger.logElapsed( } } -private fun Logger.log(task: Task, queue: TaskQueue, message: String) { +private fun Logger.log( + task: Task, + queue: TaskQueue, + message: String, +) { fine("${queue.name} ${String.format("%-22s", message)}: ${task.name}") } @@ -70,13 +74,14 @@ private fun Logger.log(task: Task, queue: TaskQueue, message: String) { * the returned string may be longer. */ fun formatDuration(ns: Long): String { - val s = when { - ns <= -999_500_000 -> "${(ns - 500_000_000) / 1_000_000_000} s " - ns <= -999_500 -> "${(ns - 500_000) / 1_000_000} ms" - ns <= 0 -> "${(ns - 500) / 1_000} µs" - ns < 999_500 -> "${(ns + 500) / 1_000} µs" - ns < 999_500_000 -> "${(ns + 500_000) / 1_000_000} ms" - else -> "${(ns + 500_000_000) / 1_000_000_000} s " - } + val s = + when { + ns <= -999_500_000 -> "${(ns - 500_000_000) / 1_000_000_000} s " + ns <= -999_500 -> "${(ns - 500_000) / 1_000_000} ms" + ns <= 0 -> "${(ns - 500) / 1_000} µs" + ns < 999_500 -> "${(ns + 500) / 1_000} µs" + ns < 999_500_000 -> "${(ns + 500_000) / 1_000_000} ms" + else -> "${(ns + 500_000_000) / 1_000_000_000} s " + } return String.format("%6s", s) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt index 1e2258e4b046..788fc0f44321 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt @@ -30,7 +30,7 @@ import okhttp3.internal.okHttpName */ class TaskQueue internal constructor( internal val taskRunner: TaskRunner, - internal val name: String + internal val name: String, ) { val lock: ReentrantLock = ReentrantLock() @@ -62,7 +62,10 @@ class TaskQueue internal constructor( * * @throws RejectedExecutionException if the queue is shut down and the task is not cancelable. */ - fun schedule(task: Task, delayNanos: Long = 0L) { + fun schedule( + task: Task, + delayNanos: Long = 0L, + ) { taskRunner.lock.withLock { if (shutdown) { if (task.cancelable) { @@ -87,13 +90,16 @@ class TaskQueue internal constructor( fun schedule( name: String, delayNanos: Long = 0L, - block: () -> Long + block: () -> Long, ) { - schedule(object : Task(name) { - override fun runOnce(): Long { - return block() - } - }, delayNanos) + schedule( + object : Task(name) { + override fun runOnce(): Long { + return block() + } + }, + delayNanos, + ) } /** @@ -105,14 +111,17 @@ class TaskQueue internal constructor( name: String, delayNanos: Long = 0L, cancelable: Boolean = true, - block: () -> Unit + block: () -> Unit, ) { - schedule(object : Task(name, cancelable) { - override fun runOnce(): Long { - block() - return -1L - } - }, delayNanos) + schedule( + object : Task(name, cancelable) { + override fun runOnce(): Long { + block() + return -1L + } + }, + delayNanos, + ) } /** Returns a latch that reaches 0 when the queue is next idle. */ @@ -154,7 +163,11 @@ class TaskQueue internal constructor( } /** Adds [task] to run in [delayNanos]. Returns true if the coordinator is impacted. */ - internal fun scheduleAndDecide(task: Task, delayNanos: Long, recurrence: Boolean): Boolean { + internal fun scheduleAndDecide( + task: Task, + delayNanos: Long, + recurrence: Boolean, + ): Boolean { task.initQueue(this) val now = taskRunner.backend.nanoTime() @@ -171,8 +184,11 @@ class TaskQueue internal constructor( } task.nextExecuteNanoTime = executeNanoTime taskRunner.logger.taskLog(task, this) { - if (recurrence) "run again after ${formatDuration(executeNanoTime - now)}" - else "scheduled after ${formatDuration(executeNanoTime - now)}" + if (recurrence) { + "run again after ${formatDuration(executeNanoTime - now)}" + } else { + "scheduled after ${formatDuration(executeNanoTime - now)}" + } } // Insert in chronological order. Always compare deltas because nanoTime() is permitted to wrap. diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt index 7d86a5f90c75..6acc7b24e774 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt @@ -43,7 +43,7 @@ import okhttp3.internal.threadFactory */ class TaskRunner( val backend: Backend, - internal val logger: Logger = TaskRunner.logger + internal val logger: Logger = TaskRunner.logger, ) { val lock: ReentrantLock = ReentrantLock() val condition: Condition = lock.newCondition() @@ -58,30 +58,32 @@ class TaskRunner( /** Queues not in [busyQueues] that have non-empty [TaskQueue.futureTasks]. */ private val readyQueues = mutableListOf() - private val runnable: Runnable = object : Runnable { - override fun run() { - while (true) { - val task = this@TaskRunner.lock.withLock { - awaitTaskToRun() - } ?: return - - logger.logElapsed(task, task.queue!!) { - var completedNormally = false - try { - runTask(task) - completedNormally = true - } finally { - // If the task is crashing start another thread to service the queues. - if (!completedNormally) { - lock.withLock { - backend.execute(this@TaskRunner, this) + private val runnable: Runnable = + object : Runnable { + override fun run() { + while (true) { + val task = + this@TaskRunner.lock.withLock { + awaitTaskToRun() + } ?: return + + logger.logElapsed(task, task.queue!!) { + var completedNormally = false + try { + runTask(task) + completedNormally = true + } finally { + // If the task is crashing start another thread to service the queues. + if (!completedNormally) { + lock.withLock { + backend.execute(this@TaskRunner, this) + } } } } } } } - } internal fun kickCoordinator(taskQueue: TaskQueue) { lock.assertHeld() @@ -128,7 +130,10 @@ class TaskRunner( } } - private fun afterRun(task: Task, delayNanos: Long) { + private fun afterRun( + task: Task, + delayNanos: Long, + ) { lock.assertHeld() val queue = task.queue!! @@ -264,23 +269,35 @@ class TaskRunner( interface Backend { fun nanoTime(): Long + fun coordinatorNotify(taskRunner: TaskRunner) - fun coordinatorWait(taskRunner: TaskRunner, nanos: Long) + + fun coordinatorWait( + taskRunner: TaskRunner, + nanos: Long, + ) + fun decorate(queue: BlockingQueue): BlockingQueue - fun execute(taskRunner: TaskRunner, runnable: Runnable) + + fun execute( + taskRunner: TaskRunner, + runnable: Runnable, + ) } class RealBackend(threadFactory: ThreadFactory) : Backend { - val executor = ThreadPoolExecutor( - // corePoolSize: - 0, - // maximumPoolSize: - Int.MAX_VALUE, - // keepAliveTime: - 60L, TimeUnit.SECONDS, - SynchronousQueue(), - threadFactory - ) + val executor = + ThreadPoolExecutor( + // corePoolSize: + 0, + // maximumPoolSize: + Int.MAX_VALUE, + // keepAliveTime: + 60L, + TimeUnit.SECONDS, + SynchronousQueue(), + threadFactory, + ) override fun nanoTime() = System.nanoTime() @@ -294,7 +311,10 @@ class TaskRunner( */ @Throws(InterruptedException::class) @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") - override fun coordinatorWait(taskRunner: TaskRunner, nanos: Long) { + override fun coordinatorWait( + taskRunner: TaskRunner, + nanos: Long, + ) { taskRunner.lock.assertHeld() if (nanos > 0) { taskRunner.condition.awaitNanos(nanos) @@ -303,7 +323,10 @@ class TaskRunner( override fun decorate(queue: BlockingQueue) = queue - override fun execute(taskRunner: TaskRunner, runnable: Runnable) { + override fun execute( + taskRunner: TaskRunner, + runnable: Runnable, + ) { executor.execute(runnable) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt index 89d8bb72b377..fd6c8a125eef 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -66,7 +66,6 @@ class ConnectPlan( private val call: RealCall, private val chain: Interceptor.Chain, private val routePlanner: RealRoutePlanner, - // Specifics to this plan. override val route: Route, internal val routes: List?, @@ -74,7 +73,7 @@ class ConnectPlan( private val tunnelRequest: Request?, internal val connectionSpecIndex: Int, internal val isTlsFallback: Boolean, - internal val connectionListener: ConnectionListener + internal val connectionListener: ConnectionListener, ) : RoutePlanner.Plan, ExchangeCodec.Carrier { private val eventListener = call.eventListener @@ -118,7 +117,7 @@ class ConnectPlan( tunnelRequest = tunnelRequest, connectionSpecIndex = connectionSpecIndex, isTlsFallback = isTlsFallback, - connectionListener = connectionListener + connectionListener = connectionListener, ) } @@ -180,13 +179,14 @@ class ConnectPlan( eventListener.secureConnectStart(call) // Create the wrapper over the connected socket. - val sslSocket = route.address.sslSocketFactory.createSocket( - rawSocket, - route.address.url.host, - route.address.url.port, - // autoClose: - true - ) as SSLSocket + val sslSocket = + route.address.sslSocketFactory.createSocket( + rawSocket, + route.address.url.host, + route.address.url.port, + // autoClose: + true, + ) as SSLSocket val tlsEquipPlan = planWithCurrentOrInitialConnectionSpec(connectionSpecs, sslSocket) val connectionSpec = connectionSpecs[tlsEquipPlan.connectionSpecIndex] @@ -199,25 +199,27 @@ class ConnectPlan( eventListener.secureConnectEnd(call, handshake) } else { socket = rawSocket - protocol = when { - Protocol.H2_PRIOR_KNOWLEDGE in route.address.protocols -> Protocol.H2_PRIOR_KNOWLEDGE - else -> Protocol.HTTP_1_1 - } + protocol = + when { + Protocol.H2_PRIOR_KNOWLEDGE in route.address.protocols -> Protocol.H2_PRIOR_KNOWLEDGE + else -> Protocol.HTTP_1_1 + } } - val connection = RealConnection( - taskRunner = client.taskRunner, - connectionPool = client.connectionPool.delegate, - route = route, - rawSocket = rawSocket, - socket = socket, - handshake = handshake, - protocol = protocol, - source = source, - sink = sink, - pingIntervalMillis = client.pingIntervalMillis, - connectionListener = client.connectionPool.connectionListener - ) + val connection = + RealConnection( + taskRunner = client.taskRunner, + connectionPool = client.connectionPool.delegate, + route = route, + rawSocket = rawSocket, + socket = socket, + handshake = handshake, + protocol = protocol, + source = source, + sink = sink, + pingIntervalMillis = client.pingIntervalMillis, + connectionListener = client.connectionPool.connectionListener, + ) this.connection = connection connection.start() @@ -236,7 +238,7 @@ class ConnectPlan( return ConnectResult( plan = this, nextPlan = retryTlsConnection, - throwable = e + throwable = e, ) } finally { call.plansToCancel -= this @@ -250,10 +252,11 @@ class ConnectPlan( /** Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */ @Throws(IOException::class) private fun connectSocket() { - val rawSocket = when (route.proxy.type()) { - Proxy.Type.DIRECT, Proxy.Type.HTTP -> route.address.socketFactory.createSocket()!! - else -> Socket(route.proxy) - } + val rawSocket = + when (route.proxy.type()) { + Proxy.Type.DIRECT, Proxy.Type.HTTP -> route.address.socketFactory.createSocket()!! + else -> Socket(route.proxy) + } this.rawSocket = rawSocket // Handle the race where cancel() precedes connectSocket(). We don't want to miss a cancel. @@ -293,8 +296,9 @@ class ConnectPlan( */ @Throws(IOException::class) internal fun connectTunnel(): ConnectResult { - val nextTunnelRequest = createTunnel() - ?: return ConnectResult(plan = this) // Success. + val nextTunnelRequest = + createTunnel() + ?: return ConnectResult(plan = this) // Success. // The proxy decided to close the connection after an auth challenge. Retry with different // auth credentials. @@ -306,16 +310,18 @@ class ConnectPlan( eventListener.connectEnd(call, route.socketAddress, route.proxy, null) ConnectResult( plan = this, - nextPlan = copy( - attempt = nextAttempt, - tunnelRequest = nextTunnelRequest, - ) + nextPlan = + copy( + attempt = nextAttempt, + tunnelRequest = nextTunnelRequest, + ), ) } else -> { - val failure = ProtocolException( - "Too many tunnel connections attempted: $MAX_TUNNEL_ATTEMPTS" - ) + val failure = + ProtocolException( + "Too many tunnel connections attempted: $MAX_TUNNEL_ATTEMPTS", + ) eventListener.connectFailed(call, route.socketAddress, route.proxy, null, failure) connectionListener.connectFailed(route, call, failure) return ConnectResult(plan = this, throwable = failure) @@ -324,7 +330,10 @@ class ConnectPlan( } @Throws(IOException::class) - private fun connectTls(sslSocket: SSLSocket, connectionSpec: ConnectionSpec) { + private fun connectTls( + sslSocket: SSLSocket, + connectionSpec: ConnectionSpec, + ) { val address = route.address var success = false try { @@ -349,27 +358,28 @@ class ConnectPlan( | certificate: ${CertificatePinner.pin(cert)} | DN: ${cert.subjectDN.name} | subjectAltNames: ${OkHostnameVerifier.allSubjectAltNames(cert)} - """.trimMargin() + """.trimMargin(), ) } else { throw SSLPeerUnverifiedException( - "Hostname ${address.url.host} not verified (no certificates)" + "Hostname ${address.url.host} not verified (no certificates)", ) } } val certificatePinner = address.certificatePinner!! - val handshake = Handshake( - unverifiedHandshake.tlsVersion, - unverifiedHandshake.cipherSuite, - unverifiedHandshake.localCertificates - ) { - certificatePinner.certificateChainCleaner!!.clean( - unverifiedHandshake.peerCertificates, - address.url.host - ) - } + val handshake = + Handshake( + unverifiedHandshake.tlsVersion, + unverifiedHandshake.cipherSuite, + unverifiedHandshake.localCertificates, + ) { + certificatePinner.certificateChainCleaner!!.clean( + unverifiedHandshake.peerCertificates, + address.url.host, + ) + } this.handshake = handshake // Check that the certificate pinner is satisfied by the certificates presented. @@ -378,11 +388,12 @@ class ConnectPlan( } // Success! Save the handshake and the ALPN protocol. - val maybeProtocol = if (connectionSpec.supportsTlsExtensions) { - Platform.get().getSelectedProtocol(sslSocket) - } else { - null - } + val maybeProtocol = + if (connectionSpec.supportsTlsExtensions) { + Platform.get().getSelectedProtocol(sslSocket) + } else { + null + } socket = sslSocket source = sslSocket.source().buffer() sink = sslSocket.sink().buffer() @@ -409,20 +420,22 @@ class ConnectPlan( while (true) { val source = this.source!! val sink = this.sink!! - val tunnelCodec = Http1ExchangeCodec( - // No client for CONNECT tunnels: - client = null, - carrier = this, - source = source, - sink = sink - ) + val tunnelCodec = + Http1ExchangeCodec( + // No client for CONNECT tunnels: + client = null, + carrier = this, + source = source, + sink = sink, + ) source.timeout().timeout(client.readTimeoutMillis.toLong(), TimeUnit.MILLISECONDS) sink.timeout().timeout(client.writeTimeoutMillis.toLong(), TimeUnit.MILLISECONDS) tunnelCodec.writeRequest(nextRequest.headers, requestLine) tunnelCodec.finishRequest() - val response = tunnelCodec.readResponseHeaders(false)!! - .request(nextRequest) - .build() + val response = + tunnelCodec.readResponseHeaders(false)!! + .request(nextRequest) + .build() tunnelCodec.skipConnectBody(response) when (response.code) { @@ -449,15 +462,15 @@ class ConnectPlan( @Throws(IOException::class) internal fun planWithCurrentOrInitialConnectionSpec( connectionSpecs: List, - sslSocket: SSLSocket + sslSocket: SSLSocket, ): ConnectPlan { if (connectionSpecIndex != -1) return this return nextConnectionSpec(connectionSpecs, sslSocket) ?: throw UnknownServiceException( "Unable to find acceptable protocols." + - " isFallback=${isTlsFallback}," + + " isFallback=$isTlsFallback," + " modes=$connectionSpecs," + - " supported protocols=${sslSocket.enabledProtocols!!.contentToString()}" + " supported protocols=${sslSocket.enabledProtocols!!.contentToString()}", ) } @@ -467,7 +480,7 @@ class ConnectPlan( */ internal fun nextConnectionSpec( connectionSpecs: List, - sslSocket: SSLSocket + sslSocket: SSLSocket, ): ConnectPlan? { for (i in connectionSpecIndex + 1 until connectionSpecs.size) { if (connectionSpecs[i].isCompatible(sslSocket)) { @@ -499,7 +512,10 @@ class ConnectPlan( return connection } - override fun trackFailure(call: RealCall, e: IOException?) { + override fun trackFailure( + call: RealCall, + e: IOException?, + ) { // Do nothing. } @@ -525,7 +541,7 @@ class ConnectPlan( tunnelRequest = tunnelRequest, connectionSpecIndex = connectionSpecIndex, isTlsFallback = isTlsFallback, - connectionListener = connectionListener + connectionListener = connectionListener, ) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/Exchange.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/Exchange.kt index c00f71a2fc75..7e7027f7840a 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/Exchange.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/Exchange.kt @@ -41,7 +41,7 @@ class Exchange( internal val call: RealCall, internal val eventListener: EventListener, internal val finder: ExchangeFinder, - private val codec: ExchangeCodec + private val codec: ExchangeCodec, ) { /** True if the request body need not complete before the response body starts. */ internal var isDuplex: Boolean = false @@ -71,7 +71,10 @@ class Exchange( } @Throws(IOException::class) - fun createRequestBody(request: Request, duplex: Boolean): Sink { + fun createRequestBody( + request: Request, + duplex: Boolean, + ): Sink { this.isDuplex = duplex val contentLength = request.body!!.contentLength() eventListener.requestBodyStart(call) @@ -176,7 +179,7 @@ class Exchange( bytesRead: Long, responseDone: Boolean, requestDone: Boolean, - e: E + e: E, ): E { if (e != null) { trackFailure(e) @@ -206,18 +209,22 @@ class Exchange( private inner class RequestBodySink( delegate: Sink, /** The exact number of bytes to be written, or -1L if that is unknown. */ - private val contentLength: Long + private val contentLength: Long, ) : ForwardingSink(delegate) { private var completed = false private var bytesReceived = 0L private var closed = false @Throws(IOException::class) - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { check(!closed) { "closed" } if (contentLength != -1L && bytesReceived + byteCount > contentLength) { throw ProtocolException( - "expected $contentLength bytes but received ${bytesReceived + byteCount}") + "expected $contentLength bytes but received ${bytesReceived + byteCount}", + ) } try { super.write(source, byteCount) @@ -261,7 +268,7 @@ class Exchange( /** A response body that fires events when it completes. */ internal inner class ResponseBodySource( delegate: Source, - private val contentLength: Long + private val contentLength: Long, ) : ForwardingSource(delegate) { private var bytesReceived = 0L private var invokeStartEvent = true @@ -275,7 +282,10 @@ class Exchange( } @Throws(IOException::class) - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { check(!closed) { "closed" } try { val read = delegate.read(sink, byteCount) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt index 33ac9723e164..74154b99c441 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt @@ -112,16 +112,17 @@ internal class FastFallbackExchangeFinder( * its connection. */ private fun launchTcpConnect(): ConnectResult? { - val plan = when { - routePlanner.hasNext() -> { - try { - routePlanner.plan() - } catch (e: Throwable) { - FailedPlan(e) + val plan = + when { + routePlanner.hasNext() -> { + try { + routePlanner.plan() + } catch (e: Throwable) { + FailedPlan(e) + } } + else -> return null // Nothing further to try. } - else -> return null // Nothing further to try. - } // Already connected. Return it immediately. if (plan.isReady) return ConnectResult(plan) @@ -132,24 +133,30 @@ internal class FastFallbackExchangeFinder( // Connect TCP asynchronously. tcpConnectsInFlight += plan val taskName = "$okHttpName connect ${routePlanner.address.url.redact()}" - taskRunner.newQueue().schedule(object : Task(taskName) { - override fun runOnce(): Long { - val connectResult = try { - plan.connectTcp() - } catch (e: Throwable) { - ConnectResult(plan, throwable = e) - } - // Only post a result if this hasn't since been canceled. - if (plan in tcpConnectsInFlight) { - connectResults.put(connectResult) + taskRunner.newQueue().schedule( + object : Task(taskName) { + override fun runOnce(): Long { + val connectResult = + try { + plan.connectTcp() + } catch (e: Throwable) { + ConnectResult(plan, throwable = e) + } + // Only post a result if this hasn't since been canceled. + if (plan in tcpConnectsInFlight) { + connectResults.put(connectResult) + } + return -1L } - return -1L - } - }) + }, + ) return null } - private fun awaitTcpConnect(timeout: Long, unit: TimeUnit): ConnectResult? { + private fun awaitTcpConnect( + timeout: Long, + unit: TimeUnit, + ): ConnectResult? { if (tcpConnectsInFlight.isEmpty()) return null val result = connectResults.poll(timeout, unit) ?: return null diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt index 67bc7a511d42..682af618efe3 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt @@ -63,19 +63,20 @@ class RealCall( val client: OkHttpClient, /** The application's original request unadulterated by redirects or auth headers. */ val originalRequest: Request, - val forWebSocket: Boolean + val forWebSocket: Boolean, ) : Call, Cloneable { private val connectionPool: RealConnectionPool = client.connectionPool.delegate internal val eventListener: EventListener = client.eventListenerFactory.create(this) - private val timeout = object : AsyncTimeout() { - override fun timedOut() { - this@RealCall.cancel() + private val timeout = + object : AsyncTimeout() { + override fun timedOut() { + this@RealCall.cancel() + } + }.apply { + timeout(client.callTimeoutMillis.toLong(), MILLISECONDS) } - }.apply { - timeout(client.callTimeoutMillis.toLong(), MILLISECONDS) - } private val executed = AtomicBoolean() @@ -115,6 +116,7 @@ class RealCall( // canceled it's canceled forever. @Volatile private var canceled = false + @Volatile private var exchange: Exchange? = null internal val plansToCancel = CopyOnWriteArrayList() @@ -189,16 +191,17 @@ class RealCall( } interceptors += CallServerInterceptor(forWebSocket) - val chain = RealInterceptorChain( - call = this, - interceptors = interceptors, - index = 0, - exchange = null, - request = originalRequest, - connectTimeoutMillis = client.connectTimeoutMillis, - readTimeoutMillis = client.readTimeoutMillis, - writeTimeoutMillis = client.writeTimeoutMillis - ) + val chain = + RealInterceptorChain( + call = this, + interceptors = interceptors, + index = 0, + exchange = null, + request = originalRequest, + connectTimeoutMillis = client.connectTimeoutMillis, + readTimeoutMillis = client.readTimeoutMillis, + writeTimeoutMillis = client.writeTimeoutMillis, + ) var calledNoMoreExchanges = false try { @@ -242,17 +245,19 @@ class RealCall( } if (newRoutePlanner) { - val routePlanner = RealRoutePlanner( - client, - createAddress(request.url), - this, - chain, - connectionListener = connectionPool.connectionListener - ) - this.exchangeFinder = when { - client.fastFallback -> FastFallbackExchangeFinder(routePlanner, client.taskRunner) - else -> SequentialExchangeFinder(routePlanner) - } + val routePlanner = + RealRoutePlanner( + client, + createAddress(request.url), + this, + chain, + connectionListener = connectionPool.connectionListener, + ) + this.exchangeFinder = + when { + client.fastFallback -> FastFallbackExchangeFinder(routePlanner, client.taskRunner) + else -> SequentialExchangeFinder(routePlanner) + } } } @@ -299,7 +304,7 @@ class RealCall( exchange: Exchange, requestDone: Boolean, responseDone: Boolean, - e: E + e: E, ): E { if (exchange != this.exchange) return e // This exchange was detached violently! @@ -360,10 +365,11 @@ class RealCall( val connection = this.connection if (connection != null) { connection.assertThreadDoesntHoldLock() - val toClose: Socket? = synchronized(connection) { - // Sets this.connection to null. - releaseConnectionNoEvents() - } + val toClose: Socket? = + synchronized(connection) { + // Sets this.connection to null. + releaseConnectionNoEvents() + } if (this.connection == null) { toClose?.closeQuietly() eventListener.connectionReleased(this, connection) @@ -468,7 +474,7 @@ class RealCall( proxy = client.proxy, protocols = client.protocols, connectionSpecs = client.connectionSpecs, - proxySelector = client.proxySelector + proxySelector = client.proxySelector, ) } @@ -482,15 +488,17 @@ class RealCall( * sensitive information. */ private fun toLoggableString(): String { - return ((if (isCanceled()) "canceled " else "") + - (if (forWebSocket) "web socket" else "call") + - " to " + redactedUrl()) + return ( + (if (isCanceled()) "canceled " else "") + + (if (forWebSocket) "web socket" else "call") + + " to " + redactedUrl() + ) } internal fun redactedUrl(): String = originalRequest.url.redact() inner class AsyncCall( - private val responseCallback: Callback + private val responseCallback: Callback, ) : Runnable { @Volatile var callsPerHost = AtomicInteger(0) private set @@ -571,6 +579,6 @@ class RealCall( * Captures the stack trace at the time the Call is executed or enqueued. This is helpful for * identifying the origin of connection leaks. */ - val callStackTrace: Any? + val callStackTrace: Any?, ) : WeakReference(referent) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt index b5d78de2af09..b9b63c9cdc2b 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt @@ -64,10 +64,8 @@ class RealConnection( val taskRunner: TaskRunner, val connectionPool: RealConnectionPool, override val route: Route, - /** The low-level TCP socket. */ private var rawSocket: Socket?, - /** * The application layer socket. Either an [SSLSocket] layered over [rawSocket], or [rawSocket] * itself if this connection does not use SSL. @@ -78,7 +76,7 @@ class RealConnection( private var source: BufferedSource?, private var sink: BufferedSink?, private val pingIntervalMillis: Int, - internal val connectionListener: ConnectionListener + internal val connectionListener: ConnectionListener, ) : Http2Connection.Listener(), Connection, ExchangeCodec.Carrier { private var http2Connection: Http2Connection? = null @@ -160,12 +158,13 @@ class RealConnection( val sink = this.sink!! socket.soTimeout = 0 // HTTP/2 connection timeouts are set per-stream. val flowControlListener = connectionListener as? FlowControlListener ?: FlowControlListener.None - val http2Connection = Http2Connection.Builder(client = true, taskRunner) - .socket(socket, route.address.url.host, source, sink) - .listener(this) - .pingIntervalMillis(pingIntervalMillis) - .flowControlListener(flowControlListener) - .build() + val http2Connection = + Http2Connection.Builder(client = true, taskRunner) + .socket(socket, route.address.url.host, source, sink) + .listener(this) + .pingIntervalMillis(pingIntervalMillis) + .flowControlListener(flowControlListener) + .build() this.http2Connection = http2Connection this.allocationLimit = Http2Connection.DEFAULT_SETTINGS.getMaxConcurrentStreams() http2Connection.start() @@ -175,7 +174,10 @@ class RealConnection( * Returns true if this connection can carry a stream allocation to `address`. If non-null * `route` is the resolved route for a connection. */ - internal fun isEligible(address: Address, routes: List?): Boolean { + internal fun isEligible( + address: Address, + routes: List?, + ): Boolean { assertThreadHoldsLock() // If this connection is not accepting new exchanges, we're done. @@ -245,7 +247,10 @@ class RealConnection( return !noCoalescedConnections && handshake != null && certificateSupportHost(url, handshake!!) } - private fun certificateSupportHost(url: HttpUrl, handshake: Handshake): Boolean { + private fun certificateSupportHost( + url: HttpUrl, + handshake: Handshake, + ): Boolean { val peerCertificates = handshake.peerCertificates return peerCertificates.isNotEmpty() && @@ -253,7 +258,10 @@ class RealConnection( } @Throws(SocketException::class) - internal fun newCodec(client: OkHttpClient, chain: RealInterceptorChain): ExchangeCodec { + internal fun newCodec( + client: OkHttpClient, + chain: RealInterceptorChain, + ): ExchangeCodec { val socket = this.socket!! val source = this.source!! val sink = this.sink!! @@ -281,6 +289,7 @@ class RealConnection( override fun close() { exchange.bodyComplete(-1L, responseDone = true, requestDone = true, e = null) } + override fun cancel() { exchange.cancel() } @@ -306,7 +315,8 @@ class RealConnection( val socket = this.socket!! val source = this.source!! if (rawSocket.isClosed || socket.isClosed || socket.isInputShutdown || - socket.isOutputShutdown) { + socket.isOutputShutdown + ) { return false } @@ -330,19 +340,28 @@ class RealConnection( } /** When settings are received, adjust the allocation limit. */ - @Synchronized override fun onSettings(connection: Http2Connection, settings: Settings) { + @Synchronized override fun onSettings( + connection: Http2Connection, + settings: Settings, + ) { allocationLimit = settings.getMaxConcurrentStreams() } override fun handshake(): Handshake? = handshake /** Track a bad route in the route database. Other routes will be attempted first. */ - internal fun connectFailed(client: OkHttpClient, failedRoute: Route, failure: IOException) { + internal fun connectFailed( + client: OkHttpClient, + failedRoute: Route, + failure: IOException, + ) { // Tell the proxy selector when we fail to connect on a fresh connection. if (failedRoute.proxy.type() != Proxy.Type.DIRECT) { val address = failedRoute.address address.proxySelector.connectFailed( - address.url.toUri(), failedRoute.proxy.address(), failure + address.url.toUri(), + failedRoute.proxy.address(), + failure, ) } @@ -353,7 +372,10 @@ class RealConnection( * Track a failure using this connection. This may prevent both the connection and its route from * being used for future exchanges. */ - override fun trackFailure(call: RealCall, e: IOException?) { + override fun trackFailure( + call: RealCall, + e: IOException?, + ) { var noNewExchangesEvent = false synchronized(this) { if (e is StreamResetException) { @@ -418,21 +440,22 @@ class RealConnection( connectionPool: RealConnectionPool, route: Route, socket: Socket, - idleAtNs: Long + idleAtNs: Long, ): RealConnection { - val result = RealConnection( - taskRunner = taskRunner, - connectionPool = connectionPool, - route = route, - rawSocket = null, - socket = socket, - handshake = null, - protocol = null, - source = null, - sink = null, - pingIntervalMillis = 0, - ConnectionListener.NONE - ) + val result = + RealConnection( + taskRunner = taskRunner, + connectionPool = connectionPool, + route = route, + rawSocket = null, + socket = socket, + handshake = null, + protocol = null, + source = null, + sink = null, + pingIntervalMillis = 0, + ConnectionListener.NONE, + ) result.idleAtNs = idleAtNs return result } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt index 99f1b7047a0c..37974480ff20 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt @@ -38,14 +38,15 @@ class RealConnectionPool( private val maxIdleConnections: Int, keepAliveDuration: Long, timeUnit: TimeUnit, - internal val connectionListener: ConnectionListener + internal val connectionListener: ConnectionListener, ) { private val keepAliveDurationNs: Long = timeUnit.toNanos(keepAliveDuration) private val cleanupQueue: TaskQueue = taskRunner.newQueue() - private val cleanupTask = object : Task("$okHttpName ConnectionPool") { - override fun runOnce(): Long = cleanup(System.nanoTime()) - } + private val cleanupTask = + object : Task("$okHttpName ConnectionPool") { + override fun runOnce(): Long = cleanup(System.nanoTime()) + } /** * Holding the lock of the connection being added or removed when mutating this, and check its @@ -86,20 +87,21 @@ class RealConnectionPool( address: Address, call: RealCall, routes: List?, - requireMultiplexed: Boolean + requireMultiplexed: Boolean, ): RealConnection? { for (connection in connections) { // In the first synchronized block, acquire the connection if it can satisfy this call. - val acquired = synchronized(connection) { - when { - requireMultiplexed && !connection.isMultiplexed -> false - !connection.isEligible(address, routes) -> false - else -> { - call.acquireConnectionNoEvents(connection) - true + val acquired = + synchronized(connection) { + when { + requireMultiplexed && !connection.isMultiplexed -> false + !connection.isEligible(address, routes) -> false + else -> { + call.acquireConnectionNoEvents(connection) + true + } } } - } if (!acquired) continue // Confirm the connection is healthy and return it. @@ -108,11 +110,12 @@ class RealConnectionPool( // In the second synchronized block, release the unhealthy acquired connection. We're also on // the hook to close this connection if it's no longer in use. val noNewExchangesEvent: Boolean - val toClose: Socket? = synchronized(connection) { - noNewExchangesEvent = !connection.noNewExchanges - connection.noNewExchanges = true - call.releaseConnectionNoEvents() - } + val toClose: Socket? = + synchronized(connection) { + noNewExchangesEvent = !connection.noNewExchanges + connection.noNewExchanges = true + call.releaseConnectionNoEvents() + } if (toClose != null) { toClose.closeQuietly() connectionListener.connectionClosed(connection) @@ -153,15 +156,16 @@ class RealConnectionPool( val i = connections.iterator() while (i.hasNext()) { val connection = i.next() - val socketToClose = synchronized(connection) { - if (connection.calls.isEmpty()) { - i.remove() - connection.noNewExchanges = true - return@synchronized connection.socket() - } else { - return@synchronized null + val socketToClose = + synchronized(connection) { + if (connection.calls.isEmpty()) { + i.remove() + connection.noNewExchanges = true + return@synchronized connection.socket() + } else { + return@synchronized null + } } - } if (socketToClose != null) { socketToClose.closeQuietly() connectionListener.connectionClosed(connection) @@ -198,14 +202,16 @@ class RealConnectionPool( if (idleDurationNs > longestIdleDurationNs) { longestIdleDurationNs = idleDurationNs longestIdleConnection = connection - } else Unit + } else { + Unit + } } } } when { - longestIdleDurationNs >= this.keepAliveDurationNs - || idleConnectionCount > this.maxIdleConnections -> { + longestIdleDurationNs >= this.keepAliveDurationNs || + idleConnectionCount > this.maxIdleConnections -> { // We've chosen a connection to evict. Confirm it's still okay to be evict, then close it. val connection = longestIdleConnection!! synchronized(connection) { @@ -245,7 +251,10 @@ class RealConnectionPool( * Calls are leaked if the connection is tracking them but the application code has abandoned * them. Leak detection is imprecise and relies on garbage collection. */ - private fun pruneAndGetAllocationCount(connection: RealConnection, now: Long): Int { + private fun pruneAndGetAllocationCount( + connection: RealConnection, + now: Long, + ): Int { connection.assertThreadHoldsLock() val references = connection.calls @@ -260,7 +269,8 @@ class RealConnectionPool( // We've discovered a leaked call. This is an application bug. val callReference = reference as CallReference - val message = "A connection to ${connection.route().address.url} was leaked. " + + val message = + "A connection to ${connection.route().address.url} was leaked. " + "Did you forget to close a response body?" Platform.get().logCloseableLeak(message, callReference.callStackTrace) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt index 19c45b7a93e0..886df21d0d07 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt @@ -41,7 +41,7 @@ class RealRoutePlanner( override val address: Address, private val call: RealCall, private val chain: RealInterceptorChain, - private val connectionListener: ConnectionListener + private val connectionListener: ConnectionListener, ) : RoutePlanner { private val doExtensiveHealthChecks = chain.request.method != "GET" @@ -90,19 +90,20 @@ class RealRoutePlanner( // then we're on the hook to close it. val healthy = candidate.isHealthy(doExtensiveHealthChecks) var noNewExchangesEvent = false - val toClose: Socket? = synchronized(candidate) { - when { - !healthy -> { - noNewExchangesEvent = !candidate.noNewExchanges - candidate.noNewExchanges = true - call.releaseConnectionNoEvents() - } - candidate.noNewExchanges || !sameHostAndPort(candidate.route().address.url) -> { - call.releaseConnectionNoEvents() + val toClose: Socket? = + synchronized(candidate) { + when { + !healthy -> { + noNewExchangesEvent = !candidate.noNewExchanges + candidate.noNewExchanges = true + call.releaseConnectionNoEvents() + } + candidate.noNewExchanges || !sameHostAndPort(candidate.route().address.url) -> { + call.releaseConnectionNoEvents() + } + else -> null } - else -> null } - } // If the call's connection wasn't released, reuse it. We don't call connectionAcquired() here // because we already acquired it. @@ -142,13 +143,14 @@ class RealRoutePlanner( // Decide which proxy to use, if any. This may block in ProxySelector.select(). var newRouteSelector = routeSelector if (newRouteSelector == null) { - newRouteSelector = RouteSelector( - address = address, - routeDatabase = call.client.routeDatabase, - call = call, - fastFallback = client.fastFallback, - eventListener = call.eventListener - ) + newRouteSelector = + RouteSelector( + address = address, + routeDatabase = call.client.routeDatabase, + call = call, + fastFallback = client.fastFallback, + eventListener = call.eventListener, + ) routeSelector = newRouteSelector } @@ -173,13 +175,14 @@ class RealRoutePlanner( planToReplace: ConnectPlan? = null, routes: List? = null, ): ReusePlan? { - val result = client.connectionPool.delegate.callAcquirePooledConnection( - doExtensiveHealthChecks = doExtensiveHealthChecks, - address = address, - call = call, - routes = routes, - requireMultiplexed = planToReplace != null && planToReplace.isReady - ) ?: return null + val result = + client.connectionPool.delegate.callAcquirePooledConnection( + doExtensiveHealthChecks = doExtensiveHealthChecks, + address = address, + call = call, + routes = routes, + requireMultiplexed = planToReplace != null && planToReplace.isReady, + ) ?: return null // If we coalesced our connection, remember the replaced connection's route. That way if the // coalesced connection later fails we don't waste a valid route. @@ -195,7 +198,10 @@ class RealRoutePlanner( /** Returns a plan for the first attempt at [route]. This throws if no plan is possible. */ @Throws(IOException::class) - internal fun planConnectToRoute(route: Route, routes: List? = null): ConnectPlan { + internal fun planConnectToRoute( + route: Route, + routes: List? = null, + ): ConnectPlan { if (route.address.sslSocketFactory == null) { if (ConnectionSpec.CLEARTEXT !in route.address.connectionSpecs) { throw UnknownServiceException("CLEARTEXT communication not enabled for client") @@ -204,7 +210,7 @@ class RealRoutePlanner( val host = route.address.url.host if (!Platform.get().isCleartextTrafficPermitted(host)) { throw UnknownServiceException( - "CLEARTEXT communication to $host not permitted by network security policy" + "CLEARTEXT communication to $host not permitted by network security policy", ) } } else { @@ -213,10 +219,11 @@ class RealRoutePlanner( } } - val tunnelRequest = when { - route.requiresTunnel() -> createTunnelRequest(route) - else -> null - } + val tunnelRequest = + when { + route.requiresTunnel() -> createTunnelRequest(route) + else -> null + } return ConnectPlan( client = client, @@ -229,7 +236,7 @@ class RealRoutePlanner( tunnelRequest = tunnelRequest, connectionSpecIndex = -1, isTlsFallback = false, - connectionListener = connectionListener + connectionListener = connectionListener, ) } @@ -244,26 +251,29 @@ class RealRoutePlanner( */ @Throws(IOException::class) private fun createTunnelRequest(route: Route): Request { - val proxyConnectRequest = Request.Builder() - .url(route.address.url) - .method("CONNECT", null) - .header("Host", route.address.url.toHostHeader(includeDefaultPort = true)) - .header("Proxy-Connection", "Keep-Alive") // For HTTP/1.0 proxies like Squid. - .header("User-Agent", USER_AGENT) - .build() - - val fakeAuthChallengeResponse = Response.Builder() - .request(proxyConnectRequest) - .protocol(Protocol.HTTP_1_1) - .code(HttpURLConnection.HTTP_PROXY_AUTH) - .message("Preemptive Authenticate") - .sentRequestAtMillis(-1L) - .receivedResponseAtMillis(-1L) - .header("Proxy-Authenticate", "OkHttp-Preemptive") - .build() - - val authenticatedRequest = route.address.proxyAuthenticator - .authenticate(route, fakeAuthChallengeResponse) + val proxyConnectRequest = + Request.Builder() + .url(route.address.url) + .method("CONNECT", null) + .header("Host", route.address.url.toHostHeader(includeDefaultPort = true)) + .header("Proxy-Connection", "Keep-Alive") // For HTTP/1.0 proxies like Squid. + .header("User-Agent", USER_AGENT) + .build() + + val fakeAuthChallengeResponse = + Response.Builder() + .request(proxyConnectRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_PROXY_AUTH) + .message("Preemptive Authenticate") + .sentRequestAtMillis(-1L) + .receivedResponseAtMillis(-1L) + .header("Proxy-Authenticate", "OkHttp-Preemptive") + .build() + + val authenticatedRequest = + route.address.proxyAuthenticator + .authenticate(route, fakeAuthChallengeResponse) return authenticatedRequest ?: proxyConnectRequest } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ReusePlan.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/ReusePlan.kt index e9a53ccbc835..af932a963326 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/ReusePlan.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/ReusePlan.kt @@ -19,7 +19,6 @@ package okhttp3.internal.connection internal class ReusePlan( val connection: RealConnection, ) : RoutePlanner.Plan { - override val isReady = true override fun connectTcp() = error("already connected") diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt index 4685de667166..920ab5920e77 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt @@ -29,7 +29,6 @@ class RouteDatabase { val failedRoutes: Set @Synchronized get() = _failedRoutes.toSet() - /** Records a failure connecting to [failedRoute]. */ @Synchronized fun failed(failedRoute: Route) { _failedRoutes.add(failedRoute) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteSelector.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteSelector.kt index 409a4abf5db8..4b44dba16f96 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteSelector.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteSelector.kt @@ -42,14 +42,14 @@ class RouteSelector( private val fastFallback: Boolean, private val eventListener: EventListener, ) { - /* State for negotiating the next proxy to use. */ + // State for negotiating the next proxy to use. private var proxies = emptyList() private var nextProxyIndex: Int = 0 - /* State for negotiating the next socket address to use. */ + // State for negotiating the next socket address to use. private var inetSocketAddresses = emptyList() - /* State for negotiating failed routes */ + // State for negotiating failed routes private val postponedRoutes = mutableListOf() init { @@ -96,7 +96,10 @@ class RouteSelector( } /** Prepares the proxy servers to try. */ - private fun resetNextProxy(url: HttpUrl, proxy: Proxy?) { + private fun resetNextProxy( + url: HttpUrl, + proxy: Proxy?, + ) { fun selectProxies(): List { // If the user specifies a proxy, try that and only that. if (proxy != null) return listOf(proxy) @@ -126,7 +129,8 @@ class RouteSelector( private fun nextProxy(): Proxy { if (!hasNextProxy()) { throw SocketException( - "No route to ${address.url.host}; exhausted proxy configurations: $proxies") + "No route to ${address.url.host}; exhausted proxy configurations: $proxies", + ) } val result = proxies[nextProxyIndex++] resetNextInetSocketAddress(result) @@ -161,25 +165,27 @@ class RouteSelector( if (proxy.type() == Proxy.Type.SOCKS) { mutableInetSocketAddresses += InetSocketAddress.createUnresolved(socketHost, socketPort) } else { - val addresses = if (socketHost.canParseAsIpAddress()) { - listOf(InetAddress.getByName(socketHost)) - } else { - eventListener.dnsStart(call, socketHost) - - val result = address.dns.lookup(socketHost) - if (result.isEmpty()) { - throw UnknownHostException("${address.dns} returned no addresses for $socketHost") - } + val addresses = + if (socketHost.canParseAsIpAddress()) { + listOf(InetAddress.getByName(socketHost)) + } else { + eventListener.dnsStart(call, socketHost) - eventListener.dnsEnd(call, socketHost, result) - result - } + val result = address.dns.lookup(socketHost) + if (result.isEmpty()) { + throw UnknownHostException("${address.dns} returned no addresses for $socketHost") + } + + eventListener.dnsEnd(call, socketHost, result) + result + } // Try each address for best behavior in mixed IPv4/IPv6 environments. - val orderedAddresses = when { - fastFallback -> reorderForHappyEyeballs(addresses) - else -> addresses - } + val orderedAddresses = + when { + fastFallback -> reorderForHappyEyeballs(addresses) + else -> addresses + } for (inetAddress in orderedAddresses) { mutableInetSocketAddresses += InetSocketAddress(inetAddress, socketPort) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt index 0687825ce8a6..a1de07cda92b 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt @@ -19,7 +19,7 @@ import java.io.IOException /** Attempt routes one at a time until one connects. */ internal class SequentialExchangeFinder( - override val routePlanner: RoutePlanner + override val routePlanner: RoutePlanner, ) : ExchangeFinder { override fun find(): RealConnection { var firstException: IOException? = null @@ -31,10 +31,11 @@ internal class SequentialExchangeFinder( if (!plan.isReady) { val tcpConnectResult = plan.connectTcp() - val connectResult = when { - tcpConnectResult.isSuccess -> plan.connectTlsEtc() - else -> tcpConnectResult - } + val connectResult = + when { + tcpConnectResult.isSuccess -> plan.connectTlsEtc() + else -> tcpConnectResult + } val (_, nextPlan, failure) = connectResult diff --git a/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt b/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt index 5e9124e210a5..857ab26a2793 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt @@ -30,7 +30,7 @@ class OkHttpFeature : Feature { override fun beforeAnalysis(access: Feature.BeforeAnalysisAccess?) { RuntimeResourceAccess.addResource( ClassLoader.getSystemClassLoader().getUnnamedModule(), - "okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz" + "okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz", ) } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/BridgeInterceptor.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/BridgeInterceptor.kt index 53bfee9743d3..9e247b31041e 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/BridgeInterceptor.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/BridgeInterceptor.kt @@ -21,8 +21,8 @@ import okhttp3.Cookie import okhttp3.CookieJar import okhttp3.Interceptor import okhttp3.Response -import okhttp3.internal.toHostHeader import okhttp3.internal.USER_AGENT +import okhttp3.internal.toHostHeader import okio.GzipSource import okio.buffer @@ -32,7 +32,6 @@ import okio.buffer * response. */ class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor { - @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val userRequest = chain.request() @@ -85,16 +84,19 @@ class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor { cookieJar.receiveHeaders(networkRequest.url, networkResponse.headers) - val responseBuilder = networkResponse.newBuilder() + val responseBuilder = + networkResponse.newBuilder() .request(networkRequest) if (transparentGzip && - "gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) && - networkResponse.promisesBody()) { + "gzip".equals(networkResponse.header("Content-Encoding"), ignoreCase = true) && + networkResponse.promisesBody() + ) { val responseBody = networkResponse.body if (responseBody != null) { val gzipSource = GzipSource(responseBody.source()) - val strippedHeaders = networkResponse.headers.newBuilder() + val strippedHeaders = + networkResponse.headers.newBuilder() .removeAll("Content-Encoding") .removeAll("Content-Length") .build() @@ -108,10 +110,11 @@ class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor { } /** Returns a 'Cookie' HTTP request header with all cookies, like `a=b; c=d`. */ - private fun cookieHeader(cookies: List): String = buildString { - cookies.forEachIndexed { index, cookie -> - if (index > 0) append("; ") - append(cookie.name).append('=').append(cookie.value) + private fun cookieHeader(cookies: List): String = + buildString { + cookies.forEachIndexed { index, cookie -> + if (index > 0) append("; ") + append(cookie.name).append('=').append(cookie.value) + } } - } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt index 8217a4329ba5..9c7a60d49d15 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt @@ -26,7 +26,6 @@ import okio.buffer /** This is the last interceptor in the chain. It makes a network call to the server. */ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor { - @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val realChain = chain as RealInterceptorChain @@ -97,7 +96,8 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor { invokeStartEvent = false } } - var response = responseBuilder + var response = + responseBuilder .request(request) .handshake(exchange.connection.handshake()) .sentRequestAtMillis(sentRequestMillis) @@ -110,7 +110,8 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor { if (invokeStartEvent) { exchange.responseHeadersStart() } - response = responseBuilder + response = + responseBuilder .request(request) .handshake(exchange.connection.handshake()) .sentRequestAtMillis(sentRequestMillis) @@ -121,21 +122,24 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor { exchange.responseHeadersEnd(response) - response = if (forWebSocket && code == 101) { - // Connection is upgrading, but we need to ensure interceptors see a non-null response body. - response.stripBody() - } else { - response.newBuilder() + response = + if (forWebSocket && code == 101) { + // Connection is upgrading, but we need to ensure interceptors see a non-null response body. + response.stripBody() + } else { + response.newBuilder() .body(exchange.openResponseBody(response)) .build() - } + } if ("close".equals(response.request.header("Connection"), ignoreCase = true) || - "close".equals(response.header("Connection"), ignoreCase = true)) { + "close".equals(response.header("Connection"), ignoreCase = true) + ) { exchange.noNewExchangesOnConnection() } if ((code == 204 || code == 205) && response.body.contentLength() > 0L) { throw ProtocolException( - "HTTP $code had non-zero Content-Length: ${response.body.contentLength()}") + "HTTP $code had non-zero Content-Length: ${response.body.contentLength()}", + ) } return response } catch (e: IOException) { @@ -147,16 +151,20 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor { } } - private fun shouldIgnoreAndWaitForRealResponse(code: Int, exchange: Exchange): Boolean = when { - // Server sent a 100-continue even though we did not request one. Try again to read the - // actual response status. - code == 100 -> true + private fun shouldIgnoreAndWaitForRealResponse( + code: Int, + exchange: Exchange, + ): Boolean = + when { + // Server sent a 100-continue even though we did not request one. Try again to read the + // actual response status. + code == 100 -> true - // Handle Processing (102) & Early Hints (103) and any new codes without failing - // 100 and 101 are the exceptions with different meanings - // But Early Hints not currently exposed - code in (102 until 200) -> true + // Handle Processing (102) & Early Hints (103) and any new codes without failing + // 100 and 101 are the exceptions with different meanings + // But Early Hints not currently exposed + code in (102 until 200) -> true - else -> false - } + else -> false + } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/DateFormatting.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/DateFormatting.kt index 08f96aa77e60..df8efc2d1d60 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/DateFormatting.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/DateFormatting.kt @@ -29,48 +29,45 @@ internal const val MAX_DATE = 253402300799999L * Most websites serve cookies in the blessed format. Eagerly create the parser to ensure such * cookies are on the fast path. */ -private val STANDARD_DATE_FORMAT = object : ThreadLocal() { - override fun initialValue(): DateFormat { - // Date format specified by RFC 7231 section 7.1.1.1. - return SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US).apply { - isLenient = false - timeZone = UTC +private val STANDARD_DATE_FORMAT = + object : ThreadLocal() { + override fun initialValue(): DateFormat { + // Date format specified by RFC 7231 section 7.1.1.1. + return SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US).apply { + isLenient = false + timeZone = UTC + } } } -} /** If we fail to parse a date in a non-standard format, try each of these formats in sequence. */ -private val BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS = arrayOf( - // HTTP formats required by RFC2616 but with any timezone: - - // RFC 822, updated by RFC 1123 with any TZ. - "EEE, dd MMM yyyy HH:mm:ss zzz", - - // RFC 850, obsoleted by RFC 1036 with any TZ. - "EEEE, dd-MMM-yy HH:mm:ss zzz", - - // ANSI C's asctime() format - "EEE MMM d HH:mm:ss yyyy", - - // Alternative formats: - "EEE, dd-MMM-yyyy HH:mm:ss z", - "EEE, dd-MMM-yyyy HH-mm-ss z", - "EEE, dd MMM yy HH:mm:ss z", - "EEE dd-MMM-yyyy HH:mm:ss z", - "EEE dd MMM yyyy HH:mm:ss z", - "EEE dd-MMM-yyyy HH-mm-ss z", - "EEE dd-MMM-yy HH:mm:ss z", - "EEE dd MMM yy HH:mm:ss z", - "EEE,dd-MMM-yy HH:mm:ss z", - "EEE,dd-MMM-yyyy HH:mm:ss z", - "EEE, dd-MM-yyyy HH:mm:ss z", - - // RI bug 6641315 claims a cookie of this format was once served by www.yahoo.com: - "EEE MMM d yyyy HH:mm:ss z" -) +private val BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS = + arrayOf( + // HTTP formats required by RFC2616 but with any timezone: + // RFC 822, updated by RFC 1123 with any TZ. + "EEE, dd MMM yyyy HH:mm:ss zzz", + // RFC 850, obsoleted by RFC 1036 with any TZ. + "EEEE, dd-MMM-yy HH:mm:ss zzz", + // ANSI C's asctime() format + "EEE MMM d HH:mm:ss yyyy", + // Alternative formats: + "EEE, dd-MMM-yyyy HH:mm:ss z", + "EEE, dd-MMM-yyyy HH-mm-ss z", + "EEE, dd MMM yy HH:mm:ss z", + "EEE dd-MMM-yyyy HH:mm:ss z", + "EEE dd MMM yyyy HH:mm:ss z", + "EEE dd-MMM-yyyy HH-mm-ss z", + "EEE dd-MMM-yy HH:mm:ss z", + "EEE dd MMM yy HH:mm:ss z", + "EEE,dd-MMM-yy HH:mm:ss z", + "EEE,dd-MMM-yyyy HH:mm:ss z", + "EEE, dd-MM-yyyy HH:mm:ss z", + // RI bug 6641315 claims a cookie of this format was once served by www.yahoo.com: + "EEE MMM d yyyy HH:mm:ss z", + ) private val BROWSER_COMPATIBLE_DATE_FORMATS = - arrayOfNulls(BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS.size) + arrayOfNulls(BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS.size) /** Returns the date for this string, or null if the value couldn't be parsed. */ fun String.toHttpDateOrNull(): Date? { @@ -87,11 +84,12 @@ fun String.toHttpDateOrNull(): Date? { for (i in 0 until BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS.size) { var format: DateFormat? = BROWSER_COMPATIBLE_DATE_FORMATS[i] if (format == null) { - format = SimpleDateFormat(BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS[i], Locale.US).apply { - // Set the timezone to use when interpreting formats that don't have a timezone. GMT is - // specified by RFC 7231. - timeZone = UTC - } + format = + SimpleDateFormat(BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS[i], Locale.US).apply { + // Set the timezone to use when interpreting formats that don't have a timezone. GMT is + // specified by RFC 7231. + timeZone = UTC + } BROWSER_COMPATIBLE_DATE_FORMATS[i] = format } position.index = 0 diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/ExchangeCodec.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/ExchangeCodec.kt index ee1edfd596fa..340d79bcabf9 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/ExchangeCodec.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/ExchangeCodec.kt @@ -31,7 +31,10 @@ interface ExchangeCodec { /** Returns an output stream where the request body can be streamed. */ @Throws(IOException::class) - fun createRequestBody(request: Request, contentLength: Long): Sink + fun createRequestBody( + request: Request, + contentLength: Long, + ): Sink /** This should update the HTTP engine's sentRequestMillis field. */ @Throws(IOException::class) @@ -76,8 +79,14 @@ interface ExchangeCodec { */ interface Carrier { val route: Route - fun trackFailure(call: RealCall, e: IOException?) + + fun trackFailure( + call: RealCall, + e: IOException?, + ) + fun noNewExchanges() + fun cancel() } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpHeaders.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/HttpHeaders.kt index f149430c60bd..583666b49710 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpHeaders.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/HttpHeaders.kt @@ -98,8 +98,12 @@ private fun Buffer.readChallengeHeader(result: MutableList) { // It's a token68 because there isn't a value after it. if (!commaPrefixed && (commaSuffixed || exhausted())) { - result.add(Challenge(schemeName, - Collections.singletonMap(null, peek + "=".repeat(eqCount)))) + result.add( + Challenge( + schemeName, + Collections.singletonMap(null, peek + "=".repeat(eqCount)), + ), + ) peek = null continue } @@ -117,10 +121,11 @@ private fun Buffer.readChallengeHeader(result: MutableList) { if (eqCount > 1) return // Unexpected '=' characters. if (skipCommasAndWhitespace()) return // Unexpected ','. - val parameterValue = when { - startsWith('"'.code.toByte()) -> readQuotedString() - else -> readToken() - } ?: return // Expected a value. + val parameterValue = + when { + startsWith('"'.code.toByte()) -> readQuotedString() + else -> readToken() + } ?: return // Expected a value. val replaced = parameters.put(peek, parameterValue) peek = null @@ -197,7 +202,10 @@ private fun Buffer.readToken(): String? { } } -fun CookieJar.receiveHeaders(url: HttpUrl, headers: Headers) { +fun CookieJar.receiveHeaders( + url: HttpUrl, + headers: Headers, +) { if (this === CookieJar.NO_COOKIES) return val cookies = Cookie.parseAll(url, headers) @@ -218,15 +226,17 @@ fun Response.promisesBody(): Boolean { val responseCode = code if ((responseCode < HTTP_CONTINUE || responseCode >= 200) && - responseCode != HTTP_NO_CONTENT && - responseCode != HTTP_NOT_MODIFIED) { + responseCode != HTTP_NO_CONTENT && + responseCode != HTTP_NOT_MODIFIED + ) { return true } // If the Content-Length or Transfer-Encoding headers disagree with the response code, the // response is malformed. For best compatibility, we honor the headers. if (headersContentLength() != -1L || - "chunked".equals(header("Transfer-Encoding"), ignoreCase = true)) { + "chunked".equals(header("Transfer-Encoding"), ignoreCase = true) + ) { return true } @@ -234,9 +244,10 @@ fun Response.promisesBody(): Boolean { } @Deprecated( - message = "No longer supported", - level = DeprecationLevel.ERROR, - replaceWith = ReplaceWith(expression = "response.promisesBody()")) + message = "No longer supported", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith(expression = "response.promisesBody()"), +) fun hasBody(response: Response): Boolean { return response.promisesBody() } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpMethod.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/HttpMethod.kt index 0c6a33a61498..89d5c1adeb82 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpMethod.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/HttpMethod.kt @@ -20,13 +20,18 @@ import kotlin.jvm.JvmStatic object HttpMethod { @JvmStatic // Despite being 'internal', this method is called by popular 3rd party SDKs. fun invalidatesCache(method: String): Boolean = - (method == "POST" || method == "PATCH" || method == "PUT" || - method == "DELETE" || method == "MOVE") + ( + method == "POST" || method == "PATCH" || method == "PUT" || + method == "DELETE" || method == "MOVE" + ) @JvmStatic // Despite being 'internal', this method is called by popular 3rd party SDKs. - fun requiresRequestBody(method: String): Boolean = (method == "POST" || method == "PUT" || - method == "PATCH" || method == "PROPPATCH" || // WebDAV - method == "REPORT") + fun requiresRequestBody(method: String): Boolean = + ( + method == "POST" || method == "PUT" || + method == "PATCH" || method == "PROPPATCH" || // WebDAV + method == "REPORT" + ) @JvmStatic // Despite being 'internal', this method is called by popular 3rd party SDKs. fun permitsRequestBody(method: String): Boolean = !(method == "GET" || method == "HEAD") diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RealInterceptorChain.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/RealInterceptorChain.kt index d7fe4e744cd8..e0a294271ddb 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/RealInterceptorChain.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/RealInterceptorChain.kt @@ -41,9 +41,8 @@ class RealInterceptorChain( internal val request: Request, internal val connectTimeoutMillis: Int, internal val readTimeoutMillis: Int, - internal val writeTimeoutMillis: Int + internal val writeTimeoutMillis: Int, ) : Interceptor.Chain { - private var calls: Int = 0 internal fun copy( @@ -52,15 +51,26 @@ class RealInterceptorChain( request: Request = this.request, connectTimeoutMillis: Int = this.connectTimeoutMillis, readTimeoutMillis: Int = this.readTimeoutMillis, - writeTimeoutMillis: Int = this.writeTimeoutMillis - ) = RealInterceptorChain(call, interceptors, index, exchange, request, connectTimeoutMillis, - readTimeoutMillis, writeTimeoutMillis) + writeTimeoutMillis: Int = this.writeTimeoutMillis, + ) = RealInterceptorChain( + call, + interceptors, + index, + exchange, + request, + connectTimeoutMillis, + readTimeoutMillis, + writeTimeoutMillis, + ) override fun connection(): Connection? = exchange?.connection override fun connectTimeoutMillis(): Int = connectTimeoutMillis - override fun withConnectTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain { + override fun withConnectTimeout( + timeout: Int, + unit: TimeUnit, + ): Interceptor.Chain { check(exchange == null) { "Timeouts can't be adjusted in a network interceptor" } return copy(connectTimeoutMillis = checkDuration("connectTimeout", timeout.toLong(), unit)) @@ -68,7 +78,10 @@ class RealInterceptorChain( override fun readTimeoutMillis(): Int = readTimeoutMillis - override fun withReadTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain { + override fun withReadTimeout( + timeout: Int, + unit: TimeUnit, + ): Interceptor.Chain { check(exchange == null) { "Timeouts can't be adjusted in a network interceptor" } return copy(readTimeoutMillis = checkDuration("readTimeout", timeout.toLong(), unit)) @@ -76,7 +89,10 @@ class RealInterceptorChain( override fun writeTimeoutMillis(): Int = writeTimeoutMillis - override fun withWriteTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain { + override fun withWriteTimeout( + timeout: Int, + unit: TimeUnit, + ): Interceptor.Chain { check(exchange == null) { "Timeouts can't be adjusted in a network interceptor" } return copy(writeTimeoutMillis = checkDuration("writeTimeout", timeout.toLong(), unit)) @@ -106,8 +122,10 @@ class RealInterceptorChain( val interceptor = interceptors[index] @Suppress("USELESS_ELVIS") - val response = interceptor.intercept(next) ?: throw NullPointerException( - "interceptor $interceptor returned null") + val response = + interceptor.intercept(next) ?: throw NullPointerException( + "interceptor $interceptor returned null", + ) if (exchange != null) { check(index + 1 >= interceptors.size || next.calls == 1) { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RealResponseBody.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/RealResponseBody.kt index 78a0d739808c..88b5db8d808e 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/RealResponseBody.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/RealResponseBody.kt @@ -27,9 +27,8 @@ class RealResponseBody( */ private val contentTypeString: String?, private val contentLength: Long, - private val source: BufferedSource + private val source: BufferedSource, ) : ResponseBody() { - override fun contentLength(): Long = contentLength override fun contentType(): MediaType? = contentTypeString?.toMediaTypeOrNull() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RequestLine.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/RequestLine.kt index 8fb22418abd6..b3fffef72d24 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/RequestLine.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/RequestLine.kt @@ -21,28 +21,34 @@ import okhttp3.HttpUrl import okhttp3.Request object RequestLine { - /** * Returns the request status line, like "GET / HTTP/1.1". This is exposed to the application by * [HttpURLConnection.getHeaderFields], so it needs to be set even if the transport is * HTTP/2. */ - fun get(request: Request, proxyType: Proxy.Type): String = buildString { - append(request.method) - append(' ') - if (includeAuthorityInRequestLine(request, proxyType)) { - append(request.url) - } else { - append(requestPath(request.url)) + fun get( + request: Request, + proxyType: Proxy.Type, + ): String = + buildString { + append(request.method) + append(' ') + if (includeAuthorityInRequestLine(request, proxyType)) { + append(request.url) + } else { + append(requestPath(request.url)) + } + append(" HTTP/1.1") } - append(" HTTP/1.1") - } /** * Returns true if the request line should contain the full URL with host and port (like "GET * http://android.com/foo HTTP/1.1") or only the path (like "GET /foo HTTP/1.1"). */ - private fun includeAuthorityInRequestLine(request: Request, proxyType: Proxy.Type): Boolean { + private fun includeAuthorityInRequestLine( + request: Request, + proxyType: Proxy.Type, + ): Boolean { return !request.isHttps && proxyType == Proxy.Type.HTTP } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt index 373fb45cd71b..c7a3b4c5dea1 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt @@ -41,7 +41,6 @@ import okhttp3.internal.withSuppressed * [IOException] if the call was canceled. */ class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Interceptor { - @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val realChain = chain as RealInterceptorChain @@ -76,10 +75,11 @@ class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Intercepto } // Clear out downstream interceptor's additional request headers, cookies, etc. - response = response.newBuilder() - .request(request) - .priorResponse(priorResponse?.stripBody()) - .build() + response = + response.newBuilder() + .request(request) + .priorResponse(priorResponse?.stripBody()) + .build() val exchange = call.interceptorScopedExchange val followUp = followUpRequest(response, exchange) @@ -122,7 +122,7 @@ class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Intercepto e: IOException, call: RealCall, userRequest: Request, - requestSendStarted: Boolean + requestSendStarted: Boolean, ): Boolean { // The application layer has forbidden retries. if (!client.retryOnConnectionFailure) return false @@ -140,13 +140,19 @@ class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Intercepto return true } - private fun requestIsOneShot(e: IOException, userRequest: Request): Boolean { + private fun requestIsOneShot( + e: IOException, + userRequest: Request, + ): Boolean { val requestBody = userRequest.body return (requestBody != null && requestBody.isOneShot()) || - e is FileNotFoundException + e is FileNotFoundException } - private fun isRecoverable(e: IOException, requestSendStarted: Boolean): Boolean { + private fun isRecoverable( + e: IOException, + requestSendStarted: Boolean, + ): Boolean { // If there was a protocol problem, don't recover. if (e is ProtocolException) { return false @@ -183,7 +189,10 @@ class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Intercepto * follow-up is either unnecessary or not applicable, this returns null. */ @Throws(IOException::class) - private fun followUpRequest(userResponse: Response, exchange: Exchange?): Request? { + private fun followUpRequest( + userResponse: Response, + exchange: Exchange?, + ): Request? { val route = exchange?.connection?.route() val responseCode = userResponse.code @@ -265,7 +274,10 @@ class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Intercepto } } - private fun buildRedirectRequest(userResponse: Response, method: String): Request? { + private fun buildRedirectRequest( + userResponse: Response, + method: String, + ): Request? { // Does the client allow redirects? if (!client.followRedirects) return null @@ -281,7 +293,8 @@ class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Intercepto val requestBuilder = userResponse.request.newBuilder() if (HttpMethod.permitsRequestBody(method)) { val responseCode = userResponse.code - val maintainBody = HttpMethod.redirectsWithBody(method) || + val maintainBody = + HttpMethod.redirectsWithBody(method) || responseCode == HTTP_PERM_REDIRECT || responseCode == HTTP_TEMP_REDIRECT if (HttpMethod.redirectsToGet(method) && responseCode != HTTP_PERM_REDIRECT && responseCode != HTTP_TEMP_REDIRECT) { @@ -307,7 +320,10 @@ class RetryAndFollowUpInterceptor(private val client: OkHttpClient) : Intercepto return requestBuilder.url(url).build() } - private fun retryAfter(userResponse: Response, defaultDelay: Int): Int { + private fun retryAfter( + userResponse: Response, + defaultDelay: Int, + ): Int { val header = userResponse.header("Retry-After") ?: return defaultDelay // https://tools.ietf.org/html/rfc7231#section-7.1.3 diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/StatusLine.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/StatusLine.kt index 5e2631943d8f..369117dbbc4b 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/StatusLine.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/StatusLine.kt @@ -26,9 +26,8 @@ import okio.IOException class StatusLine( @JvmField val protocol: Protocol, @JvmField val code: Int, - @JvmField val message: String + @JvmField val message: String, ) { - override fun toString(): String { return buildString { if (protocol == Protocol.HTTP_1_0) { @@ -60,11 +59,12 @@ class StatusLine( } val httpMinorVersion = statusLine[7] - '0' codeStart = 9 - protocol = when (httpMinorVersion) { - 0 -> Protocol.HTTP_1_0 - 1 -> Protocol.HTTP_1_1 - else -> throw ProtocolException("Unexpected status line: $statusLine") - } + protocol = + when (httpMinorVersion) { + 0 -> Protocol.HTTP_1_0 + 1 -> Protocol.HTTP_1_1 + else -> throw ProtocolException("Unexpected status line: $statusLine") + } } else if (statusLine.startsWith("ICY ")) { // Shoutcast uses ICY instead of "HTTP/1.0". protocol = Protocol.HTTP_1_0 @@ -84,7 +84,7 @@ class StatusLine( val code = statusLine.substring(codeStart, codeStart + 3).toIntOrNull() ?: throw ProtocolException( - "Unexpected status line: $statusLine" + "Unexpected status line: $statusLine", ) // Parse an optional response message like "OK" or "Not Modified". If it diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt b/okhttp/src/main/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt index 47b868b2e254..43003c7fc966 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt @@ -65,16 +65,16 @@ class Http1ExchangeCodec( private val client: OkHttpClient?, override val carrier: ExchangeCodec.Carrier, private val source: BufferedSource, - private val sink: BufferedSink + private val sink: BufferedSink, ) : ExchangeCodec { private var state = STATE_IDLE private val headersReader = HeadersReader(source) private val Response.isChunked: Boolean - get() = "chunked".equals(header("Transfer-Encoding"), ignoreCase = true) + get() = "chunked".equals(header("Transfer-Encoding"), ignoreCase = true) private val Request.isChunked: Boolean - get() = "chunked".equals(header("Transfer-Encoding"), ignoreCase = true) + get() = "chunked".equals(header("Transfer-Encoding"), ignoreCase = true) /** * Received trailers. Null unless the response body uses chunked transfer-encoding and includes @@ -86,15 +86,20 @@ class Http1ExchangeCodec( val isClosed: Boolean get() = state == STATE_CLOSED - override fun createRequestBody(request: Request, contentLength: Long): Sink { + override fun createRequestBody( + request: Request, + contentLength: Long, + ): Sink { return when { request.body?.isDuplex() == true -> throw ProtocolException( - "Duplex connections are not supported for HTTP/1") + "Duplex connections are not supported for HTTP/1", + ) request.isChunked -> newChunkedSink() // Stream a request body of unknown length. contentLength != -1L -> newKnownLengthSink() // Stream a request body of a known length. else -> // Stream a request body of a known length. throw IllegalStateException( - "Cannot stream a request body without chunked encoding or a known content length!") + "Cannot stream a request body without chunked encoding or a known content length!", + ) } } @@ -154,30 +159,36 @@ class Http1ExchangeCodec( } /** Returns bytes of a request header for sending on an HTTP transport. */ - fun writeRequest(headers: Headers, requestLine: String) { + fun writeRequest( + headers: Headers, + requestLine: String, + ) { check(state == STATE_IDLE) { "state: $state" } sink.writeUtf8(requestLine).writeUtf8("\r\n") for (i in 0 until headers.size) { sink.writeUtf8(headers.name(i)) - .writeUtf8(": ") - .writeUtf8(headers.value(i)) - .writeUtf8("\r\n") + .writeUtf8(": ") + .writeUtf8(headers.value(i)) + .writeUtf8("\r\n") } sink.writeUtf8("\r\n") state = STATE_OPEN_REQUEST_BODY } override fun readResponseHeaders(expectContinue: Boolean): Response.Builder? { - check(state == STATE_OPEN_REQUEST_BODY || + check( + state == STATE_OPEN_REQUEST_BODY || state == STATE_WRITING_REQUEST_BODY || - state == STATE_READ_RESPONSE_HEADERS) { + state == STATE_READ_RESPONSE_HEADERS, + ) { "state: $state" } try { val statusLine = StatusLine.parse(headersReader.readLine()) - val responseBuilder = Response.Builder() + val responseBuilder = + Response.Builder() .protocol(statusLine.protocol) .code(statusLine.code) .message(statusLine.message) @@ -272,7 +283,10 @@ class Http1ExchangeCodec( override fun timeout(): Timeout = timeout - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { check(!closed) { "closed" } checkOffsetAndCount(source.size, 0, byteCount) sink.write(source, byteCount) @@ -301,7 +315,10 @@ class Http1ExchangeCodec( override fun timeout(): Timeout = timeout - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { check(!closed) { "closed" } if (byteCount == 0L) return @@ -333,7 +350,10 @@ class Http1ExchangeCodec( override fun timeout(): Timeout = timeout - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { return try { source.read(sink, byteCount) } catch (e: IOException) { @@ -359,15 +379,17 @@ class Http1ExchangeCodec( /** An HTTP body with a fixed length specified in advance. */ private inner class FixedLengthSource(private var bytesRemaining: Long) : - AbstractSource() { - + AbstractSource() { init { if (bytesRemaining == 0L) { responseBodyComplete() } } - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { require(byteCount >= 0L) { "byteCount < 0: $byteCount" } check(!closed) { "closed" } if (bytesRemaining == 0L) return -1 @@ -391,7 +413,8 @@ class Http1ExchangeCodec( if (closed) return if (bytesRemaining != 0L && - !discard(ExchangeCodec.DISCARD_STREAM_TIMEOUT_MILLIS, MILLISECONDS)) { + !discard(ExchangeCodec.DISCARD_STREAM_TIMEOUT_MILLIS, MILLISECONDS) + ) { carrier.noNewExchanges() // Unread bytes remain on the stream. responseBodyComplete() } @@ -402,11 +425,14 @@ class Http1ExchangeCodec( /** An HTTP body with alternating chunk sizes and chunk bodies. */ private inner class ChunkedSource(private val url: HttpUrl) : - AbstractSource() { + AbstractSource() { private var bytesRemainingInChunk = NO_CHUNK_YET private var hasMoreChunks = true - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { require(byteCount >= 0L) { "byteCount < 0: $byteCount" } check(!closed) { "closed" } if (!hasMoreChunks) return -1 @@ -436,8 +462,10 @@ class Http1ExchangeCodec( bytesRemainingInChunk = source.readHexadecimalUnsignedLong() val extensions = source.readUtf8LineStrict().trim() if (bytesRemainingInChunk < 0L || extensions.isNotEmpty() && !extensions.startsWith(";")) { - throw ProtocolException("expected chunk size and optional extensions" + - " but was \"$bytesRemainingInChunk$extensions\"") + throw ProtocolException( + "expected chunk size and optional extensions" + + " but was \"$bytesRemainingInChunk$extensions\"", + ) } } catch (e: NumberFormatException) { throw ProtocolException(e.message) @@ -454,7 +482,8 @@ class Http1ExchangeCodec( override fun close() { if (closed) return if (hasMoreChunks && - !discard(ExchangeCodec.DISCARD_STREAM_TIMEOUT_MILLIS, MILLISECONDS)) { + !discard(ExchangeCodec.DISCARD_STREAM_TIMEOUT_MILLIS, MILLISECONDS) + ) { carrier.noNewExchanges() // Unread bytes remain on the stream. responseBodyComplete() } @@ -466,7 +495,10 @@ class Http1ExchangeCodec( private inner class UnknownLengthSource : AbstractSource() { private var inputExhausted: Boolean = false - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { require(byteCount >= 0L) { "byteCount < 0: $byteCount" } check(!closed) { "closed" } if (inputExhausted) return -1 diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/ErrorCode.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/ErrorCode.kt index 15caaca23700..cfe3d00d6a48 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/ErrorCode.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/ErrorCode.kt @@ -44,7 +44,8 @@ enum class ErrorCode constructor(val httpCode: Int) { INADEQUATE_SECURITY(0xc), - HTTP_1_1_REQUIRED(0xd); + HTTP_1_1_REQUIRED(0xd), + ; companion object { fun fromHttp2(code: Int): ErrorCode? = values().find { it.httpCode == code } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/FlowControlListener.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/FlowControlListener.kt index 194445dfdd9d..78ed4507dde7 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/FlowControlListener.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/FlowControlListener.kt @@ -22,7 +22,11 @@ interface FlowControlListener { * Notification that the receiving stream flow control window has changed. * [WindowCounter] generally carries the client view of total and acked bytes. */ - fun receivingStreamWindowChanged(streamId: Int, windowCounter: WindowCounter, bufferSize: Long) + fun receivingStreamWindowChanged( + streamId: Int, + windowCounter: WindowCounter, + bufferSize: Long, + ) /** * Notification that the receiving connection flow control window has changed. @@ -31,8 +35,12 @@ interface FlowControlListener { fun receivingConnectionWindowChanged(windowCounter: WindowCounter) /** Noop implementation */ - object None: FlowControlListener { - override fun receivingStreamWindowChanged(streamId: Int, windowCounter: WindowCounter, bufferSize: Long) { + object None : FlowControlListener { + override fun receivingStreamWindowChanged( + streamId: Int, + windowCounter: WindowCounter, + bufferSize: Long, + ) { } override fun receivingConnectionWindowChanged(windowCounter: WindowCounter) { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Header.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Header.kt index a33662c046bf..527859058326 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Header.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Header.kt @@ -23,7 +23,7 @@ data class Header( /** Name in case-insensitive ASCII encoding. */ @JvmField val name: ByteString, /** Value in UTF-8 encoding. */ - @JvmField val value: ByteString + @JvmField val value: ByteString, ) { @JvmField val hpackSize = 32 + name.size + value.size @@ -45,9 +45,13 @@ data class Header( const val TARGET_AUTHORITY_UTF8 = ":authority" @JvmField val RESPONSE_STATUS: ByteString = RESPONSE_STATUS_UTF8.encodeUtf8() + @JvmField val TARGET_METHOD: ByteString = TARGET_METHOD_UTF8.encodeUtf8() + @JvmField val TARGET_PATH: ByteString = TARGET_PATH_UTF8.encodeUtf8() + @JvmField val TARGET_SCHEME: ByteString = TARGET_SCHEME_UTF8.encodeUtf8() + @JvmField val TARGET_AUTHORITY: ByteString = TARGET_AUTHORITY_UTF8.encodeUtf8() } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Hpack.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Hpack.kt index 8407c8118821..c03aa5f48a44 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Hpack.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Hpack.kt @@ -54,7 +54,8 @@ object Hpack { */ private const val SETTINGS_HEADER_TABLE_SIZE_LIMIT = 16_384 - val STATIC_HEADER_TABLE = arrayOf( + val STATIC_HEADER_TABLE = + arrayOf( Header(TARGET_AUTHORITY, ""), Header(TARGET_METHOD, "GET"), Header(TARGET_METHOD, "POST"), @@ -115,269 +116,285 @@ object Hpack { Header("user-agent", ""), Header("vary", ""), Header("via", ""), - Header("www-authenticate", "") - ) + Header("www-authenticate", ""), + ) val NAME_TO_FIRST_INDEX = nameToFirstIndex() // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-3.1 - class Reader @JvmOverloads constructor( - source: Source, - private val headerTableSizeSetting: Int, - private var maxDynamicTableByteCount: Int = headerTableSizeSetting - ) { - private val headerList = mutableListOf
() - private val source: BufferedSource = source.buffer() - - // Visible for testing. - @JvmField var dynamicTable = arrayOfNulls
(8) - // Array is populated back to front, so new entries always have lowest index. - private var nextHeaderIndex = dynamicTable.size - 1 - @JvmField var headerCount = 0 - @JvmField var dynamicTableByteCount = 0 - - fun getAndResetHeaderList(): List
{ - val result = headerList.toList() - headerList.clear() - return result - } + class Reader + @JvmOverloads + constructor( + source: Source, + private val headerTableSizeSetting: Int, + private var maxDynamicTableByteCount: Int = headerTableSizeSetting, + ) { + private val headerList = mutableListOf
() + private val source: BufferedSource = source.buffer() + + // Visible for testing. + @JvmField var dynamicTable = arrayOfNulls
(8) + + // Array is populated back to front, so new entries always have lowest index. + private var nextHeaderIndex = dynamicTable.size - 1 + + @JvmField var headerCount = 0 + + @JvmField var dynamicTableByteCount = 0 + + fun getAndResetHeaderList(): List
{ + val result = headerList.toList() + headerList.clear() + return result + } - fun maxDynamicTableByteCount(): Int = maxDynamicTableByteCount + fun maxDynamicTableByteCount(): Int = maxDynamicTableByteCount - private fun adjustDynamicTableByteCount() { - if (maxDynamicTableByteCount < dynamicTableByteCount) { - if (maxDynamicTableByteCount == 0) { - clearDynamicTable() - } else { - evictToRecoverBytes(dynamicTableByteCount - maxDynamicTableByteCount) + private fun adjustDynamicTableByteCount() { + if (maxDynamicTableByteCount < dynamicTableByteCount) { + if (maxDynamicTableByteCount == 0) { + clearDynamicTable() + } else { + evictToRecoverBytes(dynamicTableByteCount - maxDynamicTableByteCount) + } } } - } - private fun clearDynamicTable() { - dynamicTable.fill(null) - nextHeaderIndex = dynamicTable.size - 1 - headerCount = 0 - dynamicTableByteCount = 0 - } + private fun clearDynamicTable() { + dynamicTable.fill(null) + nextHeaderIndex = dynamicTable.size - 1 + headerCount = 0 + dynamicTableByteCount = 0 + } - /** Returns the count of entries evicted. */ - private fun evictToRecoverBytes(bytesToRecover: Int): Int { - var bytesToRecover = bytesToRecover - var entriesToEvict = 0 - if (bytesToRecover > 0) { - // determine how many headers need to be evicted. - var j = dynamicTable.size - 1 - while (j >= nextHeaderIndex && bytesToRecover > 0) { - val toEvict = dynamicTable[j]!! - bytesToRecover -= toEvict.hpackSize - dynamicTableByteCount -= toEvict.hpackSize - headerCount-- - entriesToEvict++ - j-- + /** Returns the count of entries evicted. */ + private fun evictToRecoverBytes(bytesToRecover: Int): Int { + var bytesToRecover = bytesToRecover + var entriesToEvict = 0 + if (bytesToRecover > 0) { + // determine how many headers need to be evicted. + var j = dynamicTable.size - 1 + while (j >= nextHeaderIndex && bytesToRecover > 0) { + val toEvict = dynamicTable[j]!! + bytesToRecover -= toEvict.hpackSize + dynamicTableByteCount -= toEvict.hpackSize + headerCount-- + entriesToEvict++ + j-- + } + System.arraycopy( + dynamicTable, + nextHeaderIndex + 1, + dynamicTable, + nextHeaderIndex + 1 + entriesToEvict, + headerCount, + ) + nextHeaderIndex += entriesToEvict } - System.arraycopy(dynamicTable, nextHeaderIndex + 1, dynamicTable, - nextHeaderIndex + 1 + entriesToEvict, headerCount) - nextHeaderIndex += entriesToEvict + return entriesToEvict } - return entriesToEvict - } - /** - * Read `byteCount` bytes of headers from the source stream. This implementation does not - * propagate the never indexed flag of a header. - */ - @Throws(IOException::class) - fun readHeaders() { - while (!source.exhausted()) { - val b = source.readByte() and 0xff - when { - b == 0x80 -> { - // 10000000 - throw IOException("index == 0") - } - b and 0x80 == 0x80 -> { - // 1NNNNNNN - val index = readInt(b, PREFIX_7_BITS) - readIndexedHeader(index - 1) - } - b == 0x40 -> { - // 01000000 - readLiteralHeaderWithIncrementalIndexingNewName() - } - b and 0x40 == 0x40 -> { - // 01NNNNNN - val index = readInt(b, PREFIX_6_BITS) - readLiteralHeaderWithIncrementalIndexingIndexedName(index - 1) - } - b and 0x20 == 0x20 -> { - // 001NNNNN - maxDynamicTableByteCount = readInt(b, PREFIX_5_BITS) - if (maxDynamicTableByteCount < 0 || maxDynamicTableByteCount > headerTableSizeSetting) { - throw IOException("Invalid dynamic table size update $maxDynamicTableByteCount") + /** + * Read `byteCount` bytes of headers from the source stream. This implementation does not + * propagate the never indexed flag of a header. + */ + @Throws(IOException::class) + fun readHeaders() { + while (!source.exhausted()) { + val b = source.readByte() and 0xff + when { + b == 0x80 -> { + // 10000000 + throw IOException("index == 0") + } + b and 0x80 == 0x80 -> { + // 1NNNNNNN + val index = readInt(b, PREFIX_7_BITS) + readIndexedHeader(index - 1) + } + b == 0x40 -> { + // 01000000 + readLiteralHeaderWithIncrementalIndexingNewName() + } + b and 0x40 == 0x40 -> { + // 01NNNNNN + val index = readInt(b, PREFIX_6_BITS) + readLiteralHeaderWithIncrementalIndexingIndexedName(index - 1) + } + b and 0x20 == 0x20 -> { + // 001NNNNN + maxDynamicTableByteCount = readInt(b, PREFIX_5_BITS) + if (maxDynamicTableByteCount < 0 || maxDynamicTableByteCount > headerTableSizeSetting) { + throw IOException("Invalid dynamic table size update $maxDynamicTableByteCount") + } + adjustDynamicTableByteCount() + } + b == 0x10 || b == 0 -> { + // 000?0000 - Ignore never indexed bit. + readLiteralHeaderWithoutIndexingNewName() + } + else -> { + // 000?NNNN - Ignore never indexed bit. + val index = readInt(b, PREFIX_4_BITS) + readLiteralHeaderWithoutIndexingIndexedName(index - 1) } - adjustDynamicTableByteCount() - } - b == 0x10 || b == 0 -> { - // 000?0000 - Ignore never indexed bit. - readLiteralHeaderWithoutIndexingNewName() - } - else -> { - // 000?NNNN - Ignore never indexed bit. - val index = readInt(b, PREFIX_4_BITS) - readLiteralHeaderWithoutIndexingIndexedName(index - 1) } } } - } - @Throws(IOException::class) - private fun readIndexedHeader(index: Int) { - if (isStaticHeader(index)) { - val staticEntry = STATIC_HEADER_TABLE[index] - headerList.add(staticEntry) - } else { - val dynamicTableIndex = dynamicTableIndex(index - STATIC_HEADER_TABLE.size) - if (dynamicTableIndex < 0 || dynamicTableIndex >= dynamicTable.size) { - throw IOException("Header index too large ${index + 1}") + @Throws(IOException::class) + private fun readIndexedHeader(index: Int) { + if (isStaticHeader(index)) { + val staticEntry = STATIC_HEADER_TABLE[index] + headerList.add(staticEntry) + } else { + val dynamicTableIndex = dynamicTableIndex(index - STATIC_HEADER_TABLE.size) + if (dynamicTableIndex < 0 || dynamicTableIndex >= dynamicTable.size) { + throw IOException("Header index too large ${index + 1}") + } + headerList += dynamicTable[dynamicTableIndex]!! } - headerList += dynamicTable[dynamicTableIndex]!! } - } - // referencedHeaders is relative to nextHeaderIndex + 1. - private fun dynamicTableIndex(index: Int): Int { - return nextHeaderIndex + 1 + index - } + // referencedHeaders is relative to nextHeaderIndex + 1. + private fun dynamicTableIndex(index: Int): Int { + return nextHeaderIndex + 1 + index + } - @Throws(IOException::class) - private fun readLiteralHeaderWithoutIndexingIndexedName(index: Int) { - val name = getName(index) - val value = readByteString() - headerList.add(Header(name, value)) - } + @Throws(IOException::class) + private fun readLiteralHeaderWithoutIndexingIndexedName(index: Int) { + val name = getName(index) + val value = readByteString() + headerList.add(Header(name, value)) + } - @Throws(IOException::class) - private fun readLiteralHeaderWithoutIndexingNewName() { - val name = checkLowercase(readByteString()) - val value = readByteString() - headerList.add(Header(name, value)) - } + @Throws(IOException::class) + private fun readLiteralHeaderWithoutIndexingNewName() { + val name = checkLowercase(readByteString()) + val value = readByteString() + headerList.add(Header(name, value)) + } - @Throws(IOException::class) - private fun readLiteralHeaderWithIncrementalIndexingIndexedName(nameIndex: Int) { - val name = getName(nameIndex) - val value = readByteString() - insertIntoDynamicTable(-1, Header(name, value)) - } + @Throws(IOException::class) + private fun readLiteralHeaderWithIncrementalIndexingIndexedName(nameIndex: Int) { + val name = getName(nameIndex) + val value = readByteString() + insertIntoDynamicTable(-1, Header(name, value)) + } - @Throws(IOException::class) - private fun readLiteralHeaderWithIncrementalIndexingNewName() { - val name = checkLowercase(readByteString()) - val value = readByteString() - insertIntoDynamicTable(-1, Header(name, value)) - } + @Throws(IOException::class) + private fun readLiteralHeaderWithIncrementalIndexingNewName() { + val name = checkLowercase(readByteString()) + val value = readByteString() + insertIntoDynamicTable(-1, Header(name, value)) + } - @Throws(IOException::class) - private fun getName(index: Int): ByteString { - return if (isStaticHeader(index)) { - STATIC_HEADER_TABLE[index].name - } else { - val dynamicTableIndex = dynamicTableIndex(index - STATIC_HEADER_TABLE.size) - if (dynamicTableIndex < 0 || dynamicTableIndex >= dynamicTable.size) { - throw IOException("Header index too large ${index + 1}") + @Throws(IOException::class) + private fun getName(index: Int): ByteString { + return if (isStaticHeader(index)) { + STATIC_HEADER_TABLE[index].name + } else { + val dynamicTableIndex = dynamicTableIndex(index - STATIC_HEADER_TABLE.size) + if (dynamicTableIndex < 0 || dynamicTableIndex >= dynamicTable.size) { + throw IOException("Header index too large ${index + 1}") + } + + dynamicTable[dynamicTableIndex]!!.name } + } - dynamicTable[dynamicTableIndex]!!.name + private fun isStaticHeader(index: Int): Boolean { + return index >= 0 && index <= STATIC_HEADER_TABLE.size - 1 } - } - private fun isStaticHeader(index: Int): Boolean { - return index >= 0 && index <= STATIC_HEADER_TABLE.size - 1 - } + /** index == -1 when new. */ + private fun insertIntoDynamicTable( + index: Int, + entry: Header, + ) { + var index = index + headerList.add(entry) + + var delta = entry.hpackSize + if (index != -1) { // Index -1 == new header. + delta -= dynamicTable[dynamicTableIndex(index)]!!.hpackSize + } - /** index == -1 when new. */ - private fun insertIntoDynamicTable(index: Int, entry: Header) { - var index = index - headerList.add(entry) + // if the new or replacement header is too big, drop all entries. + if (delta > maxDynamicTableByteCount) { + clearDynamicTable() + return + } - var delta = entry.hpackSize - if (index != -1) { // Index -1 == new header. - delta -= dynamicTable[dynamicTableIndex(index)]!!.hpackSize - } + // Evict headers to the required length. + val bytesToRecover = dynamicTableByteCount + delta - maxDynamicTableByteCount + val entriesEvicted = evictToRecoverBytes(bytesToRecover) - // if the new or replacement header is too big, drop all entries. - if (delta > maxDynamicTableByteCount) { - clearDynamicTable() - return + if (index == -1) { // Adding a value to the dynamic table. + if (headerCount + 1 > dynamicTable.size) { // Need to grow the dynamic table. + val doubled = arrayOfNulls
(dynamicTable.size * 2) + System.arraycopy(dynamicTable, 0, doubled, dynamicTable.size, dynamicTable.size) + nextHeaderIndex = dynamicTable.size - 1 + dynamicTable = doubled + } + index = nextHeaderIndex-- + dynamicTable[index] = entry + headerCount++ + } else { // Replace value at same position. + index += dynamicTableIndex(index) + entriesEvicted + dynamicTable[index] = entry + } + dynamicTableByteCount += delta } - // Evict headers to the required length. - val bytesToRecover = dynamicTableByteCount + delta - maxDynamicTableByteCount - val entriesEvicted = evictToRecoverBytes(bytesToRecover) - - if (index == -1) { // Adding a value to the dynamic table. - if (headerCount + 1 > dynamicTable.size) { // Need to grow the dynamic table. - val doubled = arrayOfNulls
(dynamicTable.size * 2) - System.arraycopy(dynamicTable, 0, doubled, dynamicTable.size, dynamicTable.size) - nextHeaderIndex = dynamicTable.size - 1 - dynamicTable = doubled - } - index = nextHeaderIndex-- - dynamicTable[index] = entry - headerCount++ - } else { // Replace value at same position. - index += dynamicTableIndex(index) + entriesEvicted - dynamicTable[index] = entry + @Throws(IOException::class) + private fun readByte(): Int { + return source.readByte() and 0xff } - dynamicTableByteCount += delta - } - @Throws(IOException::class) - private fun readByte(): Int { - return source.readByte() and 0xff - } + @Throws(IOException::class) + fun readInt( + firstByte: Int, + prefixMask: Int, + ): Int { + val prefix = firstByte and prefixMask + if (prefix < prefixMask) { + return prefix // This was a single byte value. + } - @Throws(IOException::class) - fun readInt(firstByte: Int, prefixMask: Int): Int { - val prefix = firstByte and prefixMask - if (prefix < prefixMask) { - return prefix // This was a single byte value. + // This is a multibyte value. Read 7 bits at a time. + var result = prefixMask + var shift = 0 + while (true) { + val b = readByte() + if (b and 0x80 != 0) { // Equivalent to (b >= 128) since b is in [0..255]. + result += b and 0x7f shl shift + shift += 7 + } else { + result += b shl shift // Last byte. + break + } + } + return result } - // This is a multibyte value. Read 7 bits at a time. - var result = prefixMask - var shift = 0 - while (true) { - val b = readByte() - if (b and 0x80 != 0) { // Equivalent to (b >= 128) since b is in [0..255]. - result += b and 0x7f shl shift - shift += 7 + /** Reads a potentially Huffman encoded byte string. */ + @Throws(IOException::class) + fun readByteString(): ByteString { + val firstByte = readByte() + val huffmanDecode = firstByte and 0x80 == 0x80 // 1NNNNNNN + val length = readInt(firstByte, PREFIX_7_BITS).toLong() + + return if (huffmanDecode) { + val decodeBuffer = Buffer() + Huffman.decode(source, length, decodeBuffer) + decodeBuffer.readByteString() } else { - result += b shl shift // Last byte. - break + source.readByteString(length) } } - return result } - /** Reads a potentially Huffman encoded byte string. */ - @Throws(IOException::class) - fun readByteString(): ByteString { - val firstByte = readByte() - val huffmanDecode = firstByte and 0x80 == 0x80 // 1NNNNNNN - val length = readInt(firstByte, PREFIX_7_BITS).toLong() - - return if (huffmanDecode) { - val decodeBuffer = Buffer() - Huffman.decode(source, length, decodeBuffer) - decodeBuffer.readByteString() - } else { - source.readByteString(length) - } - } - } - private fun nameToFirstIndex(): Map { val result = LinkedHashMap(STATIC_HEADER_TABLE.size) for (i in STATIC_HEADER_TABLE.indices) { @@ -388,222 +405,237 @@ object Hpack { return Collections.unmodifiableMap(result) } - class Writer @JvmOverloads constructor( - @JvmField var headerTableSizeSetting: Int = SETTINGS_HEADER_TABLE_SIZE, - private val useCompression: Boolean = true, - private val out: Buffer - ) { - /** - * In the scenario where the dynamic table size changes multiple times between transmission of - * header blocks, we need to keep track of the smallest value in that interval. - */ - private var smallestHeaderTableSizeSetting = Integer.MAX_VALUE - private var emitDynamicTableSizeUpdate: Boolean = false - @JvmField var maxDynamicTableByteCount: Int = headerTableSizeSetting - - // Visible for testing. - @JvmField var dynamicTable = arrayOfNulls
(8) - // Array is populated back to front, so new entries always have lowest index. - private var nextHeaderIndex = dynamicTable.size - 1 - @JvmField var headerCount = 0 - @JvmField var dynamicTableByteCount = 0 - - private fun clearDynamicTable() { - dynamicTable.fill(null) - nextHeaderIndex = dynamicTable.size - 1 - headerCount = 0 - dynamicTableByteCount = 0 - } + class Writer + @JvmOverloads + constructor( + @JvmField var headerTableSizeSetting: Int = SETTINGS_HEADER_TABLE_SIZE, + private val useCompression: Boolean = true, + private val out: Buffer, + ) { + /** + * In the scenario where the dynamic table size changes multiple times between transmission of + * header blocks, we need to keep track of the smallest value in that interval. + */ + private var smallestHeaderTableSizeSetting = Integer.MAX_VALUE + private var emitDynamicTableSizeUpdate: Boolean = false - /** Returns the count of entries evicted. */ - private fun evictToRecoverBytes(bytesToRecover: Int): Int { - var bytesToRecover = bytesToRecover - var entriesToEvict = 0 - if (bytesToRecover > 0) { - // determine how many headers need to be evicted. - var j = dynamicTable.size - 1 - while (j >= nextHeaderIndex && bytesToRecover > 0) { - bytesToRecover -= dynamicTable[j]!!.hpackSize - dynamicTableByteCount -= dynamicTable[j]!!.hpackSize - headerCount-- - entriesToEvict++ - j-- - } - System.arraycopy(dynamicTable, nextHeaderIndex + 1, dynamicTable, - nextHeaderIndex + 1 + entriesToEvict, headerCount) - Arrays.fill(dynamicTable, nextHeaderIndex + 1, nextHeaderIndex + 1 + entriesToEvict, null) - nextHeaderIndex += entriesToEvict - } - return entriesToEvict - } + @JvmField var maxDynamicTableByteCount: Int = headerTableSizeSetting - private fun insertIntoDynamicTable(entry: Header) { - val delta = entry.hpackSize + // Visible for testing. + @JvmField var dynamicTable = arrayOfNulls
(8) - // if the new or replacement header is too big, drop all entries. - if (delta > maxDynamicTableByteCount) { - clearDynamicTable() - return - } + // Array is populated back to front, so new entries always have lowest index. + private var nextHeaderIndex = dynamicTable.size - 1 - // Evict headers to the required length. - val bytesToRecover = dynamicTableByteCount + delta - maxDynamicTableByteCount - evictToRecoverBytes(bytesToRecover) + @JvmField var headerCount = 0 - if (headerCount + 1 > dynamicTable.size) { // Need to grow the dynamic table. - val doubled = arrayOfNulls
(dynamicTable.size * 2) - System.arraycopy(dynamicTable, 0, doubled, dynamicTable.size, dynamicTable.size) + @JvmField var dynamicTableByteCount = 0 + + private fun clearDynamicTable() { + dynamicTable.fill(null) nextHeaderIndex = dynamicTable.size - 1 - dynamicTable = doubled + headerCount = 0 + dynamicTableByteCount = 0 } - val index = nextHeaderIndex-- - dynamicTable[index] = entry - headerCount++ - dynamicTableByteCount += delta - } - /** - * This does not use "never indexed" semantics for sensitive headers. - * - * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-6.2.3 - */ - @Throws(IOException::class) - fun writeHeaders(headerBlock: List
) { - if (emitDynamicTableSizeUpdate) { - if (smallestHeaderTableSizeSetting < maxDynamicTableByteCount) { - // Multiple dynamic table size updates! - writeInt(smallestHeaderTableSizeSetting, PREFIX_5_BITS, 0x20) + /** Returns the count of entries evicted. */ + private fun evictToRecoverBytes(bytesToRecover: Int): Int { + var bytesToRecover = bytesToRecover + var entriesToEvict = 0 + if (bytesToRecover > 0) { + // determine how many headers need to be evicted. + var j = dynamicTable.size - 1 + while (j >= nextHeaderIndex && bytesToRecover > 0) { + bytesToRecover -= dynamicTable[j]!!.hpackSize + dynamicTableByteCount -= dynamicTable[j]!!.hpackSize + headerCount-- + entriesToEvict++ + j-- + } + System.arraycopy( + dynamicTable, + nextHeaderIndex + 1, + dynamicTable, + nextHeaderIndex + 1 + entriesToEvict, + headerCount, + ) + Arrays.fill(dynamicTable, nextHeaderIndex + 1, nextHeaderIndex + 1 + entriesToEvict, null) + nextHeaderIndex += entriesToEvict } - emitDynamicTableSizeUpdate = false - smallestHeaderTableSizeSetting = Integer.MAX_VALUE - writeInt(maxDynamicTableByteCount, PREFIX_5_BITS, 0x20) + return entriesToEvict } - for (i in 0 until headerBlock.size) { - val header = headerBlock[i] - val name = header.name.toAsciiLowercase() - val value = header.value - var headerIndex = -1 - var headerNameIndex = -1 - - val staticIndex = NAME_TO_FIRST_INDEX[name] - if (staticIndex != null) { - headerNameIndex = staticIndex + 1 - if (headerNameIndex in 2..7) { - // Only search a subset of the static header table. Most entries have an empty value, so - // it's unnecessary to waste cycles looking at them. This check is built on the - // observation that the header entries we care about are in adjacent pairs, and we - // always know the first index of the pair. - if (STATIC_HEADER_TABLE[headerNameIndex - 1].value == value) { - headerIndex = headerNameIndex - } else if (STATIC_HEADER_TABLE[headerNameIndex].value == value) { - headerIndex = headerNameIndex + 1 - } + private fun insertIntoDynamicTable(entry: Header) { + val delta = entry.hpackSize + + // if the new or replacement header is too big, drop all entries. + if (delta > maxDynamicTableByteCount) { + clearDynamicTable() + return + } + + // Evict headers to the required length. + val bytesToRecover = dynamicTableByteCount + delta - maxDynamicTableByteCount + evictToRecoverBytes(bytesToRecover) + + if (headerCount + 1 > dynamicTable.size) { // Need to grow the dynamic table. + val doubled = arrayOfNulls
(dynamicTable.size * 2) + System.arraycopy(dynamicTable, 0, doubled, dynamicTable.size, dynamicTable.size) + nextHeaderIndex = dynamicTable.size - 1 + dynamicTable = doubled + } + val index = nextHeaderIndex-- + dynamicTable[index] = entry + headerCount++ + dynamicTableByteCount += delta + } + + /** + * This does not use "never indexed" semantics for sensitive headers. + * + * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-6.2.3 + */ + @Throws(IOException::class) + fun writeHeaders(headerBlock: List
) { + if (emitDynamicTableSizeUpdate) { + if (smallestHeaderTableSizeSetting < maxDynamicTableByteCount) { + // Multiple dynamic table size updates! + writeInt(smallestHeaderTableSizeSetting, PREFIX_5_BITS, 0x20) } + emitDynamicTableSizeUpdate = false + smallestHeaderTableSizeSetting = Integer.MAX_VALUE + writeInt(maxDynamicTableByteCount, PREFIX_5_BITS, 0x20) } - if (headerIndex == -1) { - for (j in nextHeaderIndex + 1 until dynamicTable.size) { - if (dynamicTable[j]!!.name == name) { - if (dynamicTable[j]!!.value == value) { - headerIndex = j - nextHeaderIndex + STATIC_HEADER_TABLE.size - break - } else if (headerNameIndex == -1) { - headerNameIndex = j - nextHeaderIndex + STATIC_HEADER_TABLE.size + for (i in 0 until headerBlock.size) { + val header = headerBlock[i] + val name = header.name.toAsciiLowercase() + val value = header.value + var headerIndex = -1 + var headerNameIndex = -1 + + val staticIndex = NAME_TO_FIRST_INDEX[name] + if (staticIndex != null) { + headerNameIndex = staticIndex + 1 + if (headerNameIndex in 2..7) { + // Only search a subset of the static header table. Most entries have an empty value, so + // it's unnecessary to waste cycles looking at them. This check is built on the + // observation that the header entries we care about are in adjacent pairs, and we + // always know the first index of the pair. + if (STATIC_HEADER_TABLE[headerNameIndex - 1].value == value) { + headerIndex = headerNameIndex + } else if (STATIC_HEADER_TABLE[headerNameIndex].value == value) { + headerIndex = headerNameIndex + 1 } } } - } - when { - headerIndex != -1 -> { - // Indexed Header Field. - writeInt(headerIndex, PREFIX_7_BITS, 0x80) - } - headerNameIndex == -1 -> { - // Literal Header Field with Incremental Indexing - New Name. - out.writeByte(0x40) - writeByteString(name) - writeByteString(value) - insertIntoDynamicTable(header) - } - name.startsWith(Header.PSEUDO_PREFIX) && TARGET_AUTHORITY != name -> { - // Follow Chromes lead - only include the :authority pseudo header, but exclude all other - // pseudo headers. Literal Header Field without Indexing - Indexed Name. - writeInt(headerNameIndex, PREFIX_4_BITS, 0) - writeByteString(value) + if (headerIndex == -1) { + for (j in nextHeaderIndex + 1 until dynamicTable.size) { + if (dynamicTable[j]!!.name == name) { + if (dynamicTable[j]!!.value == value) { + headerIndex = j - nextHeaderIndex + STATIC_HEADER_TABLE.size + break + } else if (headerNameIndex == -1) { + headerNameIndex = j - nextHeaderIndex + STATIC_HEADER_TABLE.size + } + } + } } - else -> { - // Literal Header Field with Incremental Indexing - Indexed Name. - writeInt(headerNameIndex, PREFIX_6_BITS, 0x40) - writeByteString(value) - insertIntoDynamicTable(header) + + when { + headerIndex != -1 -> { + // Indexed Header Field. + writeInt(headerIndex, PREFIX_7_BITS, 0x80) + } + headerNameIndex == -1 -> { + // Literal Header Field with Incremental Indexing - New Name. + out.writeByte(0x40) + writeByteString(name) + writeByteString(value) + insertIntoDynamicTable(header) + } + name.startsWith(Header.PSEUDO_PREFIX) && TARGET_AUTHORITY != name -> { + // Follow Chromes lead - only include the :authority pseudo header, but exclude all other + // pseudo headers. Literal Header Field without Indexing - Indexed Name. + writeInt(headerNameIndex, PREFIX_4_BITS, 0) + writeByteString(value) + } + else -> { + // Literal Header Field with Incremental Indexing - Indexed Name. + writeInt(headerNameIndex, PREFIX_6_BITS, 0x40) + writeByteString(value) + insertIntoDynamicTable(header) + } } } } - } - // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-4.1.1 - fun writeInt(value: Int, prefixMask: Int, bits: Int) { - var value = value - // Write the raw value for a single byte value. - if (value < prefixMask) { - out.writeByte(bits or value) - return - } + // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-4.1.1 + fun writeInt( + value: Int, + prefixMask: Int, + bits: Int, + ) { + var value = value + // Write the raw value for a single byte value. + if (value < prefixMask) { + out.writeByte(bits or value) + return + } - // Write the mask to start a multibyte value. - out.writeByte(bits or prefixMask) - value -= prefixMask + // Write the mask to start a multibyte value. + out.writeByte(bits or prefixMask) + value -= prefixMask - // Write 7 bits at a time 'til we're done. - while (value >= 0x80) { - val b = value and 0x7f - out.writeByte(b or 0x80) - value = value ushr 7 + // Write 7 bits at a time 'til we're done. + while (value >= 0x80) { + val b = value and 0x7f + out.writeByte(b or 0x80) + value = value ushr 7 + } + out.writeByte(value) } - out.writeByte(value) - } - @Throws(IOException::class) - fun writeByteString(data: ByteString) { - if (useCompression && Huffman.encodedLength(data) < data.size) { - val huffmanBuffer = Buffer() - Huffman.encode(data, huffmanBuffer) - val huffmanBytes = huffmanBuffer.readByteString() - writeInt(huffmanBytes.size, PREFIX_7_BITS, 0x80) - out.write(huffmanBytes) - } else { - writeInt(data.size, PREFIX_7_BITS, 0) - out.write(data) + @Throws(IOException::class) + fun writeByteString(data: ByteString) { + if (useCompression && Huffman.encodedLength(data) < data.size) { + val huffmanBuffer = Buffer() + Huffman.encode(data, huffmanBuffer) + val huffmanBytes = huffmanBuffer.readByteString() + writeInt(huffmanBytes.size, PREFIX_7_BITS, 0x80) + out.write(huffmanBytes) + } else { + writeInt(data.size, PREFIX_7_BITS, 0) + out.write(data) + } } - } - fun resizeHeaderTable(headerTableSizeSetting: Int) { - this.headerTableSizeSetting = headerTableSizeSetting - val effectiveHeaderTableSize = minOf(headerTableSizeSetting, SETTINGS_HEADER_TABLE_SIZE_LIMIT) + fun resizeHeaderTable(headerTableSizeSetting: Int) { + this.headerTableSizeSetting = headerTableSizeSetting + val effectiveHeaderTableSize = minOf(headerTableSizeSetting, SETTINGS_HEADER_TABLE_SIZE_LIMIT) - if (maxDynamicTableByteCount == effectiveHeaderTableSize) return // No change. + if (maxDynamicTableByteCount == effectiveHeaderTableSize) return // No change. - if (effectiveHeaderTableSize < maxDynamicTableByteCount) { - smallestHeaderTableSizeSetting = + if (effectiveHeaderTableSize < maxDynamicTableByteCount) { + smallestHeaderTableSizeSetting = minOf(smallestHeaderTableSizeSetting, effectiveHeaderTableSize) + } + emitDynamicTableSizeUpdate = true + maxDynamicTableByteCount = effectiveHeaderTableSize + adjustDynamicTableByteCount() } - emitDynamicTableSizeUpdate = true - maxDynamicTableByteCount = effectiveHeaderTableSize - adjustDynamicTableByteCount() - } - private fun adjustDynamicTableByteCount() { - if (maxDynamicTableByteCount < dynamicTableByteCount) { - if (maxDynamicTableByteCount == 0) { - clearDynamicTable() - } else { - evictToRecoverBytes(dynamicTableByteCount - maxDynamicTableByteCount) + private fun adjustDynamicTableByteCount() { + if (maxDynamicTableByteCount < dynamicTableByteCount) { + if (maxDynamicTableByteCount == 0) { + clearDynamicTable() + } else { + evictToRecoverBytes(dynamicTableByteCount - maxDynamicTableByteCount) + } } } } - } /** * An HTTP/2 response cannot contain uppercase header characters and must be treated as diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2.kt index e022fa4dd05e..7f2b1435ab84 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2.kt @@ -46,19 +46,21 @@ object Http2 { const val FLAG_COMPRESSED = 0x20 // Used for data. /** Lookup table for valid frame types. */ - private val FRAME_NAMES = arrayOf( + private val FRAME_NAMES = + arrayOf( "DATA", "HEADERS", "PRIORITY", "RST_STREAM", "SETTINGS", "PUSH_PROMISE", "PING", "GOAWAY", - "WINDOW_UPDATE", "CONTINUATION" - ) + "WINDOW_UPDATE", "CONTINUATION", + ) /** * Lookup table for valid flags for DATA, HEADERS, CONTINUATION. Invalid combinations are * represented in binary. */ private val FLAGS = arrayOfNulls(0x40) // Highest bit flag is 0x20. - private val BINARY = Array(256) { - format("%8s", Integer.toBinaryString(it)).replace(' ', '0') - } + private val BINARY = + Array(256) { + format("%8s", Integer.toBinaryString(it)).replace(' ', '0') + } init { FLAGS[FLAG_NONE] = "" @@ -80,7 +82,7 @@ object Http2 { for (prefixFlag in prefixFlags) { FLAGS[prefixFlag or frameFlag] = FLAGS[prefixFlag] + '|'.toString() + FLAGS[frameFlag] FLAGS[prefixFlag or frameFlag or FLAG_PADDED] = - FLAGS[prefixFlag] + '|'.toString() + FLAGS[frameFlag] + "|PADDED" + FLAGS[prefixFlag] + '|'.toString() + FLAGS[frameFlag] + "|PADDED" } } @@ -110,13 +112,19 @@ object Http2 { streamId: Int, length: Int, type: Int, - flags: Int + flags: Int, ): String { val formattedType = formattedType(type) val formattedFlags = formatFlags(type, flags) val direction = if (inbound) "<<" else ">>" - return format("%s 0x%08x %5d %-13s %s", - direction, streamId, length, formattedType, formattedFlags) + return format( + "%s 0x%08x %5d %-13s %s", + direction, + streamId, + length, + formattedType, + formattedFlags, + ) } /** @@ -131,18 +139,26 @@ object Http2 { ): String { val formattedType = formattedType(TYPE_WINDOW_UPDATE) val direction = if (inbound) "<<" else ">>" - return format("%s 0x%08x %5d %-13s %d", - direction, streamId, length, formattedType, windowSizeIncrement) + return format( + "%s 0x%08x %5d %-13s %d", + direction, + streamId, + length, + formattedType, + windowSizeIncrement, + ) } - internal fun formattedType(type: Int): String = - if (type < FRAME_NAMES.size) FRAME_NAMES[type] else format("0x%02x", type) + internal fun formattedType(type: Int): String = if (type < FRAME_NAMES.size) FRAME_NAMES[type] else format("0x%02x", type) /** * Looks up valid string representing flags from the table. Invalid combinations are represented * in binary. */ - fun formatFlags(type: Int, flags: Int): String { + fun formatFlags( + type: Int, + flags: Int, + ): String { if (flags == 0) return "" when (type) { // Special case types that have 0 or 1 flag. diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt index 45d5aad00a7d..686568d3d0fd 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt @@ -54,7 +54,6 @@ import okio.source */ @Suppress("NAME_SHADOWING") class Http2Connection internal constructor(builder: Builder) : Closeable { - // Internal state of this connection is guarded by 'this'. No blocking operations may be // performed while holding this lock! // @@ -109,14 +108,15 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { internal val flowControlListener: FlowControlListener = builder.flowControlListener /** Settings we communicate to the peer. */ - val okHttpSettings = Settings().apply { - // Flow control was designed more for servers, or proxies than edge clients. If we are a client, - // set the flow control window to 16MiB. This avoids thrashing window updates every 64KiB, yet - // small enough to avoid blowing up the heap. - if (builder.client) { - set(Settings.INITIAL_WINDOW_SIZE, OKHTTP_CLIENT_WINDOW_SIZE) + val okHttpSettings = + Settings().apply { + // Flow control was designed more for servers, or proxies than edge clients. If we are a client, + // set the flow control window to 16MiB. This avoids thrashing window updates every 64KiB, yet + // small enough to avoid blowing up the heap. + if (builder.client) { + set(Settings.INITIAL_WINDOW_SIZE, OKHTTP_CLIENT_WINDOW_SIZE) + } } - } /** * Settings we receive from the peer. Changes to the field are guarded by this. The instance is @@ -148,14 +148,15 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { if (builder.pingIntervalMillis != 0) { val pingIntervalNanos = TimeUnit.MILLISECONDS.toNanos(builder.pingIntervalMillis.toLong()) writerQueue.schedule("$connectionName ping", pingIntervalNanos) { - val failDueToMissingPong = synchronized(this@Http2Connection) { - if (intervalPongsReceived < intervalPingsSent) { - return@synchronized true - } else { - intervalPingsSent++ - return@synchronized false + val failDueToMissingPong = + synchronized(this@Http2Connection) { + if (intervalPongsReceived < intervalPingsSent) { + return@synchronized true + } else { + intervalPingsSent++ + return@synchronized false + } } - } if (failDueToMissingPong) { failConnection(null) return@schedule -1L @@ -207,7 +208,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { fun pushStream( associatedStreamId: Int, requestHeaders: List
, - out: Boolean + out: Boolean, ): Http2Stream { check(!client) { "Client cannot push requests." } return newStream(associatedStreamId, requestHeaders, out) @@ -222,7 +223,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { @Throws(IOException::class) fun newStream( requestHeaders: List
, - out: Boolean + out: Boolean, ): Http2Stream { return newStream(0, requestHeaders, out) } @@ -231,7 +232,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { private fun newStream( associatedStreamId: Int, requestHeaders: List
, - out: Boolean + out: Boolean, ): Http2Stream { val outFinished = !out val inFinished = false @@ -277,7 +278,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { internal fun writeHeaders( streamId: Int, outFinished: Boolean, - alternating: List
+ alternating: List
, ) { writer.headers(outFinished, streamId, alternating) } @@ -299,7 +300,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { streamId: Int, outFinished: Boolean, buffer: Buffer?, - byteCount: Long + byteCount: Long, ) { // Empty data frames are not flow-controlled. if (byteCount == 0L) { @@ -337,7 +338,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { internal fun writeSynResetLater( streamId: Int, - errorCode: ErrorCode + errorCode: ErrorCode, ) { writerQueue.execute("$connectionName[$streamId] writeSynReset") { try { @@ -351,14 +352,14 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { @Throws(IOException::class) internal fun writeSynReset( streamId: Int, - statusCode: ErrorCode + statusCode: ErrorCode, ) { writer.rstStream(streamId, statusCode) } internal fun writeWindowUpdateLater( streamId: Int, - unacknowledgedBytesRead: Long + unacknowledgedBytesRead: Long, ) { writerQueue.execute("$connectionName[$streamId] windowUpdate") { try { @@ -372,7 +373,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { fun writePing( reply: Boolean, payload1: Int, - payload2: Int + payload2: Int, ) { try { writer.ping(reply, payload1, payload2) @@ -395,12 +396,13 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { awaitPingsSent++ } - /* 0x4f 0x4b 0x6f 0x6b is "OKok". */ + // 0x4f 0x4b 0x6f 0x6b is "OKok". writePing(false, AWAIT_PING, 0x4f4b6f6b) } /** For testing: awaits a pong. */ - @Synchronized @Throws(InterruptedException::class) + @Synchronized + @Throws(InterruptedException::class) fun awaitPong() { while (awaitPongsReceived < awaitPingsSent) { wait() @@ -445,7 +447,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { internal fun close( connectionCode: ErrorCode, streamCode: ErrorCode, - cause: IOException? + cause: IOException?, ) { this.assertThreadDoesntHoldLock() @@ -495,7 +497,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { * except for in tests that don't check for a connection preface. * @param taskRunner the TaskRunner to use, daemon by default. */ - @Throws(IOException::class) @JvmOverloads + @Throws(IOException::class) + @JvmOverloads fun start(sendConnectionPreface: Boolean = true) { if (sendConnectionPreface) { writer.connectionPreface() @@ -563,7 +566,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { class Builder( /** True if this peer initiated the connection; false if this peer accepted the connection. */ internal var client: Boolean, - internal val taskRunner: TaskRunner + internal val taskRunner: TaskRunner, ) { internal lateinit var socket: Socket internal lateinit var connectionName: String @@ -574,37 +577,43 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { internal var pingIntervalMillis: Int = 0 internal var flowControlListener: FlowControlListener = FlowControlListener.None - @Throws(IOException::class) @JvmOverloads + @Throws(IOException::class) + @JvmOverloads fun socket( socket: Socket, peerName: String = socket.peerName(), source: BufferedSource = socket.source().buffer(), - sink: BufferedSink = socket.sink().buffer() + sink: BufferedSink = socket.sink().buffer(), ) = apply { this.socket = socket - this.connectionName = when { - client -> "$okHttpName $peerName" - else -> "MockWebServer $peerName" - } + this.connectionName = + when { + client -> "$okHttpName $peerName" + else -> "MockWebServer $peerName" + } this.source = source this.sink = sink } - fun listener(listener: Listener) = apply { - this.listener = listener - } + fun listener(listener: Listener) = + apply { + this.listener = listener + } - fun pushObserver(pushObserver: PushObserver) = apply { - this.pushObserver = pushObserver - } + fun pushObserver(pushObserver: PushObserver) = + apply { + this.pushObserver = pushObserver + } - fun pingIntervalMillis(pingIntervalMillis: Int) = apply { - this.pingIntervalMillis = pingIntervalMillis - } + fun pingIntervalMillis(pingIntervalMillis: Int) = + apply { + this.pingIntervalMillis = pingIntervalMillis + } - fun flowControlListener(flowControlListener: FlowControlListener) = apply { - this.flowControlListener = flowControlListener - } + fun flowControlListener(flowControlListener: FlowControlListener) = + apply { + this.flowControlListener = flowControlListener + } fun build(): Http2Connection { return Http2Connection(this) @@ -616,7 +625,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { * async task to do so. */ inner class ReaderRunnable internal constructor( - internal val reader: Http2Reader + internal val reader: Http2Reader, ) : Http2Reader.Handler, () -> Unit { override fun invoke() { var connectionErrorCode = ErrorCode.INTERNAL_ERROR @@ -643,7 +652,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { inFinished: Boolean, streamId: Int, source: BufferedSource, - length: Int + length: Int, ) { if (pushedStream(streamId)) { pushDataLater(streamId, source, length, inFinished) @@ -666,7 +675,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { inFinished: Boolean, streamId: Int, associatedStreamId: Int, - headerBlock: List
+ headerBlock: List
, ) { if (pushedStream(streamId)) { pushHeadersLater(streamId, headerBlock, inFinished) @@ -711,7 +720,10 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { stream!!.receiveHeaders(headerBlock.toHeaders(), inFinished) } - override fun rstStream(streamId: Int, errorCode: ErrorCode) { + override fun rstStream( + streamId: Int, + errorCode: ErrorCode, + ) { if (pushedStream(streamId)) { pushResetLater(streamId, errorCode) return @@ -720,7 +732,10 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { rstStream?.receiveRstStream(errorCode) } - override fun settings(clearPrevious: Boolean, settings: Settings) { + override fun settings( + clearPrevious: Boolean, + settings: Settings, + ) { writerQueue.execute("$connectionName applyAndAckSettings") { applyAndAckSettings(clearPrevious, settings) } @@ -739,28 +754,33 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { * writer task queue won't reorder tasks; otherwise settings could be applied in the opposite * order than received. */ - fun applyAndAckSettings(clearPrevious: Boolean, settings: Settings) { + fun applyAndAckSettings( + clearPrevious: Boolean, + settings: Settings, + ) { var delta: Long var streamsToNotify: Array? var newPeerSettings: Settings synchronized(writer) { synchronized(this@Http2Connection) { val previousPeerSettings = peerSettings - newPeerSettings = if (clearPrevious) { - settings - } else { - Settings().apply { - merge(previousPeerSettings) - merge(settings) + newPeerSettings = + if (clearPrevious) { + settings + } else { + Settings().apply { + merge(previousPeerSettings) + merge(settings) + } } - } val peerInitialWindowSize = newPeerSettings.initialWindowSize.toLong() delta = peerInitialWindowSize - previousPeerSettings.initialWindowSize.toLong() - streamsToNotify = when { - delta == 0L || streams.isEmpty() -> null // No adjustment is necessary. - else -> streams.values.toTypedArray() - } + streamsToNotify = + when { + delta == 0L || streams.isEmpty() -> null // No adjustment is necessary. + else -> streams.values.toTypedArray() + } peerSettings = newPeerSettings @@ -790,7 +810,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { override fun ping( ack: Boolean, payload1: Int, - payload2: Int + payload2: Int, ) { if (ack) { synchronized(this@Http2Connection) { @@ -821,7 +841,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { override fun goAway( lastGoodStreamId: Int, errorCode: ErrorCode, - debugData: ByteString + debugData: ByteString, ) { if (debugData.size > 0) { // TODO: log the debugData @@ -843,7 +863,10 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } } - override fun windowUpdate(streamId: Int, windowSizeIncrement: Long) { + override fun windowUpdate( + streamId: Int, + windowSizeIncrement: Long, + ) { if (streamId == 0) { synchronized(this@Http2Connection) { writeBytesMaximum += windowSizeIncrement @@ -863,7 +886,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { streamId: Int, streamDependency: Int, weight: Int, - exclusive: Boolean + exclusive: Boolean, ) { // TODO: honor priority. } @@ -871,7 +894,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { override fun pushPromise( streamId: Int, promisedStreamId: Int, - requestHeaders: List
+ requestHeaders: List
, ) { pushRequestLater(promisedStreamId, requestHeaders) } @@ -882,7 +905,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { protocol: ByteString, host: String, port: Int, - maxAge: Long + maxAge: Long, ) { // TODO: register alternate service. } @@ -891,7 +914,10 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** Even, positive numbered streams are pushed streams in HTTP/2. */ internal fun pushedStream(streamId: Int): Boolean = streamId != 0 && streamId and 1 == 0 - internal fun pushRequestLater(streamId: Int, requestHeaders: List
) { + internal fun pushRequestLater( + streamId: Int, + requestHeaders: List
, + ) { synchronized(this) { if (streamId in currentPushRequests) { writeSynResetLater(streamId, ErrorCode.PROTOCOL_ERROR) @@ -915,7 +941,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { internal fun pushHeadersLater( streamId: Int, requestHeaders: List
, - inFinished: Boolean + inFinished: Boolean, ) { pushQueue.execute("$connectionName[$streamId] onHeaders") { val cancel = pushObserver.onHeaders(streamId, requestHeaders, inFinished) @@ -939,7 +965,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { streamId: Int, source: BufferedSource, byteCount: Int, - inFinished: Boolean + inFinished: Boolean, ) { val buffer = Buffer() source.require(byteCount.toLong()) // Eagerly read the frame before firing client thread. @@ -957,7 +983,10 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } } - internal fun pushResetLater(streamId: Int, errorCode: ErrorCode) { + internal fun pushResetLater( + streamId: Int, + errorCode: ErrorCode, + ) { pushQueue.execute("$connectionName[$streamId] onReset") { pushObserver.onReset(streamId, errorCode) synchronized(this@Http2Connection) { @@ -985,26 +1014,31 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { * Methods to this method may be made concurrently with [onStream]. But a calls to this method * are serialized. */ - open fun onSettings(connection: Http2Connection, settings: Settings) {} + open fun onSettings( + connection: Http2Connection, + settings: Settings, + ) {} companion object { @JvmField - val REFUSE_INCOMING_STREAMS: Listener = object : Listener() { - @Throws(IOException::class) - override fun onStream(stream: Http2Stream) { - stream.close(REFUSED_STREAM, null) + val REFUSE_INCOMING_STREAMS: Listener = + object : Listener() { + @Throws(IOException::class) + override fun onStream(stream: Http2Stream) { + stream.close(REFUSED_STREAM, null) + } } - } } } companion object { const val OKHTTP_CLIENT_WINDOW_SIZE = 16 * 1024 * 1024 - val DEFAULT_SETTINGS = Settings().apply { - set(Settings.INITIAL_WINDOW_SIZE, DEFAULT_INITIAL_WINDOW_SIZE) - set(Settings.MAX_FRAME_SIZE, Http2.INITIAL_MAX_FRAME_SIZE) - } + val DEFAULT_SETTINGS = + Settings().apply { + set(Settings.INITIAL_WINDOW_SIZE, DEFAULT_INITIAL_WINDOW_SIZE) + set(Settings.MAX_FRAME_SIZE, Http2.INITIAL_MAX_FRAME_SIZE) + } const val INTERVAL_PING = 1 const val DEGRADED_PING = 2 diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt index baf5ff0c11f7..b56a0355d5d4 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt @@ -50,20 +50,24 @@ class Http2ExchangeCodec( client: OkHttpClient, override val carrier: Carrier, private val chain: RealInterceptorChain, - private val http2Connection: Http2Connection + private val http2Connection: Http2Connection, ) : ExchangeCodec { @Volatile private var stream: Http2Stream? = null - private val protocol: Protocol = if (Protocol.H2_PRIOR_KNOWLEDGE in client.protocols) { - Protocol.H2_PRIOR_KNOWLEDGE - } else { - Protocol.HTTP_2 - } + private val protocol: Protocol = + if (Protocol.H2_PRIOR_KNOWLEDGE in client.protocols) { + Protocol.H2_PRIOR_KNOWLEDGE + } else { + Protocol.HTTP_2 + } @Volatile private var canceled = false - override fun createRequestBody(request: Request, contentLength: Long): Sink { + override fun createRequestBody( + request: Request, + contentLength: Long, + ): Sink { return stream!!.getSink() } @@ -133,7 +137,8 @@ class Http2ExchangeCodec( private const val UPGRADE = "upgrade" /** See http://tools.ietf.org/html/draft-ietf-httpbis-http2-09#section-8.1.3. */ - private val HTTP_2_SKIPPED_REQUEST_HEADERS = immutableListOf( + private val HTTP_2_SKIPPED_REQUEST_HEADERS = + immutableListOf( CONNECTION, HOST, KEEP_ALIVE, @@ -145,8 +150,10 @@ class Http2ExchangeCodec( TARGET_METHOD_UTF8, TARGET_PATH_UTF8, TARGET_SCHEME_UTF8, - TARGET_AUTHORITY_UTF8) - private val HTTP_2_SKIPPED_RESPONSE_HEADERS = immutableListOf( + TARGET_AUTHORITY_UTF8, + ) + private val HTTP_2_SKIPPED_RESPONSE_HEADERS = + immutableListOf( CONNECTION, HOST, KEEP_ALIVE, @@ -154,7 +161,8 @@ class Http2ExchangeCodec( TE, TRANSFER_ENCODING, ENCODING, - UPGRADE) + UPGRADE, + ) fun http2HeadersList(request: Request): List
{ val headers = request.headers @@ -171,7 +179,8 @@ class Http2ExchangeCodec( // header names must be lowercase. val name = headers.name(i).lowercase(Locale.US) if (name !in HTTP_2_SKIPPED_REQUEST_HEADERS || - name == TE && headers.value(i) == "trailers") { + name == TE && headers.value(i) == "trailers" + ) { result.add(Header(name, headers.value(i))) } } @@ -179,7 +188,10 @@ class Http2ExchangeCodec( } /** Returns headers for a name value block containing an HTTP/2 response. */ - fun readHttp2HeadersList(headerBlock: Headers, protocol: Protocol): Response.Builder { + fun readHttp2HeadersList( + headerBlock: Headers, + protocol: Protocol, + ): Response.Builder { var statusLine: StatusLine? = null val headersBuilder = Headers.Builder() for (i in 0 until headerBlock.size) { @@ -194,11 +206,11 @@ class Http2ExchangeCodec( if (statusLine == null) throw ProtocolException("Expected ':status' header not present") return Response.Builder() - .protocol(protocol) - .code(statusLine.code) - .message(statusLine.message) - .headers(headersBuilder.build()) - .trailers { error("trailers not available") } + .protocol(protocol) + .code(statusLine.code) + .message(statusLine.message) + .headers(headersBuilder.build()) + .trailers { error("trailers not available") } } } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt index c3f56fbc2f4f..38e7c685ba0a 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt @@ -59,13 +59,14 @@ import okio.Timeout class Http2Reader( /** Creates a frame reader with max header table size of 4096. */ private val source: BufferedSource, - private val client: Boolean + private val client: Boolean, ) : Closeable { private val continuation: ContinuationSource = ContinuationSource(this.source) - private val hpackReader: Hpack.Reader = Hpack.Reader( + private val hpackReader: Hpack.Reader = + Hpack.Reader( source = continuation, - headerTableSizeSetting = 4096 - ) + headerTableSizeSetting = 4096, + ) @Throws(IOException::class) fun readConnectionPreface(handler: Handler) { @@ -85,7 +86,10 @@ class Http2Reader( } @Throws(IOException::class) - fun nextFrame(requireSettings: Boolean, handler: Handler): Boolean { + fun nextFrame( + requireSettings: Boolean, + handler: Handler, + ): Boolean { try { source.require(9) // Frame header size. } catch (e: EOFException) { @@ -135,7 +139,12 @@ class Http2Reader( } @Throws(IOException::class) - private fun readHeaders(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readHeaders( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { if (streamId == 0) throw IOException("PROTOCOL_ERROR: TYPE_HEADERS streamId == 0") val endStream = (flags and FLAG_END_STREAM) != 0 @@ -153,7 +162,12 @@ class Http2Reader( } @Throws(IOException::class) - private fun readHeaderBlock(length: Int, padding: Int, flags: Int, streamId: Int): List
{ + private fun readHeaderBlock( + length: Int, + padding: Int, + flags: Int, + streamId: Int, + ): List
{ continuation.left = length continuation.length = continuation.left continuation.padding = padding @@ -167,7 +181,12 @@ class Http2Reader( } @Throws(IOException::class) - private fun readData(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readData( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { if (streamId == 0) throw IOException("PROTOCOL_ERROR: TYPE_DATA streamId == 0") // TODO: checkState open or half-closed (local) or raise STREAM_CLOSED @@ -185,14 +204,22 @@ class Http2Reader( } @Throws(IOException::class) - private fun readPriority(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readPriority( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { if (length != 5) throw IOException("TYPE_PRIORITY length: $length != 5") if (streamId == 0) throw IOException("TYPE_PRIORITY streamId == 0") readPriority(handler, streamId) } @Throws(IOException::class) - private fun readPriority(handler: Handler, streamId: Int) { + private fun readPriority( + handler: Handler, + streamId: Int, + ) { val w1 = source.readInt() val exclusive = w1 and 0x80000000.toInt() != 0 val streamDependency = w1 and 0x7fffffff @@ -201,17 +228,29 @@ class Http2Reader( } @Throws(IOException::class) - private fun readRstStream(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readRstStream( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { if (length != 4) throw IOException("TYPE_RST_STREAM length: $length != 4") if (streamId == 0) throw IOException("TYPE_RST_STREAM streamId == 0") val errorCodeInt = source.readInt() - val errorCode = ErrorCode.fromHttp2(errorCodeInt) ?: throw IOException( - "TYPE_RST_STREAM unexpected error code: $errorCodeInt") + val errorCode = + ErrorCode.fromHttp2(errorCodeInt) ?: throw IOException( + "TYPE_RST_STREAM unexpected error code: $errorCodeInt", + ) handler.rstStream(streamId, errorCode) } @Throws(IOException::class) - private fun readSettings(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readSettings( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { if (streamId != 0) throw IOException("TYPE_SETTINGS streamId != 0") if (flags and FLAG_ACK != 0) { if (length != 0) throw IOException("FRAME_SIZE_ERROR ack frame should be empty!") @@ -269,7 +308,12 @@ class Http2Reader( } @Throws(IOException::class) - private fun readPushPromise(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readPushPromise( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { if (streamId == 0) { throw IOException("PROTOCOL_ERROR: TYPE_PUSH_PROMISE streamId == 0") } @@ -281,7 +325,12 @@ class Http2Reader( } @Throws(IOException::class) - private fun readPing(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readPing( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { if (length != 8) throw IOException("TYPE_PING length != 8: $length") if (streamId != 0) throw IOException("TYPE_PING streamId != 0") val payload1 = source.readInt() @@ -291,14 +340,21 @@ class Http2Reader( } @Throws(IOException::class) - private fun readGoAway(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readGoAway( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { if (length < 8) throw IOException("TYPE_GOAWAY length < 8: $length") if (streamId != 0) throw IOException("TYPE_GOAWAY streamId != 0") val lastStreamId = source.readInt() val errorCodeInt = source.readInt() val opaqueDataLength = length - 8 - val errorCode = ErrorCode.fromHttp2(errorCodeInt) ?: throw IOException( - "TYPE_GOAWAY unexpected error code: $errorCodeInt") + val errorCode = + ErrorCode.fromHttp2(errorCodeInt) ?: throw IOException( + "TYPE_GOAWAY unexpected error code: $errorCodeInt", + ) var debugData = ByteString.EMPTY if (opaqueDataLength > 0) { // Must read debug data in order to not corrupt the connection. debugData = source.readByteString(opaqueDataLength.toLong()) @@ -308,7 +364,12 @@ class Http2Reader( /** Unlike other `readXxx()` functions, this one must log the frame before returning. */ @Throws(IOException::class) - private fun readWindowUpdate(handler: Handler, length: Int, flags: Int, streamId: Int) { + private fun readWindowUpdate( + handler: Handler, + length: Int, + flags: Int, + streamId: Int, + ) { val increment: Long try { if (length != 4) throw IOException("TYPE_WINDOW_UPDATE length !=4: $length") @@ -319,12 +380,14 @@ class Http2Reader( throw e } if (logger.isLoggable(FINE)) { - logger.fine(frameLogWindowUpdate( - inbound = true, - streamId = streamId, - length = length, - windowSizeIncrement = increment, - )) + logger.fine( + frameLogWindowUpdate( + inbound = true, + streamId = streamId, + length = length, + windowSizeIncrement = increment, + ), + ) } handler.windowUpdate(streamId, increment) } @@ -339,9 +402,8 @@ class Http2Reader( * continuation frames as they are needed by [Hpack.Reader.readHeaders]. */ internal class ContinuationSource( - private val source: BufferedSource + private val source: BufferedSource, ) : Source { - var length: Int = 0 var flags: Int = 0 var streamId: Int = 0 @@ -350,7 +412,10 @@ class Http2Reader( var padding: Int = 0 @Throws(IOException::class) - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { while (left == 0) { source.skip(padding.toLong()) padding = 0 @@ -388,7 +453,12 @@ class Http2Reader( interface Handler { @Throws(IOException::class) - fun data(inFinished: Boolean, streamId: Int, source: BufferedSource, length: Int) + fun data( + inFinished: Boolean, + streamId: Int, + source: BufferedSource, + length: Int, + ) /** * Create or update incoming headers, creating the corresponding streams if necessary. Frames @@ -402,12 +472,18 @@ class Http2Reader( inFinished: Boolean, streamId: Int, associatedStreamId: Int, - headerBlock: List
+ headerBlock: List
, ) - fun rstStream(streamId: Int, errorCode: ErrorCode) + fun rstStream( + streamId: Int, + errorCode: ErrorCode, + ) - fun settings(clearPrevious: Boolean, settings: Settings) + fun settings( + clearPrevious: Boolean, + settings: Settings, + ) /** HTTP/2 only. */ fun ackSettings() @@ -419,7 +495,7 @@ class Http2Reader( fun ping( ack: Boolean, payload1: Int, - payload2: Int + payload2: Int, ) /** @@ -435,7 +511,7 @@ class Http2Reader( fun goAway( lastGoodStreamId: Int, errorCode: ErrorCode, - debugData: ByteString + debugData: ByteString, ) /** @@ -444,7 +520,7 @@ class Http2Reader( */ fun windowUpdate( streamId: Int, - windowSizeIncrement: Long + windowSizeIncrement: Long, ) /** @@ -460,7 +536,7 @@ class Http2Reader( streamId: Int, streamDependency: Int, weight: Int, - exclusive: Boolean + exclusive: Boolean, ) /** @@ -478,7 +554,7 @@ class Http2Reader( fun pushPromise( streamId: Int, promisedStreamId: Int, - requestHeaders: List
+ requestHeaders: List
, ) /** @@ -506,7 +582,7 @@ class Http2Reader( protocol: ByteString, host: String, port: Int, - maxAge: Long + maxAge: Long, ) } @@ -514,7 +590,11 @@ class Http2Reader( val logger: Logger = Logger.getLogger(Http2::class.java.name) @Throws(IOException::class) - fun lengthWithoutPadding(length: Int, flags: Int, padding: Int): Int { + fun lengthWithoutPadding( + length: Int, + flags: Int, + padding: Int, + ): Int { var result = length if (flags and FLAG_PADDED != 0) result-- // Account for reading the padding length. if (padding > result) { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt index 1de5bc45d516..dd1fa1e49584 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt @@ -41,7 +41,7 @@ class Http2Stream internal constructor( val connection: Http2Connection, outFinished: Boolean, inFinished: Boolean, - headers: Headers? + headers: Headers?, ) { // Internal state is guarded by this. No long-running or potentially blocking operations are // performed while the lock is held. @@ -63,13 +63,15 @@ class Http2Stream internal constructor( /** True if response headers have been sent or received. */ private var hasResponseHeaders: Boolean = false - internal val source = FramingSource( + internal val source = + FramingSource( maxByteCount = connection.okHttpSettings.initialWindowSize.toLong(), - finished = inFinished - ) - internal val sink = FramingSink( - finished = outFinished - ) + finished = inFinished, + ) + internal val sink = + FramingSink( + finished = outFinished, + ) internal val readTimeout = StreamTimeout() internal val writeTimeout = StreamTimeout() @@ -109,8 +111,9 @@ class Http2Stream internal constructor( return false } if ((source.finished || source.closed) && - (sink.finished || sink.closed) && - hasResponseHeaders) { + (sink.finished || sink.closed) && + hasResponseHeaders + ) { return false } return true @@ -132,7 +135,8 @@ class Http2Stream internal constructor( * This is true after a `Expect-Continue` request, false for duplex requests, and false for * all other requests. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun takeHeaders(callerIsIdle: Boolean = false): Headers { while (headersQueue.isEmpty() && errorCode == null) { val doReadTimeout = callerIsIdle || doReadTimeout() @@ -157,7 +161,8 @@ class Http2Stream internal constructor( * Returns the trailers. It is only safe to call this once the source stream has been completely * exhausted. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun trailers(): Headers { if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) { return source.trailers ?: EMPTY_HEADERS @@ -177,7 +182,11 @@ class Http2Stream internal constructor( * response body exists and will be written immediately. */ @Throws(IOException::class) - fun writeHeaders(responseHeaders: List
, outFinished: Boolean, flushHeaders: Boolean) { + fun writeHeaders( + responseHeaders: List
, + outFinished: Boolean, + flushHeaders: Boolean, + ) { this@Http2Stream.assertThreadDoesntHoldLock() var flushHeaders = flushHeaders @@ -239,7 +248,10 @@ class Http2Stream internal constructor( * transmitted. */ @Throws(IOException::class) - fun close(rstStatusCode: ErrorCode, errorException: IOException?) { + fun close( + rstStatusCode: ErrorCode, + errorException: IOException?, + ) { if (!closeInternal(rstStatusCode, errorException)) { return // Already closed. } @@ -257,7 +269,10 @@ class Http2Stream internal constructor( } /** Returns true if this stream was closed. */ - private fun closeInternal(errorCode: ErrorCode, errorException: IOException?): Boolean { + private fun closeInternal( + errorCode: ErrorCode, + errorException: IOException?, + ): Boolean { this.assertThreadDoesntHoldLock() synchronized(this) { @@ -276,14 +291,20 @@ class Http2Stream internal constructor( } @Throws(IOException::class) - fun receiveData(source: BufferedSource, length: Int) { + fun receiveData( + source: BufferedSource, + length: Int, + ) { this@Http2Stream.assertThreadDoesntHoldLock() this.source.receive(source, length.toLong()) } /** Accept headers from the network and store them until the client calls [takeHeaders]. */ - fun receiveHeaders(headers: Headers, inFinished: Boolean) { + fun receiveHeaders( + headers: Headers, + inFinished: Boolean, + ) { this@Http2Stream.assertThreadDoesntHoldLock() val open: Boolean @@ -333,12 +354,11 @@ class Http2Stream internal constructor( inner class FramingSource internal constructor( /** Maximum number of bytes to buffer before reporting a flow control error. */ private val maxByteCount: Long, - /** * True if either side has cleanly shut down this stream. We will receive no more bytes beyond * those already in the buffer. */ - internal var finished: Boolean + internal var finished: Boolean, ) : Source { /** Buffer to receive data from the network into. Only accessed by the reader thread. */ val receiveBuffer = Buffer() @@ -356,7 +376,10 @@ class Http2Stream internal constructor( internal var closed: Boolean = false @Throws(IOException::class) - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { require(byteCount >= 0L) { "byteCount < 0: $byteCount" } while (true) { @@ -439,7 +462,10 @@ class Http2Stream internal constructor( * performs blocking reads for the incoming bytes. */ @Throws(IOException::class) - internal fun receive(source: BufferedSource, byteCount: Long) { + internal fun receive( + source: BufferedSource, + byteCount: Long, + ) { this@Http2Stream.assertThreadDoesntHoldLock() var remainingByteCount = byteCount @@ -537,9 +563,8 @@ class Http2Stream internal constructor( /** A sink that writes outgoing data frames of a stream. This class is not thread safe. */ internal inner class FramingSink( /** True if either side has cleanly shut down this stream. We shall send no more bytes. */ - var finished: Boolean = false + var finished: Boolean = false, ) : Sink { - /** * Buffer of outgoing data. This batches writes of small writes into this sink as larges frames * written to the outgoing connection. Batching saves the (small) framing overhead. @@ -552,7 +577,10 @@ class Http2Stream internal constructor( var closed: Boolean = false @Throws(IOException::class) - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { this@Http2Stream.assertThreadDoesntHoldLock() sendBuffer.write(source, byteCount) @@ -573,9 +601,10 @@ class Http2Stream internal constructor( writeTimeout.enter() try { while (writeBytesTotal >= writeBytesMaximum && - !finished && - !closed && - errorCode == null) { + !finished && + !closed && + errorCode == null + ) { waitForIo() // Wait until we receive a WINDOW_UPDATE for this stream. } } finally { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt index 3a03875c9639..ff72536e9b49 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt @@ -45,14 +45,15 @@ import okio.BufferedSink @Suppress("NAME_SHADOWING") class Http2Writer( private val sink: BufferedSink, - private val client: Boolean + private val client: Boolean, ) : Closeable { private val hpackBuffer: Buffer = Buffer() private var maxFrameSize: Int = INITIAL_MAX_FRAME_SIZE private var closed: Boolean = false val hpackWriter: Hpack.Writer = Hpack.Writer(out = hpackBuffer) - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun connectionPreface() { if (closed) throw IOException("closed") if (!client) return // Nothing to write; servers don't send connection headers! @@ -64,7 +65,8 @@ class Http2Writer( } /** Applies `peerSettings` and then sends a settings ACK. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun applyAndAckSettings(peerSettings: Settings) { if (closed) throw IOException("closed") this.maxFrameSize = peerSettings.getMaxFrameSize(maxFrameSize) @@ -72,10 +74,10 @@ class Http2Writer( hpackWriter.resizeHeaderTable(peerSettings.headerTableSize) } frameHeader( - streamId = 0, - length = 0, - type = TYPE_SETTINGS, - flags = FLAG_ACK + streamId = 0, + length = 0, + type = TYPE_SETTINGS, + flags = FLAG_ACK, ) sink.flush() } @@ -92,11 +94,12 @@ class Http2Writer( * @param promisedStreamId server-initiated stream ID. Must be an even number. * @param requestHeaders minimally includes `:method`, `:scheme`, `:authority`, and `:path`. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun pushPromise( streamId: Int, promisedStreamId: Int, - requestHeaders: List
+ requestHeaders: List
, ) { if (closed) throw IOException("closed") hpackWriter.writeHeaders(requestHeaders) @@ -104,10 +107,10 @@ class Http2Writer( val byteCount = hpackBuffer.size val length = minOf(maxFrameSize - 4L, byteCount).toInt() frameHeader( - streamId = streamId, - length = length + 4, - type = TYPE_PUSH_PROMISE, - flags = if (byteCount == length.toLong()) FLAG_END_HEADERS else 0 + streamId = streamId, + length = length + 4, + type = TYPE_PUSH_PROMISE, + flags = if (byteCount == length.toLong()) FLAG_END_HEADERS else 0, ) sink.writeInt(promisedStreamId and 0x7fffffff) sink.write(hpackBuffer, length.toLong()) @@ -115,22 +118,27 @@ class Http2Writer( if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) } - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun flush() { if (closed) throw IOException("closed") sink.flush() } - @Synchronized @Throws(IOException::class) - fun rstStream(streamId: Int, errorCode: ErrorCode) { + @Synchronized + @Throws(IOException::class) + fun rstStream( + streamId: Int, + errorCode: ErrorCode, + ) { if (closed) throw IOException("closed") require(errorCode.httpCode != -1) frameHeader( - streamId = streamId, - length = 4, - type = TYPE_RST_STREAM, - flags = FLAG_NONE + streamId = streamId, + length = 4, + type = TYPE_RST_STREAM, + flags = FLAG_NONE, ) sink.writeInt(errorCode.httpCode) sink.flush() @@ -146,8 +154,14 @@ class Http2Writer( * @param source the buffer to draw bytes from. May be null if byteCount is 0. * @param byteCount must be between 0 and the minimum of `source.length` and [maxDataLength]. */ - @Synchronized @Throws(IOException::class) - fun data(outFinished: Boolean, streamId: Int, source: Buffer?, byteCount: Int) { + @Synchronized + @Throws(IOException::class) + fun data( + outFinished: Boolean, + streamId: Int, + source: Buffer?, + byteCount: Int, + ) { if (closed) throw IOException("closed") var flags = FLAG_NONE if (outFinished) flags = flags or FLAG_END_STREAM @@ -155,12 +169,17 @@ class Http2Writer( } @Throws(IOException::class) - fun dataFrame(streamId: Int, flags: Int, buffer: Buffer?, byteCount: Int) { + fun dataFrame( + streamId: Int, + flags: Int, + buffer: Buffer?, + byteCount: Int, + ) { frameHeader( - streamId = streamId, - length = byteCount, - type = TYPE_DATA, - flags = flags + streamId = streamId, + length = byteCount, + type = TYPE_DATA, + flags = flags, ) if (byteCount > 0) { sink.write(buffer!!, byteCount.toLong()) @@ -168,22 +187,24 @@ class Http2Writer( } /** Write okhttp's settings to the peer. */ - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun settings(settings: Settings) { if (closed) throw IOException("closed") frameHeader( - streamId = 0, - length = settings.size() * 6, - type = TYPE_SETTINGS, - flags = FLAG_NONE + streamId = 0, + length = settings.size() * 6, + type = TYPE_SETTINGS, + flags = FLAG_NONE, ) for (i in 0 until Settings.COUNT) { if (!settings.isSet(i)) continue - val id = when (i) { - 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. - 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. - else -> i - } + val id = + when (i) { + 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. + 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. + else -> i + } sink.writeShort(id) sink.writeInt(settings[i]) } @@ -194,14 +215,19 @@ class Http2Writer( * Send a connection-level ping to the peer. `ack` indicates this is a reply. The data in * `payload1` and `payload2` opaque binary, and there are no rules on the content. */ - @Synchronized @Throws(IOException::class) - fun ping(ack: Boolean, payload1: Int, payload2: Int) { + @Synchronized + @Throws(IOException::class) + fun ping( + ack: Boolean, + payload1: Int, + payload2: Int, + ) { if (closed) throw IOException("closed") frameHeader( - streamId = 0, - length = 8, - type = TYPE_PING, - flags = if (ack) FLAG_ACK else FLAG_NONE + streamId = 0, + length = 8, + type = TYPE_PING, + flags = if (ack) FLAG_ACK else FLAG_NONE, ) sink.writeInt(payload1) sink.writeInt(payload2) @@ -216,15 +242,20 @@ class Http2Writer( * @param errorCode reason for closing the connection. * @param debugData only valid for HTTP/2; opaque debug data to send. */ - @Synchronized @Throws(IOException::class) - fun goAway(lastGoodStreamId: Int, errorCode: ErrorCode, debugData: ByteArray) { + @Synchronized + @Throws(IOException::class) + fun goAway( + lastGoodStreamId: Int, + errorCode: ErrorCode, + debugData: ByteArray, + ) { if (closed) throw IOException("closed") require(errorCode.httpCode != -1) { "errorCode.httpCode == -1" } frameHeader( - streamId = 0, - length = 8 + debugData.size, - type = TYPE_GOAWAY, - flags = FLAG_NONE + streamId = 0, + length = 8 + debugData.size, + type = TYPE_GOAWAY, + flags = FLAG_NONE, ) sink.writeInt(lastGoodStreamId) sink.writeInt(errorCode.httpCode) @@ -238,32 +269,43 @@ class Http2Writer( * Inform peer that an additional `windowSizeIncrement` bytes can be sent on `streamId`, or the * connection if `streamId` is zero. */ - @Synchronized @Throws(IOException::class) - fun windowUpdate(streamId: Int, windowSizeIncrement: Long) { + @Synchronized + @Throws(IOException::class) + fun windowUpdate( + streamId: Int, + windowSizeIncrement: Long, + ) { if (closed) throw IOException("closed") require(windowSizeIncrement != 0L && windowSizeIncrement <= 0x7fffffffL) { "windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL: $windowSizeIncrement" } if (logger.isLoggable(FINE)) { - logger.fine(frameLogWindowUpdate( - inbound = false, - streamId = streamId, - length = 4, - windowSizeIncrement = windowSizeIncrement, - )) + logger.fine( + frameLogWindowUpdate( + inbound = false, + streamId = streamId, + length = 4, + windowSizeIncrement = windowSizeIncrement, + ), + ) } frameHeader( - streamId = streamId, - length = 4, - type = TYPE_WINDOW_UPDATE, - flags = FLAG_NONE + streamId = streamId, + length = 4, + type = TYPE_WINDOW_UPDATE, + flags = FLAG_NONE, ) sink.writeInt(windowSizeIncrement.toInt()) sink.flush() } @Throws(IOException::class) - fun frameHeader(streamId: Int, length: Int, type: Int, flags: Int) { + fun frameHeader( + streamId: Int, + length: Int, + type: Int, + flags: Int, + ) { if (type != TYPE_WINDOW_UPDATE && logger.isLoggable(FINE)) { logger.fine(frameLog(false, streamId, length, type, flags)) } @@ -275,33 +317,38 @@ class Http2Writer( sink.writeInt(streamId and 0x7fffffff) } - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) override fun close() { closed = true sink.close() } @Throws(IOException::class) - private fun writeContinuationFrames(streamId: Int, byteCount: Long) { + private fun writeContinuationFrames( + streamId: Int, + byteCount: Long, + ) { var byteCount = byteCount while (byteCount > 0L) { val length = minOf(maxFrameSize.toLong(), byteCount) byteCount -= length frameHeader( - streamId = streamId, - length = length.toInt(), - type = TYPE_CONTINUATION, - flags = if (byteCount == 0L) FLAG_END_HEADERS else 0 + streamId = streamId, + length = length.toInt(), + type = TYPE_CONTINUATION, + flags = if (byteCount == 0L) FLAG_END_HEADERS else 0, ) sink.write(hpackBuffer, length) } } - @Synchronized @Throws(IOException::class) + @Synchronized + @Throws(IOException::class) fun headers( outFinished: Boolean, streamId: Int, - headerBlock: List
+ headerBlock: List
, ) { if (closed) throw IOException("closed") hpackWriter.writeHeaders(headerBlock) @@ -311,10 +358,10 @@ class Http2Writer( var flags = if (byteCount == length) FLAG_END_HEADERS else 0 if (outFinished) flags = flags or FLAG_END_STREAM frameHeader( - streamId = streamId, - length = length.toInt(), - type = TYPE_HEADERS, - flags = flags + streamId = streamId, + length = length.toInt(), + type = TYPE_HEADERS, + flags = flags, ) sink.write(hpackBuffer, length) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Huffman.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Huffman.kt index 122d2821ea6d..5cdd16260ab9 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Huffman.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Huffman.kt @@ -35,48 +35,53 @@ object Huffman { // Appendix C: Huffman Codes // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-B private val CODES = - intArrayOf(0x1ff8, 0x7fffd8, 0xfffffe2, 0xfffffe3, 0xfffffe4, 0xfffffe5, 0xfffffe6, - 0xfffffe7, 0xfffffe8, 0xffffea, 0x3ffffffc, 0xfffffe9, 0xfffffea, 0x3ffffffd, 0xfffffeb, - 0xfffffec, 0xfffffed, 0xfffffee, 0xfffffef, 0xffffff0, 0xffffff1, 0xffffff2, 0x3ffffffe, - 0xffffff3, 0xffffff4, 0xffffff5, 0xffffff6, 0xffffff7, 0xffffff8, 0xffffff9, 0xffffffa, - 0xffffffb, 0x14, 0x3f8, 0x3f9, 0xffa, 0x1ff9, 0x15, 0xf8, 0x7fa, 0x3fa, 0x3fb, 0xf9, - 0x7fb, 0xfa, 0x16, 0x17, 0x18, 0x0, 0x1, 0x2, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x5c, 0xfb, 0x7ffc, 0x20, 0xffb, 0x3fc, 0x1ffa, 0x21, 0x5d, 0x5e, 0x5f, 0x60, 0x61, - 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x70, 0x71, 0x72, 0xfc, 0x73, 0xfd, 0x1ffb, 0x7fff0, 0x1ffc, 0x3ffc, 0x22, 0x7ffd, 0x3, - 0x23, 0x4, 0x24, 0x5, 0x25, 0x26, 0x27, 0x6, 0x74, 0x75, 0x28, 0x29, 0x2a, 0x7, 0x2b, - 0x76, 0x2c, 0x8, 0x9, 0x2d, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7ffe, 0x7fc, 0x3ffd, 0x1ffd, - 0xffffffc, 0xfffe6, 0x3fffd2, 0xfffe7, 0xfffe8, 0x3fffd3, 0x3fffd4, 0x3fffd5, 0x7fffd9, - 0x3fffd6, 0x7fffda, 0x7fffdb, 0x7fffdc, 0x7fffdd, 0x7fffde, 0xffffeb, 0x7fffdf, - 0xffffec, 0xffffed, 0x3fffd7, 0x7fffe0, 0xffffee, 0x7fffe1, 0x7fffe2, 0x7fffe3, - 0x7fffe4, 0x1fffdc, 0x3fffd8, 0x7fffe5, 0x3fffd9, 0x7fffe6, 0x7fffe7, 0xffffef, - 0x3fffda, 0x1fffdd, 0xfffe9, 0x3fffdb, 0x3fffdc, 0x7fffe8, 0x7fffe9, 0x1fffde, 0x7fffea, - 0x3fffdd, 0x3fffde, 0xfffff0, 0x1fffdf, 0x3fffdf, 0x7fffeb, 0x7fffec, 0x1fffe0, - 0x1fffe1, 0x3fffe0, 0x1fffe2, 0x7fffed, 0x3fffe1, 0x7fffee, 0x7fffef, 0xfffea, 0x3fffe2, - 0x3fffe3, 0x3fffe4, 0x7ffff0, 0x3fffe5, 0x3fffe6, 0x7ffff1, 0x3ffffe0, 0x3ffffe1, - 0xfffeb, 0x7fff1, 0x3fffe7, 0x7ffff2, 0x3fffe8, 0x1ffffec, 0x3ffffe2, 0x3ffffe3, - 0x3ffffe4, 0x7ffffde, 0x7ffffdf, 0x3ffffe5, 0xfffff1, 0x1ffffed, 0x7fff2, 0x1fffe3, - 0x3ffffe6, 0x7ffffe0, 0x7ffffe1, 0x3ffffe7, 0x7ffffe2, 0xfffff2, 0x1fffe4, 0x1fffe5, - 0x3ffffe8, 0x3ffffe9, 0xffffffd, 0x7ffffe3, 0x7ffffe4, 0x7ffffe5, 0xfffec, 0xfffff3, - 0xfffed, 0x1fffe6, 0x3fffe9, 0x1fffe7, 0x1fffe8, 0x7ffff3, 0x3fffea, 0x3fffeb, - 0x1ffffee, 0x1ffffef, 0xfffff4, 0xfffff5, 0x3ffffea, 0x7ffff4, 0x3ffffeb, 0x7ffffe6, - 0x3ffffec, 0x3ffffed, 0x7ffffe7, 0x7ffffe8, 0x7ffffe9, 0x7ffffea, 0x7ffffeb, 0xffffffe, - 0x7ffffec, 0x7ffffed, 0x7ffffee, 0x7ffffef, 0x7fffff0, 0x3ffffee) + intArrayOf( + 0x1ff8, 0x7fffd8, 0xfffffe2, 0xfffffe3, 0xfffffe4, 0xfffffe5, 0xfffffe6, + 0xfffffe7, 0xfffffe8, 0xffffea, 0x3ffffffc, 0xfffffe9, 0xfffffea, 0x3ffffffd, 0xfffffeb, + 0xfffffec, 0xfffffed, 0xfffffee, 0xfffffef, 0xffffff0, 0xffffff1, 0xffffff2, 0x3ffffffe, + 0xffffff3, 0xffffff4, 0xffffff5, 0xffffff6, 0xffffff7, 0xffffff8, 0xffffff9, 0xffffffa, + 0xffffffb, 0x14, 0x3f8, 0x3f9, 0xffa, 0x1ff9, 0x15, 0xf8, 0x7fa, 0x3fa, 0x3fb, 0xf9, + 0x7fb, 0xfa, 0x16, 0x17, 0x18, 0x0, 0x1, 0x2, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x5c, 0xfb, 0x7ffc, 0x20, 0xffb, 0x3fc, 0x1ffa, 0x21, 0x5d, 0x5e, 0x5f, 0x60, 0x61, + 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0xfc, 0x73, 0xfd, 0x1ffb, 0x7fff0, 0x1ffc, 0x3ffc, 0x22, 0x7ffd, 0x3, + 0x23, 0x4, 0x24, 0x5, 0x25, 0x26, 0x27, 0x6, 0x74, 0x75, 0x28, 0x29, 0x2a, 0x7, 0x2b, + 0x76, 0x2c, 0x8, 0x9, 0x2d, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7ffe, 0x7fc, 0x3ffd, 0x1ffd, + 0xffffffc, 0xfffe6, 0x3fffd2, 0xfffe7, 0xfffe8, 0x3fffd3, 0x3fffd4, 0x3fffd5, 0x7fffd9, + 0x3fffd6, 0x7fffda, 0x7fffdb, 0x7fffdc, 0x7fffdd, 0x7fffde, 0xffffeb, 0x7fffdf, + 0xffffec, 0xffffed, 0x3fffd7, 0x7fffe0, 0xffffee, 0x7fffe1, 0x7fffe2, 0x7fffe3, + 0x7fffe4, 0x1fffdc, 0x3fffd8, 0x7fffe5, 0x3fffd9, 0x7fffe6, 0x7fffe7, 0xffffef, + 0x3fffda, 0x1fffdd, 0xfffe9, 0x3fffdb, 0x3fffdc, 0x7fffe8, 0x7fffe9, 0x1fffde, 0x7fffea, + 0x3fffdd, 0x3fffde, 0xfffff0, 0x1fffdf, 0x3fffdf, 0x7fffeb, 0x7fffec, 0x1fffe0, + 0x1fffe1, 0x3fffe0, 0x1fffe2, 0x7fffed, 0x3fffe1, 0x7fffee, 0x7fffef, 0xfffea, 0x3fffe2, + 0x3fffe3, 0x3fffe4, 0x7ffff0, 0x3fffe5, 0x3fffe6, 0x7ffff1, 0x3ffffe0, 0x3ffffe1, + 0xfffeb, 0x7fff1, 0x3fffe7, 0x7ffff2, 0x3fffe8, 0x1ffffec, 0x3ffffe2, 0x3ffffe3, + 0x3ffffe4, 0x7ffffde, 0x7ffffdf, 0x3ffffe5, 0xfffff1, 0x1ffffed, 0x7fff2, 0x1fffe3, + 0x3ffffe6, 0x7ffffe0, 0x7ffffe1, 0x3ffffe7, 0x7ffffe2, 0xfffff2, 0x1fffe4, 0x1fffe5, + 0x3ffffe8, 0x3ffffe9, 0xffffffd, 0x7ffffe3, 0x7ffffe4, 0x7ffffe5, 0xfffec, 0xfffff3, + 0xfffed, 0x1fffe6, 0x3fffe9, 0x1fffe7, 0x1fffe8, 0x7ffff3, 0x3fffea, 0x3fffeb, + 0x1ffffee, 0x1ffffef, 0xfffff4, 0xfffff5, 0x3ffffea, 0x7ffff4, 0x3ffffeb, 0x7ffffe6, + 0x3ffffec, 0x3ffffed, 0x7ffffe7, 0x7ffffe8, 0x7ffffe9, 0x7ffffea, 0x7ffffeb, 0xffffffe, + 0x7ffffec, 0x7ffffed, 0x7ffffee, 0x7ffffef, 0x7fffff0, 0x3ffffee, + ) private val CODE_BIT_COUNTS = - byteArrayOf(13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28, 28, 28, 28, 28, - 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28, 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, - 11, 8, 6, 6, 6, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10, 13, 6, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6, 15, 5, 6, - 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5, 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, - 28, 20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23, 24, 24, 22, 23, 24, - 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24, 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, - 24, 21, 22, 23, 23, 21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23, 26, - 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25, 19, 21, 26, 27, 27, 26, 27, - 24, 21, 21, 26, 26, 28, 27, 27, 27, 20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, - 24, 26, 23, 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26) + byteArrayOf( + 13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28, 28, 28, 28, 28, + 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28, 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, + 11, 8, 6, 6, 6, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10, 13, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6, 15, 5, 6, + 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5, 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, + 28, 20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23, 24, 24, 22, 23, 24, + 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24, 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, + 24, 21, 22, 23, 23, 21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23, 26, + 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25, 19, 21, 26, 27, 27, 26, 27, + 24, 21, 21, 26, 26, 28, 27, 27, 27, 20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, + 24, 26, 23, 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26, + ) private val root = Node() + init { for (i in CODE_BIT_COUNTS.indices) { addCode(i, CODES[i], CODE_BIT_COUNTS[i].toInt()) @@ -84,7 +89,10 @@ object Huffman { } @Throws(IOException::class) - fun encode(source: ByteString, sink: BufferedSink) { + fun encode( + source: ByteString, + sink: BufferedSink, + ) { var accumulator = 0L var accumulatorBitCount = 0 @@ -120,7 +128,11 @@ object Huffman { return ((bitCount + 7) shr 3).toInt() // Round up to an even byte. } - fun decode(source: BufferedSource, byteCount: Long, sink: BufferedSink) { + fun decode( + source: BufferedSource, + byteCount: Long, + sink: BufferedSink, + ) { var node = root var accumulator = 0 var accumulatorBitCount = 0 @@ -155,7 +167,11 @@ object Huffman { } } - private fun addCode(symbol: Int, code: Int, codeBitCount: Int) { + private fun addCode( + symbol: Int, + code: Int, + codeBitCount: Int, + ) { val terminal = Node(symbol, codeBitCount) var accumulatorBitCount = codeBitCount diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/PushObserver.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/PushObserver.kt index c034eab35c5f..bdbad9d49e02 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/PushObserver.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/PushObserver.kt @@ -44,7 +44,10 @@ interface PushObserver { * @param requestHeaders minimally includes `:method`, `:scheme`, `:authority`, * and `:path`. */ - fun onRequest(streamId: Int, requestHeaders: List
): Boolean + fun onRequest( + streamId: Int, + requestHeaders: List
, + ): Boolean /** * The response headers corresponding to a pushed request. When [last] is true, there are @@ -54,7 +57,11 @@ interface PushObserver { * @param responseHeaders minimally includes `:status`. * @param last when true, there is no response data. */ - fun onHeaders(streamId: Int, responseHeaders: List
, last: Boolean): Boolean + fun onHeaders( + streamId: Int, + responseHeaders: List
, + last: Boolean, + ): Boolean /** * A chunk of response data corresponding to a pushed request. This data must either be read or @@ -66,30 +73,53 @@ interface PushObserver { * @param last when true, there are no data frames to follow. */ @Throws(IOException::class) - fun onData(streamId: Int, source: BufferedSource, byteCount: Int, last: Boolean): Boolean + fun onData( + streamId: Int, + source: BufferedSource, + byteCount: Int, + last: Boolean, + ): Boolean /** Indicates the reason why this stream was canceled. */ - fun onReset(streamId: Int, errorCode: ErrorCode) + fun onReset( + streamId: Int, + errorCode: ErrorCode, + ) companion object { @JvmField val CANCEL: PushObserver = PushObserverCancel() - private class PushObserverCancel : PushObserver { - override fun onRequest(streamId: Int, requestHeaders: List
): Boolean { + private class PushObserverCancel : PushObserver { + override fun onRequest( + streamId: Int, + requestHeaders: List
, + ): Boolean { return true } - override fun onHeaders(streamId: Int, responseHeaders: List
, last: Boolean): Boolean { + override fun onHeaders( + streamId: Int, + responseHeaders: List
, + last: Boolean, + ): Boolean { return true } @Throws(IOException::class) - override fun onData(streamId: Int, source: BufferedSource, byteCount: Int, last: Boolean): Boolean { + override fun onData( + streamId: Int, + source: BufferedSource, + byteCount: Int, + last: Boolean, + ): Boolean { source.skip(byteCount.toLong()) return true } - override fun onReset(streamId: Int, errorCode: ErrorCode) { + override fun onReset( + streamId: Int, + errorCode: ErrorCode, + ) { } } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt index 7f90fd9e0663..ef704cdfde5d 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt @@ -20,7 +20,6 @@ package okhttp3.internal.http2 * Settings are [connection][Http2Connection] scoped. */ class Settings { - /** Bitfield of which flags that values. */ private var set: Int = 0 @@ -45,7 +44,10 @@ class Settings { values.fill(0) } - operator fun set(id: Int, value: Int): Settings { + operator fun set( + id: Int, + value: Int, + ): Settings { if (id < 0 || id >= values.size) { return this // Discard unknown settings. } @@ -109,14 +111,19 @@ class Settings { /** HTTP/2: Size in bytes of the table used to decode the sender's header blocks. */ const val HEADER_TABLE_SIZE = 1 + /** HTTP/2: The peer must not send a PUSH_PROMISE frame when this is 0. */ const val ENABLE_PUSH = 2 + /** Sender's maximum number of concurrent streams. */ const val MAX_CONCURRENT_STREAMS = 4 + /** HTTP/2: Size in bytes of the largest frame payload the sender will accept. */ const val MAX_FRAME_SIZE = 5 + /** HTTP/2: Advisory only. Size in bytes of the largest header list the sender will accept. */ const val MAX_HEADER_LIST_SIZE = 6 + /** Window size in bytes. */ const val INITIAL_WINDOW_SIZE = 7 diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/StreamResetException.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/StreamResetException.kt index 54ae7d8c0f5e..8198f0d16eab 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/StreamResetException.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/StreamResetException.kt @@ -18,4 +18,6 @@ package okhttp3.internal.http2 import java.io.IOException /** Thrown when an HTTP/2 stream is canceled without damage to the socket that carries it. */ -class StreamResetException(@JvmField val errorCode: ErrorCode) : IOException("stream was reset: $errorCode") +class StreamResetException( + @JvmField val errorCode: ErrorCode, +) : IOException("stream was reset: $errorCode") diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt index a7cd89f24ecc..1793525a7e62 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt @@ -1,7 +1,7 @@ package okhttp3.internal.http2.flowcontrol class WindowCounter( - val streamId: Int + val streamId: Int, ) { /** The total number of bytes consumed. */ var total: Long = 0L @@ -15,7 +15,10 @@ class WindowCounter( @Synchronized get() = total - acknowledged @Synchronized - fun update(total: Long = 0, acknowledged: Long = 0) { + fun update( + total: Long = 0, + acknowledged: Long = 0, + ) { check(total >= 0) check(acknowledged >= 0) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt b/okhttp/src/main/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt index 7435f12ecebd..345c784841dd 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt @@ -113,15 +113,19 @@ internal class IdnaMappingTable internal constructor( /** * Returns true if the [codePoint] was applied successfully. Returns false if it was disallowed. */ - fun map(codePoint: Int, sink: BufferedSink): Boolean { + fun map( + codePoint: Int, + sink: BufferedSink, + ): Boolean { val sectionsIndex = findSectionsIndex(codePoint) val rangesPosition = sections.read14BitInt(sectionsIndex + 2) - val rangesLimit = when { - sectionsIndex + 4 < sections.length -> sections.read14BitInt(sectionsIndex + 6) - else -> ranges.length / 4 - } + val rangesLimit = + when { + sectionsIndex + 4 < sections.length -> sections.read14BitInt(sectionsIndex + 6) + else -> ranges.length / 4 + } val rangesIndex = findRangesOffset(codePoint, rangesPosition, rangesLimit) @@ -201,14 +205,15 @@ internal class IdnaMappingTable internal constructor( */ private fun findSectionsIndex(codePoint: Int): Int { val target = (codePoint and 0x1fff80) shr 7 - val offset = binarySearch( + val offset = + binarySearch( position = 0, limit = sections.length / 4, - ) { index -> + ) { index -> val entryIndex = index * 4 val b0b1 = sections.read14BitInt(entryIndex) return@binarySearch target.compareTo(b0b1) - } + } return when { offset >= 0 -> offset * 4 // This section was found by binary search. @@ -222,16 +227,21 @@ internal class IdnaMappingTable internal constructor( * This binary searches over 4-byte entries, and so it needs to adjust binary search indices * in (by dividing by 4) and out (by multiplying by 4). */ - private fun findRangesOffset(codePoint: Int, position: Int, limit: Int): Int { + private fun findRangesOffset( + codePoint: Int, + position: Int, + limit: Int, + ): Int { val target = codePoint and 0x7f - val offset = binarySearch( + val offset = + binarySearch( position = position, limit = limit, - ) { index -> + ) { index -> val entryIndex = index * 4 val b0 = ranges[entryIndex].code return@binarySearch target.compareTo(b0) - } + } return when { offset >= 0 -> offset * 4 // This section was found by binary search. @@ -253,7 +263,11 @@ internal fun String.read14BitInt(index: Int): Int { * @return the index of the match. If no match is found this is `(-1 - insertionPoint)`, where the * inserting the element at `insertionPoint` will retain sorted order. */ -inline fun binarySearch(position: Int, limit: Int, compare: (Int) -> Int): Int { +inline fun binarySearch( + position: Int, + limit: Int, + compare: (Int) -> Int, +): Int { // Do the binary searching bit. var low = position var high = limit - 1 diff --git a/okhttp/src/main/kotlin/okhttp3/internal/idn/Punycode.kt b/okhttp/src/main/kotlin/okhttp3/internal/idn/Punycode.kt index 1fe36dc378c1..ea62b0dfe2bd 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/idn/Punycode.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/idn/Punycode.kt @@ -76,8 +76,8 @@ object Punycode { string: String, pos: Int, limit: Int, - result: Buffer - ) : Boolean { + result: Buffer, + ): Boolean { if (!string.requiresEncode(pos, limit)) { result.writeUtf8(string, pos, limit) return true @@ -120,11 +120,12 @@ object Punycode { var q = delta for (k in BASE until Int.MAX_VALUE step BASE) { - val t = when { - k <= bias -> TMIN - k >= bias + TMAX -> TMAX - else -> k - bias - } + val t = + when { + k <= bias -> TMIN + k >= bias + TMAX -> TMAX + else -> k - bias + } if (q < t) break result.writeByte((t + ((q - t) % (BASE - t))).punycodeDigit) q = (q - t) / (BASE - t) @@ -179,7 +180,7 @@ object Punycode { string: String, pos: Int, limit: Int, - result: Buffer + result: Buffer, ): Boolean { if (!string.regionMatches(pos, PREFIX_STRING, 0, 4, ignoreCase = true)) { result.writeUtf8(string, pos, limit) @@ -218,20 +219,22 @@ object Punycode { for (k in BASE until Int.MAX_VALUE step BASE) { if (pos == limit) return false // Malformed. val c = string[pos++] - val digit = when (c) { - in 'a'..'z' -> c - 'a' - in 'A'..'Z' -> c - 'A' - in '0'..'9' -> c - '0' + 26 - else -> return false // Malformed. - } + val digit = + when (c) { + in 'a'..'z' -> c - 'a' + in 'A'..'Z' -> c - 'A' + in '0'..'9' -> c - '0' + 26 + else -> return false // Malformed. + } val deltaI = digit * w if (i > Int.MAX_VALUE - deltaI) return false // Prevent overflow. i += deltaI - val t = when { - k <= bias -> TMIN - k >= bias + TMAX -> TMAX - else -> k - bias - } + val t = + when { + k <= bias -> TMIN + k >= bias + TMAX -> TMAX + else -> k - bias + } if (digit < t) break val scaleW = BASE - t if (w > Int.MAX_VALUE / scaleW) return false // Prevent overflow. @@ -258,11 +261,16 @@ object Punycode { } /** Returns a new bias. */ - private fun adapt(delta: Int, numpoints: Int, first: Boolean): Int { - var delta = when { - first -> delta / DAMP - else -> delta / 2 - } + private fun adapt( + delta: Int, + numpoints: Int, + first: Boolean, + ): Int { + var delta = + when { + first -> delta / DAMP + else -> delta / 2 + } delta += (delta / numpoints) var k = 0 while (delta > ((BASE - TMIN) * TMAX) / 2) { @@ -272,40 +280,48 @@ object Punycode { return k + (((BASE - TMIN + 1) * delta) / (delta + SKEW)) } - private fun String.requiresEncode(pos: Int, limit: Int): Boolean { + private fun String.requiresEncode( + pos: Int, + limit: Int, + ): Boolean { for (i in pos until limit) { if (this[i].code >= INITIAL_N) return true } return false } - private fun String.codePoints(pos: Int, limit: Int): List { + private fun String.codePoints( + pos: Int, + limit: Int, + ): List { val result = mutableListOf() var i = pos while (i < limit) { val c = this[i] - result += when { - c.isSurrogate() -> { - val low = (if (i + 1 < limit) this[i + 1] else '\u0000') - if (c.isLowSurrogate() || !low.isLowSurrogate()) { - '?'.code - } else { - i++ - 0x010000 + (c.code and 0x03ff shl 10 or (low.code and 0x03ff)) + result += + when { + c.isSurrogate() -> { + val low = (if (i + 1 < limit) this[i + 1] else '\u0000') + if (c.isLowSurrogate() || !low.isLowSurrogate()) { + '?'.code + } else { + i++ + 0x010000 + (c.code and 0x03ff shl 10 or (low.code and 0x03ff)) + } } - } - else -> c.code - } + else -> c.code + } i++ } return result } private val Int.punycodeDigit: Int - get() = when { - this < 26 -> this + 'a'.code - this < 36 -> (this - 26) + '0'.code - else -> error("unexpected digit: $this") - } + get() = + when { + this < 26 -> this + 'a'.code + this < 36 -> (this - 26) + '0'.code + else -> error("unexpected digit: $this") + } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/internal.kt b/okhttp/src/main/kotlin/okhttp3/internal/internal.kt index 835511e1795c..784f54fe4d0a 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/internal.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/internal.kt @@ -17,6 +17,7 @@ /** Exposes Kotlin-internal APIs to Java test code and code in other modules. */ @file:JvmName("Internal") @file:Suppress("ktlint:standard:filename") + package okhttp3.internal import java.nio.charset.Charset @@ -37,22 +38,38 @@ import okhttp3.Response import okhttp3.internal.concurrent.TaskRunner import okhttp3.internal.connection.RealConnection -internal fun parseCookie(currentTimeMillis: Long, url: HttpUrl, setCookie: String): Cookie? = - Cookie.parse(currentTimeMillis, url, setCookie) +internal fun parseCookie( + currentTimeMillis: Long, + url: HttpUrl, + setCookie: String, +): Cookie? = Cookie.parse(currentTimeMillis, url, setCookie) -internal fun cookieToString(cookie: Cookie, forObsoleteRfc2965: Boolean): String = - cookie.toString(forObsoleteRfc2965) +internal fun cookieToString( + cookie: Cookie, + forObsoleteRfc2965: Boolean, +): String = cookie.toString(forObsoleteRfc2965) -internal fun addHeaderLenient(builder: Headers.Builder, line: String): Headers.Builder = - builder.addLenient(line) +internal fun addHeaderLenient( + builder: Headers.Builder, + line: String, +): Headers.Builder = builder.addLenient(line) -internal fun addHeaderLenient(builder: Headers.Builder, name: String, value: String): Headers.Builder = - builder.addLenient(name, value) +internal fun addHeaderLenient( + builder: Headers.Builder, + name: String, + value: String, +): Headers.Builder = builder.addLenient(name, value) -internal fun cacheGet(cache: Cache, request: Request): Response? = cache.get(request) +internal fun cacheGet( + cache: Cache, + request: Request, +): Response? = cache.get(request) -internal fun applyConnectionSpec(connectionSpec: ConnectionSpec, sslSocket: SSLSocket, isFallback: Boolean) = - connectionSpec.apply(sslSocket, isFallback) +internal fun applyConnectionSpec( + connectionSpec: ConnectionSpec, + sslSocket: SSLSocket, + isFallback: Boolean, +) = connectionSpec.apply(sslSocket, isFallback) internal fun ConnectionSpec.effectiveCipherSuites(socketEnabledCipherSuites: Array): Array { return if (cipherSuitesAsString != null) { @@ -94,4 +111,11 @@ internal val Response.connection: RealConnection internal fun OkHttpClient.Builder.taskRunnerInternal(taskRunner: TaskRunner) = this.taskRunner(taskRunner) -internal fun buildConnectionPool(connectionListener: ConnectionListener, taskRunner: TaskRunner): ConnectionPool = ConnectionPool(connectionListener = connectionListener, taskRunner = taskRunner) +internal fun buildConnectionPool( + connectionListener: ConnectionListener, + taskRunner: TaskRunner, +): ConnectionPool = + ConnectionPool( + connectionListener = connectionListener, + taskRunner = taskRunner, + ) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/Android10Platform.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/Android10Platform.kt index e887bd73358c..02df7e3fdfde 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/Android10Platform.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/Android10Platform.kt @@ -35,27 +35,32 @@ import okhttp3.internal.tls.CertificateChainCleaner /** Android 10+ (API 29+). */ @SuppressSignatureCheck class Android10Platform : Platform() { - private val socketAdapters = listOfNotNull( + private val socketAdapters = + listOfNotNull( Android10SocketAdapter.buildIfSupported(), DeferredSocketAdapter(AndroidSocketAdapter.playProviderFactory), // Delay and Defer any initialisation of Conscrypt and BouncyCastle DeferredSocketAdapter(ConscryptSocketAdapter.factory), - DeferredSocketAdapter(BouncyCastleSocketAdapter.factory) - ).filter { it.isSupported() } + DeferredSocketAdapter(BouncyCastleSocketAdapter.factory), + ).filter { it.isSupported() } override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? = - socketAdapters.find { it.matchesSocketFactory(sslSocketFactory) } - ?.trustManager(sslSocketFactory) + socketAdapters.find { it.matchesSocketFactory(sslSocketFactory) } + ?.trustManager(sslSocketFactory) - override fun configureTlsExtensions(sslSocket: SSLSocket, hostname: String?, protocols: List) { + override fun configureTlsExtensions( + sslSocket: SSLSocket, + hostname: String?, + protocols: List, + ) { // No TLS extensions if the socket class is custom. socketAdapters.find { it.matchesSocket(sslSocket) } - ?.configureTlsExtensions(sslSocket, hostname, protocols) + ?.configureTlsExtensions(sslSocket, hostname, protocols) } override fun getSelectedProtocol(sslSocket: SSLSocket): String? = - // No TLS extensions if the socket class is custom. - socketAdapters.find { it.matchesSocket(sslSocket) }?.getSelectedProtocol(sslSocket) + // No TLS extensions if the socket class is custom. + socketAdapters.find { it.matchesSocket(sslSocket) }?.getSelectedProtocol(sslSocket) override fun getStackTraceForCloseable(closer: String): Any? { return if (Build.VERSION.SDK_INT >= 30) { @@ -65,7 +70,10 @@ class Android10Platform : Platform() { } } - override fun logCloseableLeak(message: String, stackTrace: Any?) { + override fun logCloseableLeak( + message: String, + stackTrace: Any?, + ) { if (Build.VERSION.SDK_INT >= 30) { (stackTrace as CloseGuard).warnIfOpen() } else { @@ -76,10 +84,10 @@ class Android10Platform : Platform() { @SuppressLint("NewApi") override fun isCleartextTrafficPermitted(hostname: String): Boolean = - NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(hostname) + NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(hostname) override fun buildCertificateChainCleaner(trustManager: X509TrustManager): CertificateChainCleaner = - AndroidCertificateChainCleaner.buildIfSupported(trustManager) ?: super.buildCertificateChainCleaner(trustManager) + AndroidCertificateChainCleaner.buildIfSupported(trustManager) ?: super.buildCertificateChainCleaner(trustManager) companion object { val isSupported: Boolean = isAndroid && Build.VERSION.SDK_INT >= 29 diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/AndroidPlatform.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/AndroidPlatform.kt index 1d11d9037ad7..8a6f67a8670f 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/AndroidPlatform.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/AndroidPlatform.kt @@ -42,19 +42,20 @@ import okhttp3.internal.tls.TrustRootIndex /** Android 5 to 9 (API 21 to 28). */ @SuppressSignatureCheck class AndroidPlatform : Platform() { - private val socketAdapters = listOfNotNull( + private val socketAdapters = + listOfNotNull( StandardAndroidSocketAdapter.buildIfSupported(), DeferredSocketAdapter(AndroidSocketAdapter.playProviderFactory), // Delay and Defer any initialisation of Conscrypt and BouncyCastle DeferredSocketAdapter(ConscryptSocketAdapter.factory), - DeferredSocketAdapter(BouncyCastleSocketAdapter.factory) - ).filter { it.isSupported() } + DeferredSocketAdapter(BouncyCastleSocketAdapter.factory), + ).filter { it.isSupported() } @Throws(IOException::class) override fun connectSocket( socket: Socket, address: InetSocketAddress, - connectTimeout: Int + connectTimeout: Int, ) { try { socket.connect(address, connectTimeout) @@ -70,42 +71,47 @@ class AndroidPlatform : Platform() { } override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? = - socketAdapters.find { it.matchesSocketFactory(sslSocketFactory) } - ?.trustManager(sslSocketFactory) + socketAdapters.find { it.matchesSocketFactory(sslSocketFactory) } + ?.trustManager(sslSocketFactory) override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List<@JvmSuppressWildcards Protocol> + protocols: List<@JvmSuppressWildcards Protocol>, ) { // No TLS extensions if the socket class is custom. socketAdapters.find { it.matchesSocket(sslSocket) } - ?.configureTlsExtensions(sslSocket, hostname, protocols) + ?.configureTlsExtensions(sslSocket, hostname, protocols) } override fun getSelectedProtocol(sslSocket: SSLSocket): String? = - // No TLS extensions if the socket class is custom. - socketAdapters.find { it.matchesSocket(sslSocket) }?.getSelectedProtocol(sslSocket) + // No TLS extensions if the socket class is custom. + socketAdapters.find { it.matchesSocket(sslSocket) }?.getSelectedProtocol(sslSocket) - override fun isCleartextTrafficPermitted(hostname: String): Boolean = when { - Build.VERSION.SDK_INT >= 24 -> NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(hostname) - Build.VERSION.SDK_INT >= 23 -> NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted - else -> true - } + override fun isCleartextTrafficPermitted(hostname: String): Boolean = + when { + Build.VERSION.SDK_INT >= 24 -> NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(hostname) + Build.VERSION.SDK_INT >= 23 -> NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted + else -> true + } override fun buildCertificateChainCleaner(trustManager: X509TrustManager): CertificateChainCleaner = - AndroidCertificateChainCleaner.buildIfSupported(trustManager) ?: super.buildCertificateChainCleaner(trustManager) + AndroidCertificateChainCleaner.buildIfSupported(trustManager) ?: super.buildCertificateChainCleaner(trustManager) - override fun buildTrustRootIndex(trustManager: X509TrustManager): TrustRootIndex = try { - // From org.conscrypt.TrustManagerImpl, we want the method with this signature: - // private TrustAnchor findTrustAnchorByIssuerAndSignature(X509Certificate lastCert); - val method = trustManager.javaClass.getDeclaredMethod( - "findTrustAnchorByIssuerAndSignature", X509Certificate::class.java) - method.isAccessible = true - CustomTrustRootIndex(trustManager, method) - } catch (e: NoSuchMethodException) { - super.buildTrustRootIndex(trustManager) - } + override fun buildTrustRootIndex(trustManager: X509TrustManager): TrustRootIndex = + try { + // From org.conscrypt.TrustManagerImpl, we want the method with this signature: + // private TrustAnchor findTrustAnchorByIssuerAndSignature(X509Certificate lastCert); + val method = + trustManager.javaClass.getDeclaredMethod( + "findTrustAnchorByIssuerAndSignature", + X509Certificate::class.java, + ) + method.isAccessible = true + CustomTrustRootIndex(trustManager, method) + } catch (e: NoSuchMethodException) { + super.buildTrustRootIndex(trustManager) + } override fun getHandshakeServerNames(sslSocket: SSLSocket): List { // The superclass implementation requires APIs not available until API 24+. @@ -122,12 +128,15 @@ class AndroidPlatform : Platform() { */ internal data class CustomTrustRootIndex( private val trustManager: X509TrustManager, - private val findByIssuerAndSignatureMethod: Method + private val findByIssuerAndSignatureMethod: Method, ) : TrustRootIndex { override fun findByIssuerAndSignature(cert: X509Certificate): X509Certificate? { return try { - val trustAnchor = findByIssuerAndSignatureMethod.invoke( - trustManager, cert) as TrustAnchor + val trustAnchor = + findByIssuerAndSignatureMethod.invoke( + trustManager, + cert, + ) as TrustAnchor trustAnchor.trustedCert } catch (e: IllegalAccessException) { throw AssertionError("unable to get issues and signature", e) @@ -138,17 +147,19 @@ class AndroidPlatform : Platform() { } companion object { - val isSupported: Boolean = when { - !isAndroid -> false - Build.VERSION.SDK_INT >= 30 -> false // graylisted methods are banned - else -> { - // Fail Fast - check( - Build.VERSION.SDK_INT >= 21) { "Expected Android API level 21+ but was ${Build.VERSION.SDK_INT}" } + val isSupported: Boolean = + when { + !isAndroid -> false + Build.VERSION.SDK_INT >= 30 -> false // graylisted methods are banned + else -> { + // Fail Fast + check( + Build.VERSION.SDK_INT >= 21, + ) { "Expected Android API level 21+ but was ${Build.VERSION.SDK_INT}" } - true + true + } } - } fun buildIfSupported(): Platform? = if (isSupported) AndroidPlatform() else null } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt index 1e8c976e9ab1..fbfab2e456bd 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt @@ -34,12 +34,14 @@ import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider class BouncyCastlePlatform private constructor() : Platform() { private val provider: Provider = BouncyCastleJsseProvider() - override fun newSSLContext(): SSLContext = - SSLContext.getInstance("TLS", provider) + override fun newSSLContext(): SSLContext = SSLContext.getInstance("TLS", provider) override fun platformTrustManager(): X509TrustManager { - val factory = TrustManagerFactory.getInstance( - "PKIX", BouncyCastleJsseProvider.PROVIDER_NAME) + val factory = + TrustManagerFactory.getInstance( + "PKIX", + BouncyCastleJsseProvider.PROVIDER_NAME, + ) factory.init(null as KeyStore?) val trustManagers = factory.trustManagers!! check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) { @@ -49,13 +51,14 @@ class BouncyCastlePlatform private constructor() : Platform() { } override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager = - throw UnsupportedOperationException( - "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported with BouncyCastle") + throw UnsupportedOperationException( + "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported with BouncyCastle", + ) override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List<@JvmSuppressWildcards Protocol> + protocols: List<@JvmSuppressWildcards Protocol>, ) { if (sslSocket is BCSSLSocket) { val sslParameters = sslSocket.parameters @@ -71,25 +74,26 @@ class BouncyCastlePlatform private constructor() : Platform() { } override fun getSelectedProtocol(sslSocket: SSLSocket): String? = - if (sslSocket is BCSSLSocket) { - when (val protocol = (sslSocket as BCSSLSocket).applicationProtocol) { - // Handles both un-configured and none selected. - null, "" -> null - else -> protocol - } - } else { - super.getSelectedProtocol(sslSocket) + if (sslSocket is BCSSLSocket) { + when (val protocol = (sslSocket as BCSSLSocket).applicationProtocol) { + // Handles both un-configured and none selected. + null, "" -> null + else -> protocol } + } else { + super.getSelectedProtocol(sslSocket) + } companion object { - val isSupported: Boolean = try { - // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. - Class.forName("org.bouncycastle.jsse.provider.BouncyCastleJsseProvider", false, javaClass.classLoader) + val isSupported: Boolean = + try { + // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. + Class.forName("org.bouncycastle.jsse.provider.BouncyCastleJsseProvider", false, javaClass.classLoader) - true - } catch (_: ClassNotFoundException) { - false - } + true + } catch (_: ClassNotFoundException) { + false + } fun buildIfSupported(): BouncyCastlePlatform? = if (isSupported) BouncyCastlePlatform() else null } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt index 7f845a51d7dd..dc1d2391dbcf 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt @@ -40,13 +40,14 @@ class ConscryptPlatform private constructor() : Platform() { // See release notes https://groups.google.com/forum/#!forum/conscrypt // for version differences override fun newSSLContext(): SSLContext = - // supports TLSv1.3 by default (version api is >= 1.4.0) - SSLContext.getInstance("TLS", provider) + // supports TLSv1.3 by default (version api is >= 1.4.0) + SSLContext.getInstance("TLS", provider) override fun platformTrustManager(): X509TrustManager { - val trustManagers = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply { - init(null as KeyStore?) - }.trustManagers!! + val trustManagers = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply { + init(null as KeyStore?) + }.trustManagers!! check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) { "Unexpected default trust managers: ${trustManagers.contentToString()}" } @@ -59,7 +60,7 @@ class ConscryptPlatform private constructor() : Platform() { internal object DisabledHostnameVerifier : ConscryptHostnameVerifier { fun verify( hostname: String?, - session: SSLSession? + session: SSLSession?, ): Boolean { return true } @@ -67,7 +68,7 @@ class ConscryptPlatform private constructor() : Platform() { override fun verify( certs: Array?, hostname: String?, - session: SSLSession? + session: SSLSession?, ): Boolean { return true } @@ -78,7 +79,7 @@ class ConscryptPlatform private constructor() : Platform() { override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List<@JvmSuppressWildcards Protocol> + protocols: List<@JvmSuppressWildcards Protocol>, ) { if (Conscrypt.isConscrypt(sslSocket)) { // Enable session tickets. @@ -93,11 +94,11 @@ class ConscryptPlatform private constructor() : Platform() { } override fun getSelectedProtocol(sslSocket: SSLSocket): String? = - if (Conscrypt.isConscrypt(sslSocket)) { - Conscrypt.getApplicationProtocol(sslSocket) - } else { - super.getSelectedProtocol(sslSocket) - } + if (Conscrypt.isConscrypt(sslSocket)) { + Conscrypt.getApplicationProtocol(sslSocket) + } else { + super.getSelectedProtocol(sslSocket) + } override fun newSslSocketFactory(trustManager: X509TrustManager): SSLSocketFactory { return newSSLContext().apply { @@ -106,24 +107,29 @@ class ConscryptPlatform private constructor() : Platform() { } companion object { - val isSupported: Boolean = try { - // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. - Class.forName("org.conscrypt.Conscrypt\$Version", false, javaClass.classLoader) - - when { - // Bump this version if we ever have a binary incompatibility - Conscrypt.isAvailable() && atLeastVersion(2, 1, 0) -> true - else -> false + val isSupported: Boolean = + try { + // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. + Class.forName("org.conscrypt.Conscrypt\$Version", false, javaClass.classLoader) + + when { + // Bump this version if we ever have a binary incompatibility + Conscrypt.isAvailable() && atLeastVersion(2, 1, 0) -> true + else -> false + } + } catch (e: NoClassDefFoundError) { + false + } catch (e: ClassNotFoundException) { + false } - } catch (e: NoClassDefFoundError) { - false - } catch (e: ClassNotFoundException) { - false - } fun buildIfSupported(): ConscryptPlatform? = if (isSupported) ConscryptPlatform() else null - fun atLeastVersion(major: Int, minor: Int = 0, patch: Int = 0): Boolean { + fun atLeastVersion( + major: Int, + minor: Int = 0, + patch: Int = 0, + ): Boolean { val conscryptVersion = Conscrypt.version() ?: return false if (conscryptVersion.major() != major) { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt index e7ffc9437971..b201ee7ad690 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt @@ -28,18 +28,22 @@ class Jdk8WithJettyBootPlatform( private val getMethod: Method, private val removeMethod: Method, private val clientProviderClass: Class<*>, - private val serverProviderClass: Class<*> + private val serverProviderClass: Class<*>, ) : Platform() { override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List + protocols: List, ) { val names = alpnProtocolNames(protocols) try { - val alpnProvider = Proxy.newProxyInstance(Platform::class.java.classLoader, - arrayOf(clientProviderClass, serverProviderClass), AlpnProvider(names)) + val alpnProvider = + Proxy.newProxyInstance( + Platform::class.java.classLoader, + arrayOf(clientProviderClass, serverProviderClass), + AlpnProvider(names), + ) putMethod.invoke(null, sslSocket, alpnProvider) } catch (e: InvocationTargetException) { throw AssertionError("failed to set ALPN", e) @@ -79,15 +83,20 @@ class Jdk8WithJettyBootPlatform( */ private class AlpnProvider( /** This peer's supported protocols. */ - private val protocols: List + private val protocols: List, ) : InvocationHandler { /** Set when remote peer notifies ALPN is unsupported. */ var unsupported: Boolean = false + /** The protocol the server selected. */ var selected: String? = null @Throws(Throwable::class) - override fun invoke(proxy: Any, method: Method, args: Array?): Any? { + override fun invoke( + proxy: Any, + method: Method, + args: Array?, + ): Any? { val callArgs = args ?: arrayOf() val methodName = method.name val returnType = method.returnType @@ -99,7 +108,8 @@ class Jdk8WithJettyBootPlatform( } else if (methodName == "protocols" && callArgs.isEmpty()) { return protocols // Client advertises these protocols. } else if ((methodName == "selectProtocol" || methodName == "select") && - String::class.java == returnType && callArgs.size == 1 && callArgs[0] is List<*>) { + String::class.java == returnType && callArgs.size == 1 && callArgs[0] is List<*> + ) { val peerProtocols = callArgs[0] as List<*> // Pick the first known protocol the peer advertises. for (i in 0..peerProtocols.size) { @@ -142,7 +152,12 @@ class Jdk8WithJettyBootPlatform( val getMethod = alpnClass.getMethod("get", SSLSocket::class.java) val removeMethod = alpnClass.getMethod("remove", SSLSocket::class.java) return Jdk8WithJettyBootPlatform( - putMethod, getMethod, removeMethod, clientProviderClass, serverProviderClass) + putMethod, + getMethod, + removeMethod, + clientProviderClass, + serverProviderClass, + ) } catch (_: ClassNotFoundException) { } catch (_: NoSuchMethodException) { } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk9Platform.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk9Platform.kt index b89bafe9ea5d..dd31b687b43a 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk9Platform.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk9Platform.kt @@ -29,7 +29,7 @@ open class Jdk9Platform : Platform() { override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List<@JvmSuppressWildcards Protocol> + protocols: List<@JvmSuppressWildcards Protocol>, ) { val sslParameters = sslSocket.sslParameters @@ -61,7 +61,8 @@ open class Jdk9Platform : Platform() { // sun.security.ssl.SSLSocketFactoryImpl accessible: module java.base does not export // sun.security.ssl to unnamed module @xxx throw UnsupportedOperationException( - "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 8 (>= 252) or JDK 9+") + "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 8 (>= 252) or JDK 9+", + ) } override fun newSSLContext(): SSLContext { @@ -86,17 +87,18 @@ open class Jdk9Platform : Platform() { val majorVersion = System.getProperty("java.specification.version")?.toIntOrNull() init { - isAvailable = if (majorVersion != null) { - majorVersion >= 9 - } else { - try { - // also present on JDK8 after build 252. - SSLSocket::class.java.getMethod("getApplicationProtocol") - true - } catch (nsme: NoSuchMethodException) { - false + isAvailable = + if (majorVersion != null) { + majorVersion >= 9 + } else { + try { + // also present on JDK8 after build 252. + SSLSocket::class.java.getMethod("getApplicationProtocol") + true + } catch (nsme: NoSuchMethodException) { + false + } } - } } fun buildIfSupported(): Jdk9Platform? = if (isAvailable) Jdk9Platform() else null diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt index a98d9ff9c58a..db0bab86a5c1 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt @@ -36,12 +36,14 @@ class OpenJSSEPlatform private constructor() : Platform() { // Selects TLSv1.3 so we are specific about our intended version ranges (not just 1.3) // and because it's a common pattern for VMs to have differences between supported and // defaulted versions for TLS based on what is requested. - override fun newSSLContext(): SSLContext = - SSLContext.getInstance("TLSv1.3", provider) + override fun newSSLContext(): SSLContext = SSLContext.getInstance("TLSv1.3", provider) override fun platformTrustManager(): X509TrustManager { - val factory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm(), provider) + val factory = + TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm(), + provider, + ) factory.init(null as KeyStore?) val trustManagers = factory.trustManagers!! check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) { @@ -51,13 +53,14 @@ class OpenJSSEPlatform private constructor() : Platform() { } override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager = - throw UnsupportedOperationException( - "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported with OpenJSSE") + throw UnsupportedOperationException( + "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported with OpenJSSE", + ) override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List<@JvmSuppressWildcards Protocol> + protocols: List<@JvmSuppressWildcards Protocol>, ) { if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) { val sslParameters = sslSocket.sslParameters @@ -75,25 +78,26 @@ class OpenJSSEPlatform private constructor() : Platform() { } override fun getSelectedProtocol(sslSocket: SSLSocket): String? = - if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) { - when (val protocol = sslSocket.applicationProtocol) { - // Handles both un-configured and none selected. - null, "" -> null - else -> protocol - } - } else { - super.getSelectedProtocol(sslSocket) + if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) { + when (val protocol = sslSocket.applicationProtocol) { + // Handles both un-configured and none selected. + null, "" -> null + else -> protocol } + } else { + super.getSelectedProtocol(sslSocket) + } companion object { - val isSupported: Boolean = try { - // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. - Class.forName("org.openjsse.net.ssl.OpenJSSE", false, javaClass.classLoader) + val isSupported: Boolean = + try { + // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. + Class.forName("org.openjsse.net.ssl.OpenJSSE", false, javaClass.classLoader) - true - } catch (_: ClassNotFoundException) { - false - } + true + } catch (_: ClassNotFoundException) { + false + } fun buildIfSupported(): OpenJSSEPlatform? = if (isSupported) OpenJSSEPlatform() else null } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/Platform.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/Platform.kt index 0afeaa48b1e9..4483de380150 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/Platform.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/Platform.kt @@ -72,15 +72,16 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement * Supported on Android 6.0+ via `NetworkSecurityPolicy`. */ open class Platform { - /** Prefix used on custom headers. */ fun getPrefix() = "OkHttp" open fun newSSLContext(): SSLContext = SSLContext.getInstance("TLS") open fun platformTrustManager(): X509TrustManager { - val factory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()) + val factory = + TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm(), + ) factory.init(null as KeyStore?) val trustManagers = factory.trustManagers!! check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) { @@ -116,7 +117,7 @@ open class Platform { open fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List<@JvmSuppressWildcards Protocol> + protocols: List<@JvmSuppressWildcards Protocol>, ) { } @@ -136,11 +137,19 @@ open class Platform { } @Throws(IOException::class) - open fun connectSocket(socket: Socket, address: InetSocketAddress, connectTimeout: Int) { + open fun connectSocket( + socket: Socket, + address: InetSocketAddress, + connectTimeout: Int, + ) { socket.connect(address, connectTimeout) } - open fun log(message: String, level: Int = INFO, t: Throwable? = null) { + open fun log( + message: String, + level: Int = INFO, + t: Throwable? = null, + ) { val logLevel = if (level == WARN) Level.WARNING else Level.INFO logger.log(logLevel, message, t) } @@ -159,20 +168,22 @@ open class Platform { } } - open fun logCloseableLeak(message: String, stackTrace: Any?) { + open fun logCloseableLeak( + message: String, + stackTrace: Any?, + ) { var logMessage = message if (stackTrace == null) { logMessage += " To see where this was allocated, set the OkHttpClient logger level to " + - "FINE: Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);" + "FINE: Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);" } log(logMessage, WARN, stackTrace as Throwable?) } open fun buildCertificateChainCleaner(trustManager: X509TrustManager): CertificateChainCleaner = - BasicCertificateChainCleaner(buildTrustRootIndex(trustManager)) + BasicCertificateChainCleaner(buildTrustRootIndex(trustManager)) - open fun buildTrustRootIndex(trustManager: X509TrustManager): TrustRootIndex = - BasicTrustRootIndex(*trustManager.acceptedIssuers) + open fun buildTrustRootIndex(trustManager: X509TrustManager): TrustRootIndex = BasicTrustRootIndex(*trustManager.acceptedIssuers) open fun newSslSocketFactory(trustManager: X509TrustManager): SSLSocketFactory { try { @@ -201,13 +212,12 @@ open class Platform { this.platform = platform } - fun alpnProtocolNames(protocols: List) = - protocols.filter { it != Protocol.HTTP_1_0 }.map { it.toString() } + fun alpnProtocolNames(protocols: List) = protocols.filter { it != Protocol.HTTP_1_0 }.map { it.toString() } // This explicit check avoids activating in Android Studio with Android specific classes // available when running plugins inside the IDE. val isAndroid: Boolean - get() = "Dalvik" == System.getProperty("java.vm.name") + get() = "Dalvik" == System.getProperty("java.vm.name") private val isConscryptPreferred: Boolean get() { @@ -228,11 +238,12 @@ open class Platform { } /** Attempt to match the host runtime to a capable Platform implementation. */ - private fun findPlatform(): Platform = if (isAndroid) { - findAndroidPlatform() - } else { - findJvmPlatform() - } + private fun findPlatform(): Platform = + if (isAndroid) { + findAndroidPlatform() + } else { + findJvmPlatform() + } private fun findAndroidPlatform(): Platform { AndroidLog.enable() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt index b189478fc2cb..42199f3bace6 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt @@ -39,7 +39,7 @@ class Android10SocketAdapter : SocketAdapter { override fun isSupported(): Boolean = Companion.isSupported() @SuppressLint("NewApi") - override fun getSelectedProtocol(sslSocket: SSLSocket): String? { + override fun getSelectedProtocol(sslSocket: SSLSocket): String? { return try { // SSLSocket.getApplicationProtocol returns "" if application protocols values will not // be used. Observed if you didn't specify SSLParameters.setApplicationProtocols @@ -57,7 +57,7 @@ class Android10SocketAdapter : SocketAdapter { override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List + protocols: List, ) { try { SSLSockets.setUseSessionTickets(sslSocket, true) @@ -76,8 +76,7 @@ class Android10SocketAdapter : SocketAdapter { @SuppressSignatureCheck companion object { - fun buildIfSupported(): SocketAdapter? = - if (isSupported()) Android10SocketAdapter() else null + fun buildIfSupported(): SocketAdapter? = if (isSupported()) Android10SocketAdapter() else null fun isSupported() = isAndroid && Build.VERSION.SDK_INT >= 29 } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt index 0fc5a031bd34..09fbc2b19e9a 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt @@ -32,13 +32,15 @@ import okhttp3.internal.tls.CertificateChainCleaner */ internal class AndroidCertificateChainCleaner( private val trustManager: X509TrustManager, - private val x509TrustManagerExtensions: X509TrustManagerExtensions + private val x509TrustManagerExtensions: X509TrustManagerExtensions, ) : CertificateChainCleaner() { @Suppress("UNCHECKED_CAST") @Throws(SSLPeerUnverifiedException::class) @SuppressSignatureCheck - override - fun clean(chain: List, hostname: String): List { + override fun clean( + chain: List, + hostname: String, + ): List { val certificates = (chain as List).toTypedArray() try { return x509TrustManagerExtensions.checkServerTrusted(certificates, "RSA", hostname) @@ -48,20 +50,21 @@ internal class AndroidCertificateChainCleaner( } override fun equals(other: Any?): Boolean = - other is AndroidCertificateChainCleaner && - other.trustManager === this.trustManager + other is AndroidCertificateChainCleaner && + other.trustManager === this.trustManager override fun hashCode(): Int = System.identityHashCode(trustManager) companion object { @SuppressSignatureCheck fun buildIfSupported(trustManager: X509TrustManager): AndroidCertificateChainCleaner? { - val extensions = try { - X509TrustManagerExtensions(trustManager) - } catch (iae: IllegalArgumentException) { - // X509TrustManagerExtensions checks for checkServerTrusted(X509Certificate[], String, String) - null - } + val extensions = + try { + X509TrustManagerExtensions(trustManager) + } catch (iae: IllegalArgumentException) { + // X509TrustManagerExtensions checks for checkServerTrusted(X509Certificate[], String, String) + null + } return when { extensions != null -> AndroidCertificateChainCleaner(trustManager, extensions) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidLog.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidLog.kt index 0c418953cace..6801cd37e263 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidLog.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidLog.kt @@ -28,11 +28,12 @@ import okhttp3.internal.http2.Http2 import okhttp3.internal.platform.android.AndroidLog.androidLog private val LogRecord.androidLevel: Int - get() = when { - level.intValue() > Level.INFO.intValue() -> Log.WARN - level.intValue() == Level.INFO.intValue() -> Log.INFO - else -> Log.DEBUG - } + get() = + when { + level.intValue() > Level.INFO.intValue() -> Log.WARN + level.intValue() == Level.INFO.intValue() -> Log.INFO + else -> Log.DEBUG + } object AndroidLogHandler : Handler() { override fun publish(record: LogRecord) { @@ -53,20 +54,26 @@ object AndroidLog { // Keep references to loggers to prevent their configuration from being GC'd. private val configuredLoggers = CopyOnWriteArraySet() - private val knownLoggers = LinkedHashMap().apply { - val packageName = OkHttpClient::class.java.`package`?.name - - if (packageName != null) { - this[packageName] = "OkHttp" - } + private val knownLoggers = + LinkedHashMap().apply { + val packageName = OkHttpClient::class.java.`package`?.name - this[OkHttpClient::class.java.name] = "okhttp.OkHttpClient" - this[Http2::class.java.name] = "okhttp.Http2" - this[TaskRunner::class.java.name] = "okhttp.TaskRunner" - this["okhttp3.mockwebserver.MockWebServer"] = "okhttp.MockWebServer" - }.toMap() + if (packageName != null) { + this[packageName] = "OkHttp" + } - internal fun androidLog(loggerName: String, logLevel: Int, message: String, t: Throwable? = null) { + this[OkHttpClient::class.java.name] = "okhttp.OkHttpClient" + this[Http2::class.java.name] = "okhttp.Http2" + this[TaskRunner::class.java.name] = "okhttp.TaskRunner" + this["okhttp3.mockwebserver.MockWebServer"] = "okhttp.MockWebServer" + }.toMap() + + internal fun androidLog( + loggerName: String, + logLevel: Int, + message: String, + t: Throwable? = null, + ) { val tag = loggerTag(loggerName) if (Log.isLoggable(tag, logLevel)) { @@ -101,16 +108,20 @@ object AndroidLog { } } - private fun enableLogging(logger: String, tag: String) { + private fun enableLogging( + logger: String, + tag: String, + ) { val logger = Logger.getLogger(logger) if (configuredLoggers.add(logger)) { logger.useParentHandlers = false // log based on levels at startup to avoid logging each frame - logger.level = when { - Log.isLoggable(tag, Log.DEBUG) -> Level.FINE - Log.isLoggable(tag, Log.INFO) -> Level.INFO - else -> Level.WARNING - } + logger.level = + when { + Log.isLoggable(tag, Log.DEBUG) -> Level.FINE + Log.isLoggable(tag, Log.INFO) -> Level.INFO + else -> Level.WARNING + } logger.addHandler(AndroidLogHandler) } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt index 90b03f4fad86..cdbde44392cc 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt @@ -45,7 +45,7 @@ open class AndroidSocketAdapter(private val sslSocketClass: Class) override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List + protocols: List, ) { // No TLS extensions if the socket class is custom. if (matchesSocket(sslSocket)) { @@ -61,8 +61,8 @@ open class AndroidSocketAdapter(private val sslSocketClass: Class) // Enable ALPN. setAlpnProtocols.invoke( - sslSocket, - Platform.concatLengthPrefixed(protocols) + sslSocket, + Platform.concatLengthPrefixed(protocols), ) } catch (e: IllegalAccessException) { throw AssertionError(e) @@ -110,7 +110,7 @@ open class AndroidSocketAdapter(private val sslSocketClass: Class) if (possibleClass == null) { throw AssertionError( - "No OpenSSLSocketImpl superclass of socket of type $actualSSLSocketClass" + "No OpenSSLSocketImpl superclass of socket of type $actualSSLSocketClass", ) } } @@ -120,8 +120,7 @@ open class AndroidSocketAdapter(private val sslSocketClass: Class) fun factory(packageName: String): DeferredSocketAdapter.Factory { return object : DeferredSocketAdapter.Factory { - override fun matchesSocket(sslSocket: SSLSocket): Boolean = - sslSocket.javaClass.name.startsWith("$packageName.") + override fun matchesSocket(sslSocket: SSLSocket): Boolean = sslSocket.javaClass.name.startsWith("$packageName.") override fun create(sslSocket: SSLSocket): SocketAdapter { return build(sslSocket.javaClass) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt index e943803a2be8..a2a4ffdfb018 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt @@ -41,7 +41,7 @@ class BouncyCastleSocketAdapter : SocketAdapter { override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List + protocols: List, ) { // No TLS extensions if the socket class is custom. if (matchesSocket(sslSocket)) { @@ -57,11 +57,13 @@ class BouncyCastleSocketAdapter : SocketAdapter { } companion object { - val factory = object : DeferredSocketAdapter.Factory { - override fun matchesSocket(sslSocket: SSLSocket): Boolean { - return BouncyCastlePlatform.isSupported && sslSocket is BCSSLSocket + val factory = + object : DeferredSocketAdapter.Factory { + override fun matchesSocket(sslSocket: SSLSocket): Boolean { + return BouncyCastlePlatform.isSupported && sslSocket is BCSSLSocket + } + + override fun create(sslSocket: SSLSocket): SocketAdapter = BouncyCastleSocketAdapter() } - override fun create(sslSocket: SSLSocket): SocketAdapter = BouncyCastleSocketAdapter() - } } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt index d0fad9328e14..00781ee19b05 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt @@ -31,15 +31,15 @@ class ConscryptSocketAdapter : SocketAdapter { override fun isSupported(): Boolean = ConscryptPlatform.isSupported override fun getSelectedProtocol(sslSocket: SSLSocket): String? = - when { - matchesSocket(sslSocket) -> Conscrypt.getApplicationProtocol(sslSocket) - else -> null // No TLS extensions if the socket class is custom. - } + when { + matchesSocket(sslSocket) -> Conscrypt.getApplicationProtocol(sslSocket) + else -> null // No TLS extensions if the socket class is custom. + } override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List + protocols: List, ) { // No TLS extensions if the socket class is custom. if (matchesSocket(sslSocket)) { @@ -53,11 +53,13 @@ class ConscryptSocketAdapter : SocketAdapter { } companion object { - val factory = object : DeferredSocketAdapter.Factory { - override fun matchesSocket(sslSocket: SSLSocket): Boolean { - return ConscryptPlatform.isSupported && Conscrypt.isConscrypt(sslSocket) + val factory = + object : DeferredSocketAdapter.Factory { + override fun matchesSocket(sslSocket: SSLSocket): Boolean { + return ConscryptPlatform.isSupported && Conscrypt.isConscrypt(sslSocket) + } + + override fun create(sslSocket: SSLSocket): SocketAdapter = ConscryptSocketAdapter() } - override fun create(sslSocket: SSLSocket): SocketAdapter = ConscryptSocketAdapter() - } } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt index 2d61626db3b0..fc8257f23dcc 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt @@ -33,13 +33,12 @@ class DeferredSocketAdapter(private val socketAdapterFactory: Factory) : SocketA return true } - override fun matchesSocket(sslSocket: SSLSocket): Boolean = - socketAdapterFactory.matchesSocket(sslSocket) + override fun matchesSocket(sslSocket: SSLSocket): Boolean = socketAdapterFactory.matchesSocket(sslSocket) override fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List + protocols: List, ) { getDelegate(sslSocket)?.configureTlsExtensions(sslSocket, hostname, protocols) } @@ -58,6 +57,7 @@ class DeferredSocketAdapter(private val socketAdapterFactory: Factory) : SocketA interface Factory { fun matchesSocket(sslSocket: SSLSocket): Boolean + fun create(sslSocket: SSLSocket): SocketAdapter } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt index 9cfbf9b21824..40776f6bfb17 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt @@ -22,14 +22,17 @@ import okhttp3.Protocol interface SocketAdapter { fun isSupported(): Boolean + fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? = null + fun matchesSocket(sslSocket: SSLSocket): Boolean + fun matchesSocketFactory(sslSocketFactory: SSLSocketFactory): Boolean = false fun configureTlsExtensions( sslSocket: SSLSocket, hostname: String?, - protocols: List + protocols: List, ) fun getSelectedProtocol(sslSocket: SSLSocket): String? diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt index 18741ca2f22f..8e75fd4e06d6 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt @@ -31,21 +31,28 @@ import okhttp3.internal.readFieldOrNull class StandardAndroidSocketAdapter( sslSocketClass: Class, private val sslSocketFactoryClass: Class, - private val paramClass: Class<*> + private val paramClass: Class<*>, ) : AndroidSocketAdapter(sslSocketClass) { - - override fun matchesSocketFactory(sslSocketFactory: SSLSocketFactory): Boolean = - sslSocketFactoryClass.isInstance(sslSocketFactory) + override fun matchesSocketFactory(sslSocketFactory: SSLSocketFactory): Boolean = sslSocketFactoryClass.isInstance(sslSocketFactory) override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? { val context: Any? = - readFieldOrNull(sslSocketFactory, paramClass, - "sslParameters") - val x509TrustManager = readFieldOrNull( - context!!, X509TrustManager::class.java, "x509TrustManager") - return x509TrustManager ?: readFieldOrNull(context, + readFieldOrNull( + sslSocketFactory, + paramClass, + "sslParameters", + ) + val x509TrustManager = + readFieldOrNull( + context!!, + X509TrustManager::class.java, + "x509TrustManager", + ) + return x509TrustManager ?: readFieldOrNull( + context, X509TrustManager::class.java, - "trustManager") + "trustManager", + ) } companion object { @@ -59,7 +66,12 @@ class StandardAndroidSocketAdapter( StandardAndroidSocketAdapter(sslSocketClass, sslSocketFactoryClass, paramsClass) } catch (e: Exception) { - AndroidLog.androidLog(loggerName = OkHttpClient::class.java.name, logLevel = Platform.WARN, message = "unable to load android socket classes", t = e) + AndroidLog.androidLog( + loggerName = OkHttpClient::class.java.name, + logLevel = Platform.WARN, + message = "unable to load android socket classes", + t = e, + ) null } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/proxy/NullProxySelector.kt b/okhttp/src/main/kotlin/okhttp3/internal/proxy/NullProxySelector.kt index 40c0674146f1..f42379c5e64f 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/proxy/NullProxySelector.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/proxy/NullProxySelector.kt @@ -30,6 +30,10 @@ object NullProxySelector : ProxySelector() { return listOf(Proxy.NO_PROXY) } - override fun connectFailed(uri: URI?, sa: SocketAddress?, ioe: IOException?) { + override fun connectFailed( + uri: URI?, + sa: SocketAddress?, + ioe: IOException?, + ) { } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt b/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt index 35db6ae63e48..fef4fd01df79 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt @@ -35,9 +35,8 @@ import okio.buffer */ class PublicSuffixDatabase internal constructor( val path: Path = PUBLIC_SUFFIX_RESOURCE, - val fileSystem: FileSystem = FileSystem.RESOURCES + val fileSystem: FileSystem = FileSystem.RESOURCES, ) { - /** True after we've attempted to read the list for the first time. */ private val listRead = AtomicBoolean(false) @@ -78,13 +77,14 @@ class PublicSuffixDatabase internal constructor( return null // The domain is a public suffix. } - val firstLabelOffset = if (rule[0][0] == EXCEPTION_MARKER) { - // Exception rules hold the effective TLD plus one. - domainLabels.size - rule.size - } else { - // Otherwise the rule is for a public suffix, so we must take one more label. - domainLabels.size - (rule.size + 1) - } + val firstLabelOffset = + if (rule[0][0] == EXCEPTION_MARKER) { + // Exception rules hold the effective TLD plus one. + domainLabels.size - rule.size + } else { + // Otherwise the rule is for a public suffix, so we must take one more label. + domainLabels.size - (rule.size + 1) + } return splitDomain(domain).asSequence().drop(firstLabelOffset).joinToString(".") } @@ -152,8 +152,11 @@ class PublicSuffixDatabase internal constructor( var exception: String? = null if (wildcardMatch != null) { for (labelIndex in 0 until domainLabelsUtf8Bytes.size - 1) { - val rule = publicSuffixExceptionListBytes.binarySearch( - domainLabelsUtf8Bytes, labelIndex) + val rule = + publicSuffixExceptionListBytes.binarySearch( + domainLabelsUtf8Bytes, + labelIndex, + ) if (rule != null) { exception = rule break @@ -232,7 +235,7 @@ class PublicSuffixDatabase internal constructor( /** Visible for testing. */ fun setListBytes( publicSuffixListBytes: ByteArray, - publicSuffixExceptionListBytes: ByteArray + publicSuffixExceptionListBytes: ByteArray, ) { this.publicSuffixListBytes = publicSuffixListBytes this.publicSuffixExceptionListBytes = publicSuffixExceptionListBytes @@ -257,7 +260,7 @@ class PublicSuffixDatabase internal constructor( private fun ByteArray.binarySearch( labels: Array, - labelIndex: Int + labelIndex: Int, ): String? { var low = 0 var high = size diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt b/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt index ab28385179ff..4e150dff3be7 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt @@ -34,9 +34,8 @@ import javax.net.ssl.SSLPeerUnverifiedException * [Conscrypt]: https://conscrypt.org/ */ class BasicCertificateChainCleaner( - private val trustRootIndex: TrustRootIndex + private val trustRootIndex: TrustRootIndex, ) : CertificateChainCleaner() { - /** * Returns a cleaned chain for [chain]. * @@ -45,7 +44,10 @@ class BasicCertificateChainCleaner( * what was used to establish [chain]. */ @Throws(SSLPeerUnverifiedException::class) - override fun clean(chain: List, hostname: String): List { + override fun clean( + chain: List, + hostname: String, + ): List { val queue: Deque = ArrayDeque(chain) val result = mutableListOf() result.add(queue.removeFirst()) @@ -89,7 +91,8 @@ class BasicCertificateChainCleaner( // The last link isn't trusted. Fail. throw SSLPeerUnverifiedException( - "Failed to find a trusted cert that signed $toVerify") + "Failed to find a trusted cert that signed $toVerify", + ) } throw SSLPeerUnverifiedException("Certificate chain too long: $result") diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt b/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt index 4730e78d4294..ab25e9b00cd8 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt @@ -46,7 +46,7 @@ class BasicTrustRootIndex(vararg caCerts: X509Certificate) : TrustRootIndex { override fun equals(other: Any?): Boolean { return other === this || - (other is BasicTrustRootIndex && other.subjectToCaCerts == subjectToCaCerts) + (other is BasicTrustRootIndex && other.subjectToCaCerts == subjectToCaCerts) } override fun hashCode(): Int { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt b/okhttp/src/main/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt index c7080a458ba4..285d4298e64b 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt @@ -33,9 +33,11 @@ import okhttp3.internal.platform.Platform * pinning. */ abstract class CertificateChainCleaner { - @Throws(SSLPeerUnverifiedException::class) - abstract fun clean(chain: List, hostname: String): List + abstract fun clean( + chain: List, + hostname: String, + ): List companion object { fun get(trustManager: X509TrustManager): CertificateChainCleaner { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt b/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt index a43791bb2813..706721b483e7 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt @@ -16,15 +16,15 @@ */ package okhttp3.internal.tls -import okhttp3.internal.canParseAsIpAddress -import okhttp3.internal.toCanonicalHost -import okio.utf8Size import java.security.cert.CertificateParsingException import java.security.cert.X509Certificate import java.util.Locale import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLException import javax.net.ssl.SSLSession +import okhttp3.internal.canParseAsIpAddress +import okhttp3.internal.toCanonicalHost +import okio.utf8Size /** * A HostnameVerifier consistent with [RFC 2818][rfc_2818]. @@ -36,7 +36,10 @@ object OkHostnameVerifier : HostnameVerifier { private const val ALT_DNS_NAME = 2 private const val ALT_IPA_NAME = 7 - override fun verify(host: String, session: SSLSession): Boolean { + override fun verify( + host: String, + session: SSLSession, + ): Boolean { return if (!host.isAscii()) { false } else { @@ -46,10 +49,12 @@ object OkHostnameVerifier : HostnameVerifier { false } } - } - fun verify(host: String, certificate: X509Certificate): Boolean { + fun verify( + host: String, + certificate: X509Certificate, + ): Boolean { return when { host.canParseAsIpAddress() -> verifyIpAddress(host, certificate) else -> verifyHostname(host, certificate) @@ -57,7 +62,10 @@ object OkHostnameVerifier : HostnameVerifier { } /** Returns true if [certificate] matches [ipAddress]. */ - private fun verifyIpAddress(ipAddress: String, certificate: X509Certificate): Boolean { + private fun verifyIpAddress( + ipAddress: String, + certificate: X509Certificate, + ): Boolean { val canonicalIpAddress = ipAddress.toCanonicalHost() return getSubjectAltNames(certificate, ALT_IPA_NAME).any { @@ -66,7 +74,10 @@ object OkHostnameVerifier : HostnameVerifier { } /** Returns true if [certificate] matches [hostname]. */ - private fun verifyHostname(hostname: String, certificate: X509Certificate): Boolean { + private fun verifyHostname( + hostname: String, + certificate: X509Certificate, + ): Boolean { val hostname = hostname.asciiToLowercase() return getSubjectAltNames(certificate, ALT_DNS_NAME).any { verifyHostname(hostname, it) @@ -95,19 +106,24 @@ object OkHostnameVerifier : HostnameVerifier { * @param pattern domain name pattern from certificate. May be a wildcard pattern such as * `*.android.com`. */ - private fun verifyHostname(hostname: String?, pattern: String?): Boolean { + private fun verifyHostname( + hostname: String?, + pattern: String?, + ): Boolean { var hostname = hostname var pattern = pattern // Basic sanity checks if (hostname.isNullOrEmpty() || - hostname.startsWith(".") || - hostname.endsWith("..")) { + hostname.startsWith(".") || + hostname.endsWith("..") + ) { // Invalid domain name return false } if (pattern.isNullOrEmpty() || - pattern.startsWith(".") || - pattern.endsWith("..")) { + pattern.startsWith(".") || + pattern.endsWith("..") + ) { // Invalid pattern/domain name return false } @@ -175,7 +191,8 @@ object OkHostnameVerifier : HostnameVerifier { // Check that asterisk did not match across domain name labels. val suffixStartIndexInHostname = hostname.length - suffix.length if (suffixStartIndexInHostname > 0 && - hostname.lastIndexOf('.', suffixStartIndexInHostname - 1) != -1) { + hostname.lastIndexOf('.', suffixStartIndexInHostname - 1) != -1 + ) { return false // Asterisk is matching across domain name labels -- not permitted. } @@ -189,7 +206,10 @@ object OkHostnameVerifier : HostnameVerifier { return altIpaNames + altDnsNames } - private fun getSubjectAltNames(certificate: X509Certificate, type: Int): List { + private fun getSubjectAltNames( + certificate: X509Certificate, + type: Int, + ): List { try { val subjectAltNames = certificate.subjectAlternativeNames ?: return emptyList() val result = mutableListOf() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageDeflater.kt b/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageDeflater.kt index 1b324c557602..5aa3803f6125 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageDeflater.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageDeflater.kt @@ -27,15 +27,16 @@ private val EMPTY_DEFLATE_BLOCK = "000000ffff".decodeHex() private const val LAST_OCTETS_COUNT_TO_REMOVE_AFTER_DEFLATION = 4 class MessageDeflater( - private val noContextTakeover: Boolean + private val noContextTakeover: Boolean, ) : Closeable { private val deflatedBytes = Buffer() - private val deflater = Deflater( - Deflater.DEFAULT_COMPRESSION, - // nowrap (omits zlib header): - true, - ) + private val deflater = + Deflater( + Deflater.DEFAULT_COMPRESSION, + // nowrap (omits zlib header): + true, + ) private val deflaterSink = DeflaterSink(deflatedBytes, deflater) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageInflater.kt b/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageInflater.kt index 2f51016cf64f..382a2a4d9e51 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageInflater.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageInflater.kt @@ -24,14 +24,15 @@ import okio.InflaterSource private const val OCTETS_TO_ADD_BEFORE_INFLATION = 0x0000ffff class MessageInflater( - private val noContextTakeover: Boolean + private val noContextTakeover: Boolean, ) : Closeable { private val deflatedBytes = Buffer() - private val inflater = Inflater( - // nowrap (omits zlib header): - true, - ) + private val inflater = + Inflater( + // nowrap (omits zlib header): + true, + ) private val inflaterSource = InflaterSource(deflatedBytes, inflater) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/RealWebSocket.kt b/okhttp/src/main/kotlin/okhttp3/internal/ws/RealWebSocket.kt index 3cd4f65cdb12..a8dee727ad05 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/ws/RealWebSocket.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/ws/RealWebSocket.kt @@ -63,7 +63,7 @@ class RealWebSocket( */ private var extensions: WebSocketExtensions?, /** If compression is negotiated, outbound messages of this size and larger will be compressed. */ - private var minimumDeflateSize: Long + private var minimumDeflateSize: Long, ) : WebSocket, WebSocketReader.FrameCallback { private val key: String @@ -145,11 +145,13 @@ class RealWebSocket( return } - val webSocketClient = client.newBuilder() + val webSocketClient = + client.newBuilder() .eventListener(EventListener.NONE) .protocols(ONLY_HTTP1) .build() - val request = originalRequest.newBuilder() + val request = + originalRequest.newBuilder() .header("Upgrade", "websocket") .header("Connection", "Upgrade") .header("Sec-WebSocket-Key", key) @@ -157,41 +159,49 @@ class RealWebSocket( .header("Sec-WebSocket-Extensions", "permessage-deflate") .build() call = RealCall(webSocketClient, request, forWebSocket = true) - call!!.enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - val exchange = response.exchange - val streams: Streams - try { - checkUpgradeSuccess(response, exchange) - streams = exchange!!.newWebSocketStreams() - } catch (e: IOException) { - failWebSocket(e, response) - response.closeQuietly() - exchange?.webSocketUpgradeFailed() - return - } + call!!.enqueue( + object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + val exchange = response.exchange + val streams: Streams + try { + checkUpgradeSuccess(response, exchange) + streams = exchange!!.newWebSocketStreams() + } catch (e: IOException) { + failWebSocket(e, response) + response.closeQuietly() + exchange?.webSocketUpgradeFailed() + return + } - // Apply the extensions. If they're unacceptable initiate a graceful shut down. - // TODO(jwilson): Listeners should get onFailure() instead of onClosing() + onClosed(1010). - val extensions = WebSocketExtensions.parse(response.headers) - this@RealWebSocket.extensions = extensions - if (!extensions.isValid()) { - synchronized(this@RealWebSocket) { - messageAndCloseQueue.clear() // Don't transmit any messages. - close(1010, "unexpected Sec-WebSocket-Extensions in response header") + // Apply the extensions. If they're unacceptable initiate a graceful shut down. + // TODO(jwilson): Listeners should get onFailure() instead of onClosing() + onClosed(1010). + val extensions = WebSocketExtensions.parse(response.headers) + this@RealWebSocket.extensions = extensions + if (!extensions.isValid()) { + synchronized(this@RealWebSocket) { + messageAndCloseQueue.clear() // Don't transmit any messages. + close(1010, "unexpected Sec-WebSocket-Extensions in response header") + } } - } - // Process all web socket messages. - val name = "$okHttpName WebSocket ${request.url.redact()}" - initReaderAndWriter(name, streams) - loopReader(response) - } + // Process all web socket messages. + val name = "$okHttpName WebSocket ${request.url.redact()}" + initReaderAndWriter(name, streams) + loopReader(response) + } - override fun onFailure(call: Call, e: IOException) { - failWebSocket(e) - } - }) + override fun onFailure( + call: Call, + e: IOException, + ) { + failWebSocket(e) + } + }, + ) } private fun WebSocketExtensions.isValid(): Boolean { @@ -209,29 +219,36 @@ class RealWebSocket( } @Throws(IOException::class) - internal fun checkUpgradeSuccess(response: Response, exchange: Exchange?) { + internal fun checkUpgradeSuccess( + response: Response, + exchange: Exchange?, + ) { if (response.code != 101) { throw ProtocolException( - "Expected HTTP 101 response but was '${response.code} ${response.message}'") + "Expected HTTP 101 response but was '${response.code} ${response.message}'", + ) } val headerConnection = response.header("Connection") if (!"Upgrade".equals(headerConnection, ignoreCase = true)) { throw ProtocolException( - "Expected 'Connection' header value 'Upgrade' but was '$headerConnection'") + "Expected 'Connection' header value 'Upgrade' but was '$headerConnection'", + ) } val headerUpgrade = response.header("Upgrade") if (!"websocket".equals(headerUpgrade, ignoreCase = true)) { throw ProtocolException( - "Expected 'Upgrade' header value 'websocket' but was '$headerUpgrade'") + "Expected 'Upgrade' header value 'websocket' but was '$headerUpgrade'", + ) } val headerAccept = response.header("Sec-WebSocket-Accept") val acceptExpected = (key + WebSocketProtocol.ACCEPT_MAGIC).encodeUtf8().sha1().base64() if (acceptExpected != headerAccept) { throw ProtocolException( - "Expected 'Sec-WebSocket-Accept' header value '$acceptExpected' but was '$headerAccept'") + "Expected 'Sec-WebSocket-Accept' header value '$acceptExpected' but was '$headerAccept'", + ) } if (exchange == null) { @@ -239,19 +256,23 @@ class RealWebSocket( } } - fun initReaderAndWriter(name: String, streams: Streams) { + fun initReaderAndWriter( + name: String, + streams: Streams, + ) { val extensions = this.extensions!! synchronized(this) { this.name = name this.streams = streams - this.writer = WebSocketWriter( + this.writer = + WebSocketWriter( isClient = streams.client, sink = streams.sink, random = random, perMessageDeflate = extensions.perMessageDeflate, noContextTakeover = extensions.noContextTakeover(streams.client), - minimumDeflateSize = minimumDeflateSize - ) + minimumDeflateSize = minimumDeflateSize, + ) this.writerTask = WriterTask() if (pingIntervalMillis != 0L) { val pingIntervalNanos = MILLISECONDS.toNanos(pingIntervalMillis) @@ -265,13 +286,14 @@ class RealWebSocket( } } - reader = WebSocketReader( + reader = + WebSocketReader( isClient = streams.client, source = streams.source, frameCallback = this, perMessageDeflate = extensions.perMessageDeflate, - noContextTakeover = extensions.noContextTakeover(!streams.client) - ) + noContextTakeover = extensions.noContextTakeover(!streams.client), + ) } /** Receive frames until there are no more. Invoked only by the reader thread. */ @@ -336,10 +358,11 @@ class RealWebSocket( this.taskQueue.shutdown() } - streamsToClose = when { - writer == null -> streams - else -> null - } + streamsToClose = + when { + writer == null -> streams + else -> null + } } if (!failed && streamsToClose != null && receivedCloseCode != -1) { @@ -388,7 +411,10 @@ class RealWebSocket( awaitingPong = false } - override fun onReadClose(code: Int, reason: String) { + override fun onReadClose( + code: Int, + reason: String, + ) { require(code != -1) synchronized(this) { @@ -410,7 +436,10 @@ class RealWebSocket( return send(bytes, OPCODE_BINARY) } - @Synchronized private fun send(data: ByteString, formatOpcode: Int): Boolean { + @Synchronized private fun send( + data: ByteString, + formatOpcode: Int, + ): Boolean { // Don't send new frames after we've failed or enqueued a close frame. if (failed || enqueuedClose) return false @@ -436,14 +465,17 @@ class RealWebSocket( return true } - override fun close(code: Int, reason: String?): Boolean { + override fun close( + code: Int, + reason: String?, + ): Boolean { return close(code, reason, CANCEL_AFTER_CLOSE_MILLIS) } @Synchronized fun close( code: Int, reason: String?, - cancelAfterCloseMillis: Long + cancelAfterCloseMillis: Long, ): Boolean { validateCloseCode(code) @@ -513,10 +545,11 @@ class RealWebSocket( if (receivedCloseCode != -1) { writerToClose = this.writer this.writer = null - streamsToClose = when { - writerToClose != null && reader == null -> this.streams - else -> null - } + streamsToClose = + when { + writerToClose != null && reader == null -> this.streams + else -> null + } this.taskQueue.shutdown() } else { // When we request a graceful close also schedule a cancel of the web socket. @@ -572,10 +605,11 @@ class RealWebSocket( if (failedPing != -1) { failWebSocket( - e = SocketTimeoutException( - "sent ping but didn't receive pong within " + - "${pingIntervalMillis}ms (after ${failedPing - 1} successful ping/pongs)" - ), + e = + SocketTimeoutException( + "sent ping but didn't receive pong within " + + "${pingIntervalMillis}ms (after ${failedPing - 1} successful ping/pongs)", + ), isWriter = true, ) return @@ -605,10 +639,11 @@ class RealWebSocket( writerToClose = this.writer this.writer = null - streamsToClose = when { - writerToClose != null && reader == null -> this.streams - else -> null - } + streamsToClose = + when { + writerToClose != null && reader == null -> this.streams + else -> null + } if (!isWriter && writerToClose != null) { // If the caller isn't the writer thread, get that thread to close the writer. @@ -636,19 +671,19 @@ class RealWebSocket( internal class Message( val formatOpcode: Int, - val data: ByteString + val data: ByteString, ) internal class Close( val code: Int, val reason: ByteString?, - val cancelAfterCloseMillis: Long + val cancelAfterCloseMillis: Long, ) abstract class Streams( val client: Boolean, val source: BufferedSource, - val sink: BufferedSink + val sink: BufferedSink, ) : Closeable { abstract fun cancel() } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt b/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt index 697682d13ad9..4b88e5c32368 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt @@ -61,26 +61,20 @@ import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement data class WebSocketExtensions( /** True if the agreed upon extensions includes the permessage-deflate extension. */ @JvmField val perMessageDeflate: Boolean = false, - /** Should be a value in [8..15]. Only 15 is acceptable by OkHttp as Java APIs are limited. */ @JvmField val clientMaxWindowBits: Int? = null, - /** True if the agreed upon extension parameters includes "client_no_context_takeover". */ @JvmField val clientNoContextTakeover: Boolean = false, - /** Should be a value in [8..15]. Any value in that range is acceptable by OkHttp. */ @JvmField val serverMaxWindowBits: Int? = null, - /** True if the agreed upon extension parameters includes "server_no_context_takeover". */ @JvmField val serverNoContextTakeover: Boolean = false, - /** * True if the agreed upon extensions or parameters contained values unrecognized by OkHttp. * Typically this indicates that the client will need to close the web socket with code 1010. */ - @JvmField val unknownValues: Boolean = false + @JvmField val unknownValues: Boolean = false, ) { - fun noContextTakeover(clientOriginated: Boolean): Boolean { return if (clientOriginated) { clientNoContextTakeover // Client is deflating. @@ -129,11 +123,12 @@ data class WebSocketExtensions( val parameterEnd = header.delimiterOffset(';', pos, extensionEnd) val equals = header.delimiterOffset('=', pos, parameterEnd) val name = header.trimSubstring(pos, equals) - val value = if (equals < parameterEnd) { - header.trimSubstring(equals + 1, parameterEnd).removeSurrounding("\"") - } else { - null - } + val value = + if (equals < parameterEnd) { + header.trimSubstring(equals + 1, parameterEnd).removeSurrounding("\"") + } else { + null + } pos = parameterEnd + 1 when { name.equals("client_max_window_bits", ignoreCase = true) -> { @@ -171,12 +166,12 @@ data class WebSocketExtensions( } return WebSocketExtensions( - perMessageDeflate = compressionEnabled, - clientMaxWindowBits = clientMaxWindowBits, - clientNoContextTakeover = clientNoContextTakeover, - serverMaxWindowBits = serverMaxWindowBits, - serverNoContextTakeover = serverNoContextTakeover, - unknownValues = unexpectedValues + perMessageDeflate = compressionEnabled, + clientMaxWindowBits = clientMaxWindowBits, + clientNoContextTakeover = clientNoContextTakeover, + serverMaxWindowBits = serverMaxWindowBits, + serverNoContextTakeover = serverNoContextTakeover, + unknownValues = unexpectedValues, ) } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt b/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt index 58bdda788df2..0d41593abd29 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt @@ -32,18 +32,23 @@ object WebSocketProtocol { |N|V|V|V| | |S| | | |1|2|3| | |K| | +-+-+-+-+-------+ +-+-------------+ - */ + */ /** Byte 0 flag for whether this is the final fragment in a message. */ internal const val B0_FLAG_FIN = 128 + /** Byte 0 reserved flag 1. Must be 0 unless negotiated otherwise. */ internal const val B0_FLAG_RSV1 = 64 + /** Byte 0 reserved flag 2. Must be 0 unless negotiated otherwise. */ internal const val B0_FLAG_RSV2 = 32 + /** Byte 0 reserved flag 3. Must be 0 unless negotiated otherwise. */ internal const val B0_FLAG_RSV3 = 16 + /** Byte 0 mask for the frame opcode. */ internal const val B0_MASK_OPCODE = 15 + /** Flag in the opcode which indicates a control frame. */ internal const val OPCODE_FLAG_CONTROL = 8 @@ -54,6 +59,7 @@ object WebSocketProtocol { * bytes represent the mask key. These bytes appear after any additional bytes specified by [B1_MASK_LENGTH]. */ internal const val B1_FLAG_MASK = 128 + /** * Byte 1 mask for the payload length. * @@ -76,14 +82,18 @@ object WebSocketProtocol { * special values [PAYLOAD_SHORT] or [PAYLOAD_LONG]. */ internal const val PAYLOAD_BYTE_MAX = 125L + /** Maximum length of close message in bytes. */ internal const val CLOSE_MESSAGE_MAX = PAYLOAD_BYTE_MAX - 2 + /** * Value for [B1_MASK_LENGTH] which indicates the next two bytes are the unsigned length. */ internal const val PAYLOAD_SHORT = 126 + /** Maximum length of a frame payload to be denoted as [PAYLOAD_SHORT]. */ internal const val PAYLOAD_SHORT_MAX = 0xffffL + /** * Value for [B1_MASK_LENGTH] which indicates the next eight bytes are the unsigned * length. @@ -92,10 +102,14 @@ object WebSocketProtocol { /** Used when an unchecked exception was thrown in a listener. */ internal const val CLOSE_CLIENT_GOING_AWAY = 1001 + /** Used when an empty close frame was received (i.e., without a status code). */ internal const val CLOSE_NO_STATUS_CODE = 1005 - fun toggleMask(cursor: Buffer.UnsafeCursor, key: ByteArray) { + fun toggleMask( + cursor: Buffer.UnsafeCursor, + key: ByteArray, + ) { var keyIndex = 0 val keyLength = key.size do { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketReader.kt b/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketReader.kt index 6d306cbcd9b4..42fa7d8034e8 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketReader.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketReader.kt @@ -56,7 +56,7 @@ class WebSocketReader( val source: BufferedSource, private val frameCallback: FrameCallback, private val perMessageDeflate: Boolean, - private val noContextTakeover: Boolean + private val noContextTakeover: Boolean, ) : Closeable { private var closed = false @@ -85,8 +85,13 @@ class WebSocketReader( fun onReadMessage(bytes: ByteString) fun onReadPing(payload: ByteString) + fun onReadPong(payload: ByteString) - fun onReadClose(code: Int, reason: String) + + fun onReadClose( + code: Int, + reason: String, + ) } /** @@ -133,12 +138,13 @@ class WebSocketReader( val reservedFlag1 = b0 and B0_FLAG_RSV1 != 0 when (opcode) { OPCODE_TEXT, OPCODE_BINARY -> { - readingCompressedMessage = if (reservedFlag1) { - if (!perMessageDeflate) throw ProtocolException("Unexpected rsv1 flag") - true - } else { - false - } + readingCompressedMessage = + if (reservedFlag1) { + if (!perMessageDeflate) throw ProtocolException("Unexpected rsv1 flag") + true + } else { + false + } } else -> { if (reservedFlag1) throw ProtocolException("Unexpected rsv1 flag") @@ -156,11 +162,13 @@ class WebSocketReader( val isMasked = b1 and B1_FLAG_MASK != 0 if (isMasked == isClient) { // Masked payloads must be read on the server. Unmasked payloads must be read on the client. - throw ProtocolException(if (isClient) { - "Server-sent frames must not be masked." - } else { - "Client-sent frames must be masked." - }) + throw ProtocolException( + if (isClient) { + "Server-sent frames must not be masked." + } else { + "Client-sent frames must be masked." + }, + ) } // Get frame length, optionally reading from follow-up bytes if indicated by special values. @@ -171,7 +179,8 @@ class WebSocketReader( frameLength = source.readLong() if (frameLength < 0L) { throw ProtocolException( - "Frame length 0x${frameLength.toHexString()} > 0x7FFFFFFFFFFFFFFF") + "Frame length 0x${frameLength.toHexString()} > 0x7FFFFFFFFFFFFFFF", + ) } } @@ -236,7 +245,8 @@ class WebSocketReader( readMessage() if (readingCompressedMessage) { - val messageInflater = this.messageInflater + val messageInflater = + this.messageInflater ?: MessageInflater(noContextTakeover).also { this.messageInflater = it } messageInflater.inflate(messageFrameBuffer) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketWriter.kt b/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketWriter.kt index 0b61c43ee6cb..29a3b501f2bf 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketWriter.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketWriter.kt @@ -47,7 +47,7 @@ class WebSocketWriter( val random: Random, private val perMessageDeflate: Boolean, private val noContextTakeover: Boolean, - private val minimumDeflateSize: Long + private val minimumDeflateSize: Long, ) : Closeable { /** This holds outbound data for compression and masking. */ private val messageBuffer = Buffer() @@ -83,19 +83,23 @@ class WebSocketWriter( * @param reason Reason for shutting down or `null`. */ @Throws(IOException::class) - fun writeClose(code: Int, reason: ByteString?) { + fun writeClose( + code: Int, + reason: ByteString?, + ) { var payload = ByteString.EMPTY if (code != 0 || reason != null) { if (code != 0) { validateCloseCode(code) } - payload = Buffer().run { - writeShort(code) - if (reason != null) { - write(reason) + payload = + Buffer().run { + writeShort(code) + if (reason != null) { + write(reason) + } + readByteString() } - readByteString() - } } try { @@ -106,7 +110,10 @@ class WebSocketWriter( } @Throws(IOException::class) - private fun writeControlFrame(opcode: Int, payload: ByteString) { + private fun writeControlFrame( + opcode: Int, + payload: ByteString, + ) { if (writerClosed) throw IOException("closed") val length = payload.size @@ -143,14 +150,18 @@ class WebSocketWriter( } @Throws(IOException::class) - fun writeMessageFrame(formatOpcode: Int, data: ByteString) { + fun writeMessageFrame( + formatOpcode: Int, + data: ByteString, + ) { if (writerClosed) throw IOException("closed") messageBuffer.write(data) var b0 = formatOpcode or B0_FLAG_FIN if (perMessageDeflate && data.size >= minimumDeflateSize) { - val messageDeflater = this.messageDeflater + val messageDeflater = + this.messageDeflater ?: MessageDeflater(noContextTakeover).also { this.messageDeflater = it } messageDeflater.deflate(messageBuffer) b0 = b0 or B0_FLAG_RSV1 diff --git a/okhttp/src/main/kotlinTemplates/okhttp3/internal/-InternalVersion.kt b/okhttp/src/main/kotlinTemplates/okhttp3/internal/-InternalVersion.kt index fac79c90d16c..47a5787a73e6 100644 --- a/okhttp/src/main/kotlinTemplates/okhttp3/internal/-InternalVersion.kt +++ b/okhttp/src/main/kotlinTemplates/okhttp3/internal/-InternalVersion.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3.internal internal const val CONST_VERSION = "$projectVersion" diff --git a/okhttp/src/test/java/okhttp3/AddressTest.kt b/okhttp/src/test/java/okhttp3/AddressTest.kt index 0392841d326b..24db060ffd21 100644 --- a/okhttp/src/test/java/okhttp3/AddressTest.kt +++ b/okhttp/src/test/java/okhttp3/AddressTest.kt @@ -24,10 +24,11 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test class AddressTest { - private val factory = TestValueFactory().apply { - uriHost = "example.com" - uriPort = 80 - } + private val factory = + TestValueFactory().apply { + uriHost = "example.com" + uriPort = 80 + } @AfterEach fun tearDown() { factory.close() diff --git a/okhttp/src/test/java/okhttp3/AutobahnTester.kt b/okhttp/src/test/java/okhttp3/AutobahnTester.kt index cb309de3327d..ed313031fe51 100644 --- a/okhttp/src/test/java/okhttp3/AutobahnTester.kt +++ b/okhttp/src/test/java/okhttp3/AutobahnTester.kt @@ -29,10 +29,14 @@ import okio.ByteString class AutobahnTester { val client = OkHttpClient() - private fun newWebSocket(path: String, listener: WebSocketListener): WebSocket { - val request = Request.Builder() - .url(HOST + path) - .build() + private fun newWebSocket( + path: String, + listener: WebSocketListener, + ): WebSocket { + val request = + Request.Builder() + .url(HOST + path) + .build() return client.newWebSocket(request, listener) } @@ -49,33 +53,56 @@ class AutobahnTester { } } - private fun runTest(number: Long, count: Long) { + private fun runTest( + number: Long, + count: Long, + ) { val latch = CountDownLatch(1) val startNanos = AtomicLong() - newWebSocket("/runCase?case=$number&agent=okhttp", object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - println("Executing test case $number/$count") - startNanos.set(System.nanoTime()) - } - - override fun onMessage(webSocket: WebSocket, bytes: ByteString) { - webSocket.send(bytes) - } - - override fun onMessage(webSocket: WebSocket, text: String) { - webSocket.send(text) - } - - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - webSocket.close(1000, null) - latch.countDown() - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - t.printStackTrace(System.out) - latch.countDown() - } - }) + newWebSocket( + "/runCase?case=$number&agent=okhttp", + object : WebSocketListener() { + override fun onOpen( + webSocket: WebSocket, + response: Response, + ) { + println("Executing test case $number/$count") + startNanos.set(System.nanoTime()) + } + + override fun onMessage( + webSocket: WebSocket, + bytes: ByteString, + ) { + webSocket.send(bytes) + } + + override fun onMessage( + webSocket: WebSocket, + text: String, + ) { + webSocket.send(text) + } + + override fun onClosing( + webSocket: WebSocket, + code: Int, + reason: String, + ) { + webSocket.close(1000, null) + latch.countDown() + } + + override fun onFailure( + webSocket: WebSocket, + t: Throwable, + response: Response?, + ) { + t.printStackTrace(System.out) + latch.countDown() + } + }, + ) check(latch.await(30, TimeUnit.SECONDS)) { "Timed out waiting for test $number to finish." } val endNanos = System.nanoTime() @@ -88,21 +115,35 @@ class AutobahnTester { val countRef = AtomicLong() val failureRef = AtomicReference() - newWebSocket("/getCaseCount", object : WebSocketListener() { - override fun onMessage(webSocket: WebSocket, text: String) { - countRef.set(text.toLong()) - } - - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - webSocket.close(1000, null) - latch.countDown() - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - failureRef.set(t) - latch.countDown() - } - }) + newWebSocket( + "/getCaseCount", + object : WebSocketListener() { + override fun onMessage( + webSocket: WebSocket, + text: String, + ) { + countRef.set(text.toLong()) + } + + override fun onClosing( + webSocket: WebSocket, + code: Int, + reason: String, + ) { + webSocket.close(1000, null) + latch.countDown() + } + + override fun onFailure( + webSocket: WebSocket, + t: Throwable, + response: Response?, + ) { + failureRef.set(t) + latch.countDown() + } + }, + ) check(latch.await(10, TimeUnit.SECONDS)) { "Timed out waiting for count." } @@ -116,16 +157,27 @@ class AutobahnTester { private fun updateReports() { val latch = CountDownLatch(1) - newWebSocket("/updateReports?agent=$USER_AGENT", object : WebSocketListener() { - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - webSocket.close(1000, null) - latch.countDown() - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - latch.countDown() - } - }) + newWebSocket( + "/updateReports?agent=$USER_AGENT", + object : WebSocketListener() { + override fun onClosing( + webSocket: WebSocket, + code: Int, + reason: String, + ) { + webSocket.close(1000, null) + latch.countDown() + } + + override fun onFailure( + webSocket: WebSocket, + t: Throwable, + response: Response?, + ) { + latch.countDown() + } + }, + ) check(latch.await(10, TimeUnit.SECONDS)) { "Timed out waiting for count." } } diff --git a/okhttp/src/test/java/okhttp3/BouncyCastleTest.kt b/okhttp/src/test/java/okhttp3/BouncyCastleTest.kt index 502ea04d89b7..b857692ea0f4 100644 --- a/okhttp/src/test/java/okhttp3/BouncyCastleTest.kt +++ b/okhttp/src/test/java/okhttp3/BouncyCastleTest.kt @@ -25,8 +25,11 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension class BouncyCastleTest { - @JvmField @RegisterExtension var platform = PlatformRule() - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule() + @JvmField @RegisterExtension + var platform = PlatformRule() + + @JvmField @RegisterExtension + val clientTestRule = OkHttpClientTestRule() var client = clientTestRule.newClient() private lateinit var server: MockWebServer diff --git a/okhttp/src/test/java/okhttp3/CacheControlJvmTest.kt b/okhttp/src/test/java/okhttp3/CacheControlJvmTest.kt index 1b109fb73ff2..666fbb238e05 100644 --- a/okhttp/src/test/java/okhttp3/CacheControlJvmTest.kt +++ b/okhttp/src/test/java/okhttp3/CacheControlJvmTest.kt @@ -30,19 +30,20 @@ class CacheControlJvmTest { @Test @Throws(Exception::class) fun completeBuilder() { - val cacheControl = CacheControl.Builder() - .noCache() - .noStore() - .maxAge(1, TimeUnit.SECONDS) - .maxStale(2, TimeUnit.SECONDS) - .minFresh(3, TimeUnit.SECONDS) - .onlyIfCached() - .noTransform() - .immutable() - .build() + val cacheControl = + CacheControl.Builder() + .noCache() + .noStore() + .maxAge(1, TimeUnit.SECONDS) + .maxStale(2, TimeUnit.SECONDS) + .minFresh(3, TimeUnit.SECONDS) + .onlyIfCached() + .noTransform() + .immutable() + .build() assertThat(cacheControl.toString()).isEqualTo( - "no-cache, no-store, max-age=1, max-stale=2, min-fresh=3, only-if-cached, " - + "no-transform, immutable" + "no-cache, no-store, max-age=1, max-stale=2, min-fresh=3, only-if-cached, " + + "no-transform, immutable", ) assertThat(cacheControl.noCache).isTrue() assertThat(cacheControl.noStore).isTrue() @@ -63,9 +64,10 @@ class CacheControlJvmTest { @Test @Throws(Exception::class) fun parseEmpty() { - val cacheControl = parse( - Headers.Builder().set("Cache-Control", "").build() - ) + val cacheControl = + parse( + Headers.Builder().set("Cache-Control", "").build(), + ) assertThat(cacheControl.toString()).isEqualTo("") assertThat(cacheControl.noCache).isFalse() assertThat(cacheControl.noStore).isFalse() @@ -82,13 +84,16 @@ class CacheControlJvmTest { @Test @Throws(Exception::class) fun parse() { - val header = ("no-cache, no-store, max-age=1, s-maxage=2, private, public, must-revalidate, " - + "max-stale=3, min-fresh=4, only-if-cached, no-transform") - val cacheControl = parse( - Headers.Builder() - .set("Cache-Control", header) - .build() + val header = ( + "no-cache, no-store, max-age=1, s-maxage=2, private, public, must-revalidate, " + + "max-stale=3, min-fresh=4, only-if-cached, no-transform" ) + val cacheControl = + parse( + Headers.Builder() + .set("Cache-Control", header) + .build(), + ) assertThat(cacheControl.noCache).isTrue() assertThat(cacheControl.noStore).isTrue() assertThat(cacheControl.maxAgeSeconds).isEqualTo(1) @@ -108,11 +113,12 @@ class CacheControlJvmTest { fun parseIgnoreCacheControlExtensions() { // Example from http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.6 val header = "private, community=\"UCI\"" - val cacheControl = parse( - Headers.Builder() - .set("Cache-Control", header) - .build() - ) + val cacheControl = + parse( + Headers.Builder() + .set("Cache-Control", header) + .build(), + ) assertThat(cacheControl.noCache).isFalse() assertThat(cacheControl.noStore).isFalse() assertThat(cacheControl.maxAgeSeconds).isEqualTo(-1) @@ -145,20 +151,26 @@ class CacheControlJvmTest { @Test fun parseCacheControlHeaderValueInvalidatedByPragma() { - val headers = headersOf( - "Cache-Control", "max-age=12", - "Pragma", "must-revalidate" - ) + val headers = + headersOf( + "Cache-Control", + "max-age=12", + "Pragma", + "must-revalidate", + ) val cacheControl = parse(headers) assertThat(cacheControl.toString()).isEqualTo("max-age=12, must-revalidate") } @Test fun parseCacheControlHeaderValueInvalidatedByTwoValues() { - val headers = headersOf( - "Cache-Control", "max-age=12", - "Cache-Control", "must-revalidate" - ) + val headers = + headersOf( + "Cache-Control", + "max-age=12", + "Cache-Control", + "must-revalidate", + ) val cacheControl = parse(headers) assertThat(cacheControl.toString()).isEqualTo("max-age=12, must-revalidate") } @@ -172,9 +184,10 @@ class CacheControlJvmTest { @Test fun computedHeaderValueIsCached() { - val cacheControl = CacheControl.Builder() - .maxAge(2, TimeUnit.DAYS) - .build() + val cacheControl = + CacheControl.Builder() + .maxAge(2, TimeUnit.DAYS) + .build() assertThat(cacheControl.toString()).isEqualTo("max-age=172800") assertThat(cacheControl.toString()).isSameAs(cacheControl.toString()) } @@ -182,9 +195,10 @@ class CacheControlJvmTest { @Test @Throws(Exception::class) fun timeDurationTruncatedToMaxValue() { - val cacheControl = CacheControl.Builder() - .maxAge(365 * 100, TimeUnit.DAYS) // Longer than Integer.MAX_VALUE seconds. - .build() + val cacheControl = + CacheControl.Builder() + .maxAge(365 * 100, TimeUnit.DAYS) // Longer than Integer.MAX_VALUE seconds. + .build() assertThat(cacheControl.maxAgeSeconds).isEqualTo(Int.MAX_VALUE) } @@ -200,9 +214,10 @@ class CacheControlJvmTest { @Test @Throws(Exception::class) fun timePrecisionIsTruncatedToSeconds() { - val cacheControl = CacheControl.Builder() - .maxAge(4999, TimeUnit.MILLISECONDS) - .build() + val cacheControl = + CacheControl.Builder() + .maxAge(4999, TimeUnit.MILLISECONDS) + .build() assertThat(cacheControl.maxAgeSeconds).isEqualTo(4) } } diff --git a/okhttp/src/test/java/okhttp3/CacheControlTest.kt b/okhttp/src/test/java/okhttp3/CacheControlTest.kt index 162f5b9acbdc..d7d3e904df0b 100644 --- a/okhttp/src/test/java/okhttp3/CacheControlTest.kt +++ b/okhttp/src/test/java/okhttp3/CacheControlTest.kt @@ -44,18 +44,19 @@ class CacheControlTest { @Test @Throws(Exception::class) fun completeBuilder() { - val cacheControl = CacheControl.Builder() - .noCache() - .noStore() - .maxAge(1, DurationUnit.SECONDS) - .maxStale(2, DurationUnit.SECONDS) - .minFresh(3, DurationUnit.SECONDS) - .onlyIfCached() - .noTransform() - .immutable() - .build() + val cacheControl = + CacheControl.Builder() + .noCache() + .noStore() + .maxAge(1, DurationUnit.SECONDS) + .maxStale(2, DurationUnit.SECONDS) + .minFresh(3, DurationUnit.SECONDS) + .onlyIfCached() + .noTransform() + .immutable() + .build() assertThat(cacheControl.toString()).isEqualTo( - "no-cache, no-store, max-age=1, max-stale=2, min-fresh=3, only-if-cached, no-transform, immutable" + "no-cache, no-store, max-age=1, max-stale=2, min-fresh=3, only-if-cached, no-transform, immutable", ) assertThat(cacheControl.noCache).isTrue() assertThat(cacheControl.noStore).isTrue() diff --git a/okhttp/src/test/java/okhttp3/CacheCorruptionTest.kt b/okhttp/src/test/java/okhttp3/CacheCorruptionTest.kt index f0bfc54a0cc9..7a762dc50575 100644 --- a/okhttp/src/test/java/okhttp3/CacheCorruptionTest.kt +++ b/okhttp/src/test/java/okhttp3/CacheCorruptionTest.kt @@ -68,10 +68,11 @@ class CacheCorruptionTest { server.protocolNegotiationEnabled = false val loggingFileSystem = LoggingFilesystem(fileSystem) cache = buildCache("/cache/".toPath(), Int.MAX_VALUE.toLong(), loggingFileSystem) - client = clientTestRule.newClientBuilder() - .cache(cache) - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + clientTestRule.newClientBuilder() + .cache(cache) + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() } @AfterEach @@ -84,12 +85,13 @@ class CacheCorruptionTest { @Test fun corruptedCipher() { - val response = testCorruptingCache { - corruptMetadata { - // mess with cipher suite - it.replace("TLS_", "SLT_") + val response = + testCorruptingCache { + corruptMetadata { + // mess with cipher suite + it.replace("TLS_", "SLT_") + } } - } assertThat(response.body.string()).isEqualTo("ABC.1") // cached assertThat(cache.requestCount()).isEqualTo(2) @@ -101,12 +103,13 @@ class CacheCorruptionTest { @Test fun truncatedMetadataEntry() { - val response = testCorruptingCache { - corruptMetadata { - // truncate metadata to 1/4 of length - it.substring(0, it.length / 4) + val response = + testCorruptingCache { + corruptMetadata { + // truncate metadata to 1/4 of length + it.substring(0, it.length / 4) + } } - } assertThat(response.body.string()).isEqualTo("ABC.2") // not cached assertThat(cache.requestCount()).isEqualTo(2) @@ -115,12 +118,13 @@ class CacheCorruptionTest { } @Test fun corruptedUrl() { - val response = testCorruptingCache { - corruptMetadata { - // strip https scheme - it.substring(5) + val response = + testCorruptingCache { + corruptMetadata { + // strip https scheme + it.substring(5) + } } - } assertThat(response.body.string()).isEqualTo("ABC.2") // not cached assertThat(cache.requestCount()).isEqualTo(2) @@ -129,14 +133,16 @@ class CacheCorruptionTest { } private fun corruptMetadata(corruptor: (String) -> String) { - val metadataFile = fileSystem.allPaths.find { - it.name.endsWith(".0") - } + val metadataFile = + fileSystem.allPaths.find { + it.name.endsWith(".0") + } if (metadataFile != null) { - val contents = fileSystem.read(metadataFile) { - readUtf8() - } + val contents = + fileSystem.read(metadataFile) { + readUtf8() + } fileSystem.write(metadataFile) { writeUtf8(corruptor(contents)) @@ -148,28 +154,35 @@ class CacheCorruptionTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue( MockResponse( - headers = headersOf( - "Last-Modified", formatDate(-1, TimeUnit.HOURS)!!, - "Expires", formatDate(1, TimeUnit.HOURS)!!, - ), + headers = + headersOf( + "Last-Modified", + formatDate(-1, TimeUnit.HOURS)!!, + "Expires", + formatDate(1, TimeUnit.HOURS)!!, + ), body = "ABC.1", - ) + ), ) server.enqueue( MockResponse( - headers = headersOf( - "Last-Modified", formatDate(-1, TimeUnit.HOURS)!!, - "Expires", formatDate(1, TimeUnit.HOURS)!!, - ), + headers = + headersOf( + "Last-Modified", + formatDate(-1, TimeUnit.HOURS)!!, + "Expires", + formatDate(1, TimeUnit.HOURS)!!, + ), body = "ABC.2", - ) + ), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(nullHostnameVerifier) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(nullHostnameVerifier) + .build() val request = Request(server.url("/")) val response1: Response = client.newCall(request).execute() val bodySource = response1.body.source() @@ -184,7 +197,10 @@ class CacheCorruptionTest { * @param delta the offset from the current date to use. Negative values yield dates in the past; * positive values yield dates in the future. */ - private fun formatDate(delta: Long, timeUnit: TimeUnit): String? { + private fun formatDate( + delta: Long, + timeUnit: TimeUnit, + ): String? { return formatDate(Date(System.currentTimeMillis() + timeUnit.toMillis(delta))) } diff --git a/okhttp/src/test/java/okhttp3/CacheTest.kt b/okhttp/src/test/java/okhttp3/CacheTest.kt index fd8d4ce95123..696b7496b0cf 100644 --- a/okhttp/src/test/java/okhttp3/CacheTest.kt +++ b/okhttp/src/test/java/okhttp3/CacheTest.kt @@ -93,10 +93,11 @@ class CacheTest { server.protocolNegotiationEnabled = false fileSystem.emulateUnix() cache = Cache("/cache/".toPath(), Long.MAX_VALUE, fileSystem) - client = clientTestRule.newClientBuilder() - .cache(cache) - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + clientTestRule.newClientBuilder() + .cache(cache) + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() } @AfterEach @@ -123,7 +124,7 @@ class CacheTest { assertCached(true, 203) assertCached(true, 204) assertCached(false, 205) - assertCached(false, 206) //Electing to not cache partial responses + assertCached(false, 206) // Electing to not cache partial responses assertCached(false, 207) assertCached(true, 300) assertCached(true, 301) @@ -168,15 +169,19 @@ class CacheTest { assertSubsequentResponseCached(103, 200) } - private fun assertCached(shouldWriteToCache: Boolean, responseCode: Int) { + private fun assertCached( + shouldWriteToCache: Boolean, + responseCode: Int, + ) { var expectedResponseCode = responseCode server = MockWebServer() - val builder = MockResponse.Builder() - .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) - .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .code(responseCode) - .body("ABCDE") - .addHeader("WWW-Authenticate: challenge") + val builder = + MockResponse.Builder() + .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) + .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) + .code(responseCode) + .body("ABCDE") + .addHeader("WWW-Authenticate: challenge") when (responseCode) { HttpURLConnection.HTTP_PROXY_AUTH -> { builder.addHeader("Proxy-Authenticate: Basic realm=\"protected area\"") @@ -200,13 +205,14 @@ class CacheTest { MockResponse.Builder() .setHeader("Cache-Control", "no-store") .body("FGHIJ") - .build() + .build(), ) } server.start() - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(expectedResponseCode) @@ -222,19 +228,24 @@ class CacheTest { server.shutdown() // tearDown() isn't sufficient; this test starts multiple servers } - private fun assertSubsequentResponseCached(initialResponseCode: Int, finalResponseCode: Int) { + private fun assertSubsequentResponseCached( + initialResponseCode: Int, + finalResponseCode: Int, + ) { server = MockWebServer() - val builder = MockResponse.Builder() - .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) - .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .code(finalResponseCode) - .body("ABCDE") - .addInformationalResponse(MockResponse(initialResponseCode)) + val builder = + MockResponse.Builder() + .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) + .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) + .code(finalResponseCode) + .body("ABCDE") + .addInformationalResponse(MockResponse(initialResponseCode)) server.enqueue(builder.build()) server.start() - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(finalResponseCode) @@ -266,10 +277,11 @@ class CacheTest { * http://code.google.com/p/android/issues/detail?id=8175 */ private fun testResponseCaching(transferKind: TransferKind) { - val mockResponse = MockResponse.Builder() - .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) - .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .status("HTTP/1.1 200 Fantastic") + val mockResponse = + MockResponse.Builder() + .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) + .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) + .status("HTTP/1.1 200 Fantastic") transferKind.setBody(mockResponse, "I love puppies but hate spiders", 1) server.enqueue(mockResponse.build()) @@ -288,7 +300,7 @@ class CacheTest { val in2 = response2.body.source() assertThat(in2.readUtf8("I love puppies but hate spiders".length.toLong())) .isEqualTo( - "I love puppies but hate spiders" + "I love puppies but hate spiders", ) assertThat(response2.code).isEqualTo(200) assertThat(response2.message).isEqualTo("Fantastic") @@ -308,14 +320,15 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .body("ABC") - .build() + .build(), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(NULL_HOSTNAME_VERIFIER) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(NULL_HOSTNAME_VERIFIER) + .build() val request = Request.Builder().url(server.url("/")).build() val response1 = client.newCall(request).execute() val source = response1.body.source() @@ -347,28 +360,30 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .body("ABC") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Last-Modified: " + formatDate(-5, TimeUnit.MINUTES)) .addHeader("Expires: " + formatDate(2, TimeUnit.HOURS)) .body("DEF") - .build() + .build(), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(NULL_HOSTNAME_VERIFIER) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(NULL_HOSTNAME_VERIFIER) + .build() val request = Request.Builder().url(server.url("/")).build() val response1 = client.newCall(request).execute() assertThat(response1.body.string()).isEqualTo("ABC") - val cacheEntry = fileSystem.allPaths.stream() - .filter { e: Path -> e.name.endsWith(".0") } - .findFirst() - .orElseThrow { NoSuchElementException() } + val cacheEntry = + fileSystem.allPaths.stream() + .filter { e: Path -> e.name.endsWith(".0") } + .findFirst() + .orElseThrow { NoSuchElementException() } corruptCertificate(cacheEntry) val response2 = client.newCall(request).execute() // Not Cached! assertThat(response2.body.string()).isEqualTo("DEF") @@ -391,19 +406,19 @@ class CacheTest { .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .code(HttpURLConnection.HTTP_MOVED_PERM) .addHeader("Location: /foo") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .body("ABC") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("DEF") - .build() + .build(), ) val request = Request.Builder().url(server.url("/")).build() val response1 = client.newCall(request).execute() @@ -423,18 +438,18 @@ class CacheTest { MockResponse.Builder() .addHeader("Cache-Control: max-age=60") .body("ABC") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_PERM) .addHeader("Location: /foo") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("DEF") - .build() + .build(), ) val request1 = Request.Builder().url(server.url("/foo")).build() val response1 = client.newCall(request1).execute() @@ -467,26 +482,27 @@ class CacheTest { .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .code(HttpURLConnection.HTTP_MOVED_PERM) .addHeader("Location: /foo") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .body("ABC") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("DEF") - .build() + .build(), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(NULL_HOSTNAME_VERIFIER) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(NULL_HOSTNAME_VERIFIER) + .build() val response1 = get(server.url("/")) assertThat(response1.body.string()).isEqualTo("ABC") assertThat(response1.handshake!!.cipherSuite).isNotNull() @@ -500,7 +516,7 @@ class CacheTest { assertThat(cache.requestCount()).isEqualTo(4) assertThat(cache.hitCount()).isEqualTo(2) assertThat(response2.handshake!!.cipherSuite).isEqualTo( - response1.handshake!!.cipherSuite + response1.handshake!!.cipherSuite, ) } @@ -519,12 +535,12 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .body("ABC") - .build() + .build(), ) server2.enqueue( MockResponse.Builder() .body("DEF") - .build() + .build(), ) server.enqueue( MockResponse.Builder() @@ -532,14 +548,15 @@ class CacheTest { .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .code(HttpURLConnection.HTTP_MOVED_PERM) .addHeader("Location: " + server2.url("/")) - .build() + .build(), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(NULL_HOSTNAME_VERIFIER) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(NULL_HOSTNAME_VERIFIER) + .build() val response1 = get(server.url("/")) assertThat(response1.body.string()).isEqualTo("ABC") @@ -592,23 +609,23 @@ class CacheTest { .code(responseCode) .addHeader(headerName, headerValue) .addHeader("Location", "/a") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader(headerName, headerValue) .body("a") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("b") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("c") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("a") @@ -620,17 +637,17 @@ class CacheTest { MockResponse.Builder() .code(responseCode) .addHeader("Location", "/a") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("a") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("b") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("a") @@ -645,17 +662,17 @@ class CacheTest { .code(301) .addHeader("Cache-Control: max-age=60") .addHeader("Location: /bar") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("ABC") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("ABC") - .build() + .build(), ) val request1 = Request.Builder().url(server.url("/")).build() val response1 = client.newCall(request1).execute() @@ -689,7 +706,7 @@ class CacheTest { server.enqueue( MockResponse.Builder() .body("Request #2") - .build() + .build(), ) val bodySource = get(server.url("/")).body.source() assertThat(bodySource.readUtf8Line()).isEqualTo("ABCDE") @@ -723,14 +740,15 @@ class CacheTest { private fun testClientPrematureDisconnect(transferKind: TransferKind) { // Setting a low transfer speed ensures that stream discarding will time out. - val builder = MockResponse.Builder() - .throttleBody(6, 1, TimeUnit.SECONDS) + val builder = + MockResponse.Builder() + .throttleBody(6, 1, TimeUnit.SECONDS) transferKind.setBody(builder, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024) server.enqueue(builder.build()) server.enqueue( MockResponse.Builder() .body("Request #2") - .build() + .build(), ) val response1 = get(server.url("/")) val source = response1.body.source() @@ -758,7 +776,7 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) .body("A") - .build() + .build(), ) val url = server.url("/") val response1 = get(url) @@ -775,12 +793,13 @@ class CacheTest { // default lifetime: (115 - 15) / 10 = 10 seconds // expires: 10 seconds from served date = 5 seconds ago val lastModifiedDate = formatDate(-115, TimeUnit.SECONDS) - val conditionalRequest = assertConditionallyCached( - MockResponse.Builder() - .addHeader("Last-Modified: $lastModifiedDate") - .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS)) - .build() - ) + val conditionalRequest = + assertConditionallyCached( + MockResponse.Builder() + .addHeader("Last-Modified: $lastModifiedDate") + .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS)) + .build(), + ) assertThat(conditionalRequest.headers["If-Modified-Since"]) .isEqualTo(lastModifiedDate) } @@ -796,13 +815,13 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) .body("A") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") val response = get(server.url("/")) assertThat(response.body.string()).isEqualTo("A") assertThat(response.header("Warning")).isEqualTo( - "113 HttpURLConnection \"Heuristic expiration\"" + "113 HttpURLConnection \"Heuristic expiration\"", ) } @@ -813,12 +832,12 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/").newBuilder().addQueryParameter("foo", "bar").build() assertThat(get(url).body.string()).isEqualTo("A") @@ -828,12 +847,13 @@ class CacheTest { @Test fun expirationDateInThePastWithLastModifiedHeader() { val lastModifiedDate = formatDate(-2, TimeUnit.HOURS) - val conditionalRequest = assertConditionallyCached( - MockResponse.Builder() - .addHeader("Last-Modified: $lastModifiedDate") - .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) - .build() - ) + val conditionalRequest = + assertConditionallyCached( + MockResponse.Builder() + .addHeader("Last-Modified: $lastModifiedDate") + .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) + .build(), + ) assertThat(conditionalRequest.headers["If-Modified-Since"]) .isEqualTo(lastModifiedDate) } @@ -843,7 +863,7 @@ class CacheTest { assertNotCached( MockResponse.Builder() .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) - .build() + .build(), ) } @@ -852,7 +872,7 @@ class CacheTest { assertFullyCached( MockResponse.Builder() .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .build() + .build(), ) } @@ -863,20 +883,21 @@ class CacheTest { .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) } @Test fun maxAgeInThePastWithDateAndLastModifiedHeaders() { val lastModifiedDate = formatDate(-2, TimeUnit.HOURS) - val conditionalRequest = assertConditionallyCached( - MockResponse.Builder() - .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) - .addHeader("Last-Modified: $lastModifiedDate") - .addHeader("Cache-Control: max-age=60") - .build() - ) + val conditionalRequest = + assertConditionallyCached( + MockResponse.Builder() + .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) + .addHeader("Last-Modified: $lastModifiedDate") + .addHeader("Cache-Control: max-age=60") + .build(), + ) assertThat(conditionalRequest.headers["If-Modified-Since"]) .isEqualTo(lastModifiedDate) } @@ -889,7 +910,7 @@ class CacheTest { MockResponse.Builder() .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) } @@ -899,7 +920,7 @@ class CacheTest { MockResponse.Builder() .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) } @@ -908,7 +929,7 @@ class CacheTest { assertFullyCached( MockResponse.Builder() .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) } @@ -918,7 +939,7 @@ class CacheTest { MockResponse.Builder() .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) } @@ -929,7 +950,7 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) } @@ -940,7 +961,7 @@ class CacheTest { .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) .addHeader("Cache-Control: s-maxage=60") .addHeader("Cache-Control: max-age=180") - .build() + .build(), ) } @@ -951,7 +972,7 @@ class CacheTest { .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) .addHeader("Cache-Control: s-maxage=180") .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) } @@ -992,25 +1013,29 @@ class CacheTest { testRequestMethod("TRACE", false) } - private fun testRequestMethod(requestMethod: String, expectCached: Boolean) { + private fun testRequestMethod( + requestMethod: String, + expectCached: Boolean, + ) { // 1. Seed the cache (potentially). // 2. Expect a cache hit or miss. server.enqueue( MockResponse.Builder() .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .addHeader("X-Response-ID: 1") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("X-Response-ID: 2") - .build() + .build(), ) val url = server.url("/") - val request = Request.Builder() - .url(url) - .method(requestMethod, requestBodyOrNull(requestMethod)) - .build() + val request = + Request.Builder() + .url(url) + .method(requestMethod, requestBodyOrNull(requestMethod)) + .build() val response1 = client.newCall(request).execute() response1.body.close() assertThat(response1.header("X-Response-ID")).isEqualTo("1") @@ -1050,24 +1075,25 @@ class CacheTest { MockResponse.Builder() .body("A") .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("C") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(url) - .method(requestMethod, requestBodyOrNull(requestMethod)) - .build() + val request = + Request.Builder() + .url(url) + .method(requestMethod, requestBodyOrNull(requestMethod)) + .build() val invalidate = client.newCall(request).execute() assertThat(invalidate.body.string()).isEqualTo("B") assertThat(get(url).body.string()).isEqualTo("C") @@ -1082,25 +1108,26 @@ class CacheTest { MockResponse.Builder() .body("A") .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") .code(500) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("C") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(url) - .method("POST", requestBodyOrNull("POST")) - .build() + val request = + Request.Builder() + .url(url) + .method("POST", requestBodyOrNull("POST")) + .build() val invalidate = client.newCall(request).execute() assertThat(invalidate.body.string()).isEqualTo("B") assertThat(get(url).body.string()).isEqualTo("C") @@ -1115,25 +1142,26 @@ class CacheTest { MockResponse.Builder() .body("A") .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .clearHeaders() .code(HttpURLConnection.HTTP_NO_CONTENT) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("C") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(url) - .put("foo".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(url) + .put("foo".toRequestBody("text/plain".toMediaType())) + .build() val invalidate = client.newCall(request).execute() assertThat(invalidate.body.string()).isEqualTo("") assertThat(get(url).body.string()).isEqualTo("C") @@ -1141,11 +1169,12 @@ class CacheTest { @Test fun etag() { - val conditionalRequest = assertConditionallyCached( - MockResponse.Builder() - .addHeader("ETag: v1") - .build() - ) + val conditionalRequest = + assertConditionallyCached( + MockResponse.Builder() + .addHeader("ETag: v1") + .build(), + ) assertThat(conditionalRequest.headers["If-None-Match"]).isEqualTo("v1") } @@ -1153,13 +1182,14 @@ class CacheTest { @Test fun etagAndExpirationDateInThePast() { val lastModifiedDate = formatDate(-2, TimeUnit.HOURS) - val conditionalRequest = assertConditionallyCached( - MockResponse.Builder() - .addHeader("ETag: v1") - .addHeader("Last-Modified: $lastModifiedDate") - .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) - .build() - ) + val conditionalRequest = + assertConditionallyCached( + MockResponse.Builder() + .addHeader("ETag: v1") + .addHeader("Last-Modified: $lastModifiedDate") + .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) + .build(), + ) assertThat(conditionalRequest.headers["If-None-Match"]).isEqualTo("v1") assertThat(conditionalRequest.headers["If-Modified-Since"]).isNull() } @@ -1171,7 +1201,7 @@ class CacheTest { .addHeader("ETag: v1") .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .build() + .build(), ) } @@ -1180,20 +1210,21 @@ class CacheTest { assertNotCached( MockResponse.Builder() .addHeader("Cache-Control: no-cache") - .build() + .build(), ) } @Test fun cacheControlNoCacheAndExpirationDateInTheFuture() { val lastModifiedDate = formatDate(-2, TimeUnit.HOURS) - val conditionalRequest = assertConditionallyCached( - MockResponse.Builder() - .addHeader("Last-Modified: $lastModifiedDate") - .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .addHeader("Cache-Control: no-cache") - .build() - ) + val conditionalRequest = + assertConditionallyCached( + MockResponse.Builder() + .addHeader("Last-Modified: $lastModifiedDate") + .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) + .addHeader("Cache-Control: no-cache") + .build(), + ) assertThat(conditionalRequest.headers["If-Modified-Since"]) .isEqualTo(lastModifiedDate) } @@ -1203,20 +1234,21 @@ class CacheTest { assertNotCached( MockResponse.Builder() .addHeader("Pragma: no-cache") - .build() + .build(), ) } @Test fun pragmaNoCacheAndExpirationDateInTheFuture() { val lastModifiedDate = formatDate(-2, TimeUnit.HOURS) - val conditionalRequest = assertConditionallyCached( - MockResponse.Builder() - .addHeader("Last-Modified: $lastModifiedDate") - .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .addHeader("Pragma: no-cache") - .build() - ) + val conditionalRequest = + assertConditionallyCached( + MockResponse.Builder() + .addHeader("Last-Modified: $lastModifiedDate") + .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) + .addHeader("Pragma: no-cache") + .build(), + ) assertThat(conditionalRequest.headers["If-Modified-Since"]) .isEqualTo(lastModifiedDate) } @@ -1226,7 +1258,7 @@ class CacheTest { assertNotCached( MockResponse.Builder() .addHeader("Cache-Control: no-store") - .build() + .build(), ) } @@ -1237,7 +1269,7 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .addHeader("Cache-Control: no-store") - .build() + .build(), ) } @@ -1251,18 +1283,19 @@ class CacheTest { .code(HttpURLConnection.HTTP_PARTIAL) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) .addHeader("Content-Range: bytes 1000-1001/2000") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("BB") - .build() + .build(), ) val url = server.url("/") - val request = Request.Builder() - .url(url) - .header("Range", "bytes=1000-1001") - .build() + val request = + Request.Builder() + .url(url) + .header("Range", "bytes=1000-1001") + .build() val range = client.newCall(request).execute() assertThat(range.body.string()).isEqualTo("AA") assertThat(get(url).body.string()).isEqualTo("BB") @@ -1282,18 +1315,18 @@ class CacheTest { .body("A") .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") @@ -1307,23 +1340,25 @@ class CacheTest { MockResponse.Builder() .addHeader("Cache-Control: max-age=60") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Cache-Control: max-age=60") .body("B") - .build() + .build(), ) - val request1 = Request.Builder() - .url(server.url("/")) - .cacheControl(CacheControl.Builder().noStore().build()) - .build() + val request1 = + Request.Builder() + .url(server.url("/")) + .cacheControl(CacheControl.Builder().noStore().build()) + .build() val response1 = client.newCall(request1).execute() assertThat(response1.body.string()).isEqualTo("A") - val request2 = Request.Builder() - .url(server.url("/")) - .build() + val request2 = + Request.Builder() + .url(server.url("/")) + .build() val response2 = client.newCall(request2).execute() assertThat(response2.body.string()).isEqualTo("B") } @@ -1334,7 +1369,7 @@ class CacheTest { MockResponse.Builder() .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) - .build() + .build(), ) } @@ -1344,7 +1379,7 @@ class CacheTest { MockResponse.Builder() .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .build() + .build(), ) } @@ -1353,17 +1388,17 @@ class CacheTest { response.newBuilder() .body(gzip("ABCABCABC")) .addHeader("Content-Encoding: gzip") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) // At least three request/response pairs are required because after the first request is cached @@ -1382,19 +1417,19 @@ class CacheTest { .addHeader("Content-Type: text/plain") .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) .addHeader("Content-Type: text/plain") .addHeader("Content-Encoding: gzip") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("DEFDEFDEF") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("ABCABCABC") assertThat(get(server.url("/")).body.string()).isEqualTo("ABCABCABC") @@ -1410,19 +1445,19 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Content-Encoding: gzip") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) .addHeader("Content-Type: text/plain") .addHeader("Content-Encoding: identity") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("DEFDEFDEF") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("ABCABCABC") assertThat(get(server.url("/")).body.string()).isEqualTo("ABCABCABC") @@ -1437,18 +1472,18 @@ class CacheTest { .addHeader("Content-Encoding: gzip") .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) .addHeader("Content-Encoding: gzip") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("DEFDEFDEF") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("ABCABCABC") assertThat(get(server.url("/")).body.string()).isEqualTo("ABCABCABC") @@ -1464,12 +1499,12 @@ class CacheTest { .addHeader("Content-Encoding: gzip") .addHeader("Vary: Accept-Encoding") .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("FAIL") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("ABCABCABC") assertThat(get(server.url("/")).body.string()).isEqualTo("ABCABCABC") @@ -1482,13 +1517,13 @@ class CacheTest { MockResponse.Builder() .addHeader("ETag: v1") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .clearHeaders() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") assertThat(get(server.url("/")).body.string()).isEqualTo("A") @@ -1501,7 +1536,7 @@ class CacheTest { MockResponse.Builder() .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS)) - .build() + .build(), ) } @@ -1513,18 +1548,19 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "max-age=30") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "max-age=30") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("B") } @@ -1536,18 +1572,19 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=60") .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "min-fresh=120") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "min-fresh=120") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("B") } @@ -1559,22 +1596,23 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=120") .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "max-stale=180") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "max-stale=180") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("A") assertThat(response.header("Warning")).isEqualTo( - "110 HttpURLConnection \"Response is stale\"" + "110 HttpURLConnection \"Response is stale\"", ) } @@ -1586,24 +1624,25 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=120") .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") // With max-stale, we'll return that stale response. - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "max-stale") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "max-stale") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("A") assertThat(response.header("Warning")).isEqualTo( - "110 HttpURLConnection \"Response is stale\"" + "110 HttpURLConnection \"Response is stale\"", ) } @@ -1614,18 +1653,19 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=120, must-revalidate") .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "max-stale=180") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "max-stale=180") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("B") } @@ -1633,10 +1673,11 @@ class CacheTest { @Test fun requestOnlyIfCachedWithNoResponseCached() { // (no responses enqueued) - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "only-if-cached") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "only-if-cached") + .build() val response = client.newCall(request).execute() assertThat(response.body.source().exhausted()).isTrue() assertThat(response.code).isEqualTo(504) @@ -1652,13 +1693,14 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=30") .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES)) - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "only-if-cached") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "only-if-cached") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("A") assertThat(cache.requestCount()).isEqualTo(2) @@ -1673,13 +1715,14 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=30") .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "only-if-cached") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "only-if-cached") + .build() val response = client.newCall(request).execute() assertThat(response.body.source().exhausted()).isTrue() assertThat(response.code).isEqualTo(504) @@ -1693,13 +1736,14 @@ class CacheTest { server.enqueue( MockResponse.Builder() .body("A") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")) - .header("Cache-Control", "only-if-cached") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Cache-Control", "only-if-cached") + .build() val response = client.newCall(request).execute() assertThat(response.body.source().exhausted()).isTrue() assertThat(response.code).isEqualTo(504) @@ -1716,19 +1760,20 @@ class CacheTest { .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) .addHeader("Cache-Control: max-age=60") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(url) - .header("Cache-Control", "no-cache") - .build() + val request = + Request.Builder() + .url(url) + .header("Cache-Control", "no-cache") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("B") } @@ -1741,29 +1786,31 @@ class CacheTest { .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) .addHeader("Cache-Control: max-age=60") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(url) - .header("Pragma", "no-cache") - .build() + val request = + Request.Builder() + .url(url) + .header("Pragma", "no-cache") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("B") } @Test fun clientSuppliedIfModifiedSinceWithCachedResult() { - val response = MockResponse.Builder() - .addHeader("ETag: v3") - .addHeader("Cache-Control: max-age=0") - .build() + val response = + MockResponse.Builder() + .addHeader("ETag: v3") + .addHeader("Cache-Control: max-age=0") + .build() val ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS) val request = assertClientSuppliedCondition(response, "If-Modified-Since", ifModifiedSinceDate) @@ -1774,36 +1821,39 @@ class CacheTest { @Test fun clientSuppliedIfNoneMatchSinceWithCachedResult() { val lastModifiedDate = formatDate(-3, TimeUnit.MINUTES) - val response = MockResponse.Builder() - .addHeader("Last-Modified: $lastModifiedDate") - .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) - .addHeader("Cache-Control: max-age=0") - .build() + val response = + MockResponse.Builder() + .addHeader("Last-Modified: $lastModifiedDate") + .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) + .addHeader("Cache-Control: max-age=0") + .build() val request = assertClientSuppliedCondition(response, "If-None-Match", "v1") assertThat(request.headers["If-None-Match"]).isEqualTo("v1") assertThat(request.headers["If-Modified-Since"]).isNull() } private fun assertClientSuppliedCondition( - seed: MockResponse, conditionName: String, - conditionValue: String + seed: MockResponse, + conditionName: String, + conditionValue: String, ): RecordedRequest { server.enqueue( seed.newBuilder() .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(url) - .header(conditionName, conditionValue) - .build() + val request = + Request.Builder() + .url(url) + .header(conditionName, conditionValue) + .build() val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(HttpURLConnection.HTTP_NOT_MODIFIED) assertThat(response.body.string()).isEqualTo("") @@ -1831,12 +1881,12 @@ class CacheTest { .addHeader("Last-Modified: $lastModifiedString") .addHeader("Expires: $servedString") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") assertThat(get(server.url("/")).body.string()).isEqualTo("A") @@ -1855,12 +1905,13 @@ class CacheTest { server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .header("If-Modified-Since", formatDate(-24, TimeUnit.HOURS)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("If-Modified-Since", formatDate(-24, TimeUnit.HOURS)) + .build() val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(HttpURLConnection.HTTP_NOT_MODIFIED) assertThat(response.body.string()).isEqualTo("") @@ -1872,18 +1923,19 @@ class CacheTest { MockResponse.Builder() .addHeader("Cache-Control: max-age=60") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") - val request = Request.Builder() - .url(url) - .header("Authorization", "password") - .build() + val request = + Request.Builder() + .url(url) + .header("Authorization", "password") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("A") assertThat(get(url).body.string()).isEqualTo("A") @@ -1896,12 +1948,12 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Content-Location: /bar") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/foo")).body.string()).isEqualTo("A") assertThat(get(server.url("/bar")).body.string()).isEqualTo("B") @@ -1914,17 +1966,17 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/a")).body.string()).isEqualTo("A") assertThat(get(server.url("/a")).body.string()).isEqualTo("A") @@ -1941,17 +1993,17 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("C") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") assertThat(cache.requestCount()).isEqualTo(1) @@ -1971,17 +2023,17 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") assertThat(cache.requestCount()).isEqualTo(1) @@ -2000,7 +2052,7 @@ class CacheTest { MockResponse.Builder() .addHeader("Cache-Control: max-age=60") .body("A") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") assertThat(cache.requestCount()).isEqualTo(1) @@ -2020,24 +2072,26 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Accept-Language") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") - val frRequest = Request.Builder() - .url(url) - .header("Accept-Language", "fr-CA") - .build() + val frRequest = + Request.Builder() + .url(url) + .header("Accept-Language", "fr-CA") + .build() val frResponse = client.newCall(frRequest).execute() assertThat(frResponse.body.string()).isEqualTo("A") - val enRequest = Request.Builder() - .url(url) - .header("Accept-Language", "en-US") - .build() + val enRequest = + Request.Builder() + .url(url) + .header("Accept-Language", "en-US") + .build() val enResponse = client.newCall(enRequest).execute() assertThat(enResponse.body.string()).isEqualTo("B") } @@ -2049,24 +2103,26 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Accept-Language") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") - val request = Request.Builder() - .url(url) - .header("Accept-Language", "fr-CA") - .build() + val request = + Request.Builder() + .url(url) + .header("Accept-Language", "fr-CA") + .build() val response1 = client.newCall(request).execute() assertThat(response1.body.string()).isEqualTo("A") - val request1 = Request.Builder() - .url(url) - .header("Accept-Language", "fr-CA") - .build() + val request1 = + Request.Builder() + .url(url) + .header("Accept-Language", "fr-CA") + .build() val response2 = client.newCall(request1).execute() assertThat(response2.body.string()).isEqualTo("A") } @@ -2078,12 +2134,12 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Foo") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") assertThat(get(server.url("/")).body.string()).isEqualTo("A") @@ -2096,17 +2152,18 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Foo") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")).header("Foo", "bar") - .build() + val request = + Request.Builder() + .url(server.url("/")).header("Foo", "bar") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("B") } @@ -2118,16 +2175,17 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Foo") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")).header("Foo", "bar") - .build() + val request = + Request.Builder() + .url(server.url("/")).header("Foo", "bar") + .build() val fooresponse = client.newCall(request).execute() assertThat(fooresponse.body.string()).isEqualTo("A") assertThat(get(server.url("/")).body.string()).isEqualTo("B") @@ -2140,24 +2198,26 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: ACCEPT-LANGUAGE") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") - val request = Request.Builder() - .url(url) - .header("Accept-Language", "fr-CA") - .build() + val request = + Request.Builder() + .url(url) + .header("Accept-Language", "fr-CA") + .build() val response1 = client.newCall(request).execute() assertThat(response1.body.string()).isEqualTo("A") - val request1 = Request.Builder() - .url(url) - .header("accept-language", "fr-CA") - .build() + val request1 = + Request.Builder() + .url(url) + .header("accept-language", "fr-CA") + .build() val response2 = client.newCall(request1).execute() assertThat(response2.body.string()).isEqualTo("A") } @@ -2170,28 +2230,30 @@ class CacheTest { .addHeader("Vary: Accept-Language, Accept-Charset") .addHeader("Vary: Accept-Encoding") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") - val request = Request.Builder() - .url(url) - .header("Accept-Language", "fr-CA") - .header("Accept-Charset", "UTF-8") - .header("Accept-Encoding", "identity") - .build() + val request = + Request.Builder() + .url(url) + .header("Accept-Language", "fr-CA") + .header("Accept-Charset", "UTF-8") + .header("Accept-Encoding", "identity") + .build() val response1 = client.newCall(request).execute() assertThat(response1.body.string()).isEqualTo("A") - val request1 = Request.Builder() - .url(url) - .header("Accept-Language", "fr-CA") - .header("Accept-Charset", "UTF-8") - .header("Accept-Encoding", "identity") - .build() + val request1 = + Request.Builder() + .url(url) + .header("Accept-Language", "fr-CA") + .header("Accept-Charset", "UTF-8") + .header("Accept-Encoding", "identity") + .build() val response2 = client.newCall(request1).execute() assertThat(response2.body.string()).isEqualTo("A") } @@ -2204,28 +2266,30 @@ class CacheTest { .addHeader("Vary: Accept-Language, Accept-Charset") .addHeader("Vary: Accept-Encoding") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") - val frRequest = Request.Builder() - .url(url) - .header("Accept-Language", "fr-CA") - .header("Accept-Charset", "UTF-8") - .header("Accept-Encoding", "identity") - .build() + val frRequest = + Request.Builder() + .url(url) + .header("Accept-Language", "fr-CA") + .header("Accept-Charset", "UTF-8") + .header("Accept-Encoding", "identity") + .build() val frResponse = client.newCall(frRequest).execute() assertThat(frResponse.body.string()).isEqualTo("A") - val enRequest = Request.Builder() - .url(url) - .header("Accept-Language", "en-CA") - .header("Accept-Charset", "UTF-8") - .header("Accept-Encoding", "identity") - .build() + val enRequest = + Request.Builder() + .url(url) + .header("Accept-Language", "en-CA") + .header("Accept-Charset", "UTF-8") + .header("Accept-Encoding", "identity") + .build() val enResponse = client.newCall(enRequest).execute() assertThat(enResponse.body.string()).isEqualTo("B") } @@ -2237,26 +2301,28 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Accept-Language") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") - val request1 = Request.Builder() - .url(url) - .addHeader("Accept-Language", "fr-CA, fr-FR") - .addHeader("Accept-Language", "en-US") - .build() + val request1 = + Request.Builder() + .url(url) + .addHeader("Accept-Language", "fr-CA, fr-FR") + .addHeader("Accept-Language", "en-US") + .build() val response1 = client.newCall(request1).execute() assertThat(response1.body.string()).isEqualTo("A") - val request2 = Request.Builder() - .url(url) - .addHeader("Accept-Language", "fr-CA, fr-FR") - .addHeader("Accept-Language", "en-US") - .build() + val request2 = + Request.Builder() + .url(url) + .addHeader("Accept-Language", "fr-CA, fr-FR") + .addHeader("Accept-Language", "en-US") + .build() val response2 = client.newCall(request2).execute() assertThat(response2.body.string()).isEqualTo("A") } @@ -2268,26 +2334,28 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Accept-Language") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") - val request1 = Request.Builder() - .url(url) - .addHeader("Accept-Language", "fr-CA, fr-FR") - .addHeader("Accept-Language", "en-US") - .build() + val request1 = + Request.Builder() + .url(url) + .addHeader("Accept-Language", "fr-CA, fr-FR") + .addHeader("Accept-Language", "en-US") + .build() val response1 = client.newCall(request1).execute() assertThat(response1.body.string()).isEqualTo("A") - val request2 = Request.Builder() - .url(url) - .addHeader("Accept-Language", "fr-CA") - .addHeader("Accept-Language", "en-US") - .build() + val request2 = + Request.Builder() + .url(url) + .addHeader("Accept-Language", "fr-CA") + .addHeader("Accept-Language", "en-US") + .build() val response2 = client.newCall(request2).execute() assertThat(response2.body.string()).isEqualTo("B") } @@ -2299,12 +2367,12 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: *") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") assertThat(get(server.url("/")).body.string()).isEqualTo("B") @@ -2318,30 +2386,33 @@ class CacheTest { .addHeader("Cache-Control: max-age=60") .addHeader("Vary: Accept-Language") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(NULL_HOSTNAME_VERIFIER) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(NULL_HOSTNAME_VERIFIER) + .build() val url = server.url("/") - val request1 = Request.Builder() - .url(url) - .header("Accept-Language", "en-US") - .build() + val request1 = + Request.Builder() + .url(url) + .header("Accept-Language", "en-US") + .build() val response1 = client.newCall(request1).execute() assertThat(response1.body.string()).isEqualTo("A") - val request2 = Request.Builder() - .url(url) - .header("Accept-Language", "en-US") - .build() + val request2 = + Request.Builder() + .url(url) + .header("Accept-Language", "en-US") + .build() val response2 = client.newCall(request2).execute() assertThat(response2.body.string()).isEqualTo("A") } @@ -2349,22 +2420,23 @@ class CacheTest { @Test fun cachePlusCookies() { val cookieJar = RecordingCookieJar() - client = client.newBuilder() - .cookieJar(cookieJar) - .build() + client = + client.newBuilder() + .cookieJar(cookieJar) + .build() server.enqueue( MockResponse.Builder() .addHeader("Set-Cookie: a=FIRST") .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Set-Cookie: a=SECOND") .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") @@ -2381,13 +2453,13 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Allow: GET, HEAD, PUT") .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val response1 = get(server.url("/")) assertThat(response1.body.string()).isEqualTo("A") @@ -2405,13 +2477,13 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Transfer-Encoding: none") .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val response1 = get(server.url("/")) assertThat(response1.body.string()).isEqualTo("A") @@ -2429,12 +2501,12 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val response1 = get(server.url("/")) assertThat(response1.body.string()).isEqualTo("A") @@ -2452,12 +2524,12 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val response1 = get(server.url("/")) assertThat(response1.body.string()).isEqualTo("A") @@ -2475,7 +2547,7 @@ class CacheTest { .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) .addHeader("Content-Range: bytes 100-100/200") .addHeader("Cache-Control: max-age=60") - .build() + .build(), ) } @@ -2486,19 +2558,19 @@ class CacheTest { .addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS)) .addHeader("Cache-Control: max-age=0") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Cache-Control: max-age=30") .addHeader("Allow: GET, HEAD") .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) // A cache miss writes the cache. @@ -2534,12 +2606,13 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=30") .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES)) - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") - val request = Request.Builder() - .url(server.url("/")).header("Cache-Control", "only-if-cached") - .build() + val request = + Request.Builder() + .url(server.url("/")).header("Cache-Control", "only-if-cached") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("A") } @@ -2551,14 +2624,14 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=30") .addHeader("Date: " + formatDate(-31, TimeUnit.MINUTES)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") .addHeader("Cache-Control: max-age=30") .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES)) - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") val response = get(server.url("/")) @@ -2572,12 +2645,12 @@ class CacheTest { .body("A") .addHeader("Cache-Control: max-age=0") .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES)) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(304) - .build() + .build(), ) assertThat(get(server.url("/")).body.string()).isEqualTo("A") val response = get(server.url("/")) @@ -2589,7 +2662,7 @@ class CacheTest { server.enqueue( MockResponse.Builder() .body("A") - .build() + .build(), ) val response = get(server.url("/")) assertThat(response.body.string()).isEqualTo("A") @@ -2597,14 +2670,15 @@ class CacheTest { @Test fun emptyResponseHeaderNameFromCacheIsLenient() { - val headers = Headers.Builder() - .add("Cache-Control: max-age=120") + val headers = + Headers.Builder() + .add("Cache-Control: max-age=120") addHeaderLenient(headers, ": A") server.enqueue( MockResponse.Builder() .headers(headers.build()) .body("body") - .build() + .build(), ) val response = get(server.url("/")) assertThat(response.header("")).isEqualTo("A") @@ -2625,30 +2699,31 @@ class CacheTest { MockResponse.Builder() .clearHeaders() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val url = server.url("/") val urlKey = key(url) - val entryMetadata = """ - $url - GET - 0 - HTTP/1.1 200 OK - 7 - :status: 200 OK - :version: HTTP/1.1 - etag: foo - content-length: 3 - OkHttp-Received-Millis: ${System.currentTimeMillis()} - X-Android-Response-Source: NETWORK 200 - OkHttp-Sent-Millis: ${System.currentTimeMillis()} - - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - 1 - MIIBpDCCAQ2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1qd2lsc29uLmxvY2FsMB4XDTEzMDgyOTA1MDE1OVoXDTEzMDgzMDA1MDE1OVowGDEWMBQGA1UEAxMNandpbHNvbi5sb2NhbDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAlFW+rGo/YikCcRghOyKkJanmVmJSce/p2/jH1QvNIFKizZdh8AKNwojt3ywRWaDULA/RlCUcltF3HGNsCyjQI/+Lf40x7JpxXF8oim1E6EtDoYtGWAseelawus3IQ13nmo6nWzfyCA55KhAWf4VipelEy8DjcuFKv6L0xwXnI0ECAwEAATANBgkqhkiG9w0BAQsFAAOBgQAuluNyPo1HksU3+Mr/PyRQIQS4BI7pRXN8mcejXmqyscdP7S6J21FBFeRR8/XNjVOp4HT9uSc2hrRtTEHEZCmpyoxixbnM706ikTmC7SN/GgM+SmcoJ1ipJcNcl8N0X6zym4dmyFfXKHu2PkTo7QFdpOJFvP3lIigcSZXozfmEDg== - -1 - - """.trimIndent() + val entryMetadata = + """ + $url + GET + 0 + HTTP/1.1 200 OK + 7 + :status: 200 OK + :version: HTTP/1.1 + etag: foo + content-length: 3 + OkHttp-Received-Millis: ${System.currentTimeMillis()} + X-Android-Response-Source: NETWORK 200 + OkHttp-Sent-Millis: ${System.currentTimeMillis()} + + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + 1 + MIIBpDCCAQ2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1qd2lsc29uLmxvY2FsMB4XDTEzMDgyOTA1MDE1OVoXDTEzMDgzMDA1MDE1OVowGDEWMBQGA1UEAxMNandpbHNvbi5sb2NhbDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAlFW+rGo/YikCcRghOyKkJanmVmJSce/p2/jH1QvNIFKizZdh8AKNwojt3ywRWaDULA/RlCUcltF3HGNsCyjQI/+Lf40x7JpxXF8oim1E6EtDoYtGWAseelawus3IQ13nmo6nWzfyCA55KhAWf4VipelEy8DjcuFKv6L0xwXnI0ECAwEAATANBgkqhkiG9w0BAQsFAAOBgQAuluNyPo1HksU3+Mr/PyRQIQS4BI7pRXN8mcejXmqyscdP7S6J21FBFeRR8/XNjVOp4HT9uSc2hrRtTEHEZCmpyoxixbnM706ikTmC7SN/GgM+SmcoJ1ipJcNcl8N0X6zym4dmyFfXKHu2PkTo7QFdpOJFvP3lIigcSZXozfmEDg== + -1 + + """.trimIndent() val entryBody = "abc" val journalBody = """libcore.io.DiskLruCache 1 @@ -2662,9 +2737,10 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} writeFile(cache.directoryPath, "$urlKey.1", entryBody) writeFile(cache.directoryPath, "journal", journalBody) cache = Cache(cache.directory.path.toPath(), Int.MAX_VALUE.toLong(), fileSystem) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() val response = get(url) assertThat(response.body.string()).isEqualTo(entryBody) assertThat(response.header("Content-Length")).isEqualTo("3") @@ -2677,23 +2753,24 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} val url = server.url("/") val urlKey = key(url) val prefix = get().getPrefix() - val entryMetadata = """ - $url - GET - 0 - HTTP/1.1 200 OK - 4 - Content-Length: 3 - $prefix-Received-Millis: ${System.currentTimeMillis()} - $prefix-Sent-Millis: ${System.currentTimeMillis()} - Cache-Control: max-age=60 - - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - 1 - MIIBnDCCAQWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTUxMjIyMDExMTQwWhcNMTUxMjIzMDExMTQwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJTn2Dh8xYmegvpOSmsKb2Os6Cxf1L4fYbnHr/turInUD5r1P7ZAuxurY880q3GT5bUDoirS3IfucddrT1AcAmUzEmk/FDjggiP8DlxFkY/XwXBlhRDVIp/mRuASPMGInckc0ZaixOkRFyrxADj+r1eaSmXCIvV5yTY6IaIokLj1AgMBAAEwDQYJKoZIhvcNAQELBQADgYEAFblnedqtfRqI9j2WDyPPoG0NTZf9xwjeUu+ju+Ktty8u9k7Lgrrd/DH2mQEtBD1Ctvp91MJfAClNg3faZzwClUyu5pd0QXRZEUwSwZQNen2QWDHRlVsItclBJ4t+AJLqTbwofWi4m4K8REOl593hD55E4+lY22JZiVQyjsQhe6I= - 0 - - """.trimIndent() + val entryMetadata = + """ + $url + GET + 0 + HTTP/1.1 200 OK + 4 + Content-Length: 3 + $prefix-Received-Millis: ${System.currentTimeMillis()} + $prefix-Sent-Millis: ${System.currentTimeMillis()} + Cache-Control: max-age=60 + + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + 1 + MIIBnDCCAQWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTUxMjIyMDExMTQwWhcNMTUxMjIzMDExMTQwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJTn2Dh8xYmegvpOSmsKb2Os6Cxf1L4fYbnHr/turInUD5r1P7ZAuxurY880q3GT5bUDoirS3IfucddrT1AcAmUzEmk/FDjggiP8DlxFkY/XwXBlhRDVIp/mRuASPMGInckc0ZaixOkRFyrxADj+r1eaSmXCIvV5yTY6IaIokLj1AgMBAAEwDQYJKoZIhvcNAQELBQADgYEAFblnedqtfRqI9j2WDyPPoG0NTZf9xwjeUu+ju+Ktty8u9k7Lgrrd/DH2mQEtBD1Ctvp91MJfAClNg3faZzwClUyu5pd0QXRZEUwSwZQNen2QWDHRlVsItclBJ4t+AJLqTbwofWi4m4K8REOl593hD55E4+lY22JZiVQyjsQhe6I= + 0 + + """.trimIndent() val entryBody = "abc" val journalBody = """libcore.io.DiskLruCache 1 @@ -2709,9 +2786,10 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} writeFile(cache.directoryPath, "journal", journalBody) cache.close() cache = Cache(cache.directory.path.toPath(), Int.MAX_VALUE.toLong(), fileSystem) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() val response = get(url) assertThat(response.body.string()).isEqualTo(entryBody) assertThat(response.header("Content-Length")).isEqualTo("3") @@ -2723,7 +2801,8 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} val url = server.url("/") val urlKey = key(url) val prefix = get().getPrefix() - val entryMetadata = """ + val entryMetadata = + """ |$url |GET |0 @@ -2740,9 +2819,11 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} |0 |TLSv1.2 | - |""".trimMargin() + | + """.trimMargin() val entryBody = "abc" - val journalBody = """ + val journalBody = + """ |libcore.io.DiskLruCache |1 |201105 @@ -2750,16 +2831,18 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} | |DIRTY $urlKey |CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} - |""".trimMargin() + | + """.trimMargin() fileSystem.createDirectory(cache.directoryPath) writeFile(cache.directoryPath, "$urlKey.0", entryMetadata) writeFile(cache.directoryPath, "$urlKey.1", entryBody) writeFile(cache.directoryPath, "journal", journalBody) cache.close() cache = Cache(cache.directory.path.toPath(), Int.MAX_VALUE.toLong(), fileSystem) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() val response = get(url) assertThat(response.body.string()).isEqualTo(entryBody) assertThat(response.header("Content-Length")).isEqualTo("3") @@ -2770,7 +2853,8 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} val url = server.url("/") val urlKey = key(url) val prefix = get().getPrefix() - val entryMetadata = """ + val entryMetadata = + """ |$url |GET |0 @@ -2783,7 +2867,8 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} | """.trimMargin() val entryBody = "abc" - val journalBody = """ + val journalBody = + """ |libcore.io.DiskLruCache |1 |201105 @@ -2799,9 +2884,10 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} writeFile(cache.directoryPath, "journal", journalBody) cache.close() cache = Cache(cache.directory.path.toPath(), Int.MAX_VALUE.toLong(), fileSystem) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() val response = get(url) assertThat(response.body.string()).isEqualTo(entryBody) assertThat(response.header("Content-Length")).isEqualTo("3") @@ -2813,12 +2899,12 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} MockResponse.Builder() .addHeader("Cache-Control: max-age=60") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") @@ -2833,24 +2919,27 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} MockResponse.Builder() .addHeader("ETag: v1") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) // Seed the cache. val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") val ifNoneMatch = AtomicReference() - client = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain -> - ifNoneMatch.compareAndSet(null, chain.request().header("If-None-Match")) - chain.proceed(chain.request()) - }) - .build() + client = + client.newBuilder() + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain -> + ifNoneMatch.compareAndSet(null, chain.request().header("If-None-Match")) + chain.proceed(chain.request()) + }, + ) + .build() // Confirm the value is cached and intercepted. assertThat(get(url).body.string()).isEqualTo("A") @@ -2863,7 +2952,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} MockResponse.Builder() .addHeader("Cache-Control: max-age=60") .body("A") - .build() + .build(), ) // Seed the cache. @@ -2871,9 +2960,10 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} assertThat(get(url).body.string()).isEqualTo("A") // Confirm the interceptor isn't exercised. - client = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain? -> throw AssertionError() }) - .build() + client = + client.newBuilder() + .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain? -> throw AssertionError() }) + .build() assertThat(get(url).body.string()).isEqualTo("A") } @@ -2883,21 +2973,21 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} server.enqueue( MockResponse.Builder() .body("a") - .build() + .build(), ) val urlA = server.url("/a") assertThat(get(urlA).body.string()).isEqualTo("a") server.enqueue( MockResponse.Builder() .body("b") - .build() + .build(), ) val urlB = server.url("/b") assertThat(get(urlB).body.string()).isEqualTo("b") server.enqueue( MockResponse.Builder() .body("c") - .build() + .build(), ) val urlC = server.url("/c") assertThat(get(urlC).body.string()).isEqualTo("c") @@ -2925,7 +3015,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} MockResponse.Builder() .addHeader("Cache-Control: max-age=60") .body("a") - .build() + .build(), ) val url = server.url("/a") assertThat(get(url).body.string()).isEqualTo("a") @@ -2939,7 +3029,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} server.enqueue( MockResponse.Builder() .body("b") - .build() + .build(), ) assertThat(get(url).body.string()).isEqualTo("b") } @@ -2950,7 +3040,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} server.enqueue( MockResponse.Builder() .body("a") - .build() + .build(), ) val url = server.url("/a") assertThat(get(url).body.string()).isEqualTo("a") @@ -2967,7 +3057,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} server.enqueue( MockResponse.Builder() .body("a") - .build() + .build(), ) val url = server.url("/a") assertThat(get(url).body.string()).isEqualTo("a") @@ -2987,7 +3077,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} server.enqueue( MockResponse.Builder() .body("a") - .build() + .build(), ) val url = server.url("/a") assertThat(get(url).body.string()).isEqualTo("a") @@ -3010,7 +3100,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} server.enqueue( MockResponse.Builder() .body("a") - .build() + .build(), ) val url = server.url("/a") assertThat(get(url).body.string()).isEqualTo("a") @@ -3031,23 +3121,23 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} MockResponse.Builder() .addHeader("ETag: v1") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("ETag: v2") .body("B") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") @@ -3069,7 +3159,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} .addHeaderLenient("Alpha", "α") .addHeaderLenient("β", "Beta") .body("abcd") - .build() + .build(), ) server.enqueue( MockResponse.Builder() @@ -3077,7 +3167,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} .addHeaderLenient("Gamma", "Γ") .addHeaderLenient("Δ", "Delta") .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val response1 = get(server.url("/")) assertThat(response1.header("Alpha")).isEqualTo("α") @@ -3098,12 +3188,12 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} .addHeaderLenient("Etag", "α") .addHeader("Cache-Control: max-age=0") .body("abcd") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) val response1 = get(server.url("/")) assertThat(response1.body.string()).isEqualTo("abcd") @@ -3123,7 +3213,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} .addHeader("B: b2") .addHeader("B: b3") .body("abcd") - .build() + .build(), ) server.enqueue( MockResponse.Builder() @@ -3131,15 +3221,15 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} .addHeader("B: b4") .addHeader("B: b5") .addHeader("C: c6") - .build() + .build(), ) val response1 = get(server.url("/")) assertThat(response1.body.string()).isEqualTo("abcd") assertThat(response1.headers).isEqualTo( headersOf( "Etag", "a", "Cache-Control", "max-age=0", - "A", "a1", "B", "b2", "B", "b3", "Content-Length", "4" - ) + "A", "a1", "B", "b2", "B", "b3", "Content-Length", "4", + ), ) // The original 'A' header is retained because the network response doesn't have one. @@ -3150,19 +3240,24 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} assertThat(response2.headers).isEqualTo( headersOf( "Etag", "a", "Cache-Control", "max-age=0", - "A", "a1", "Content-Length", "4", "B", "b4", "B", "b5", "C", "c6" - ) + "A", "a1", "Content-Length", "4", "B", "b4", "B", "b5", "C", "c6", + ), ) } private operator fun get(url: HttpUrl): Response { - val request = Request.Builder() - .url(url) - .build() + val request = + Request.Builder() + .url(url) + .build() return client.newCall(request).execute() } - private fun writeFile(directory: Path, file: String, content: String) { + private fun writeFile( + directory: Path, + file: String, + content: String, + ) { val sink = fileSystem.sink(directory.div(file)).buffer() sink.writeUtf8(content) sink.close() @@ -3172,7 +3267,10 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} * @param delta the offset from the current date to use. Negative values yield dates in the past; * positive values yield dates in the future. */ - private fun formatDate(delta: Long, timeUnit: TimeUnit): String { + private fun formatDate( + delta: Long, + timeUnit: TimeUnit, + ): String { return formatDate(Date(System.currentTimeMillis() + timeUnit.toMillis(delta))) } @@ -3186,12 +3284,12 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} server.enqueue( response.newBuilder() .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") @@ -3205,12 +3303,12 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} response.newBuilder() .body("A") .status("HTTP/1.1 200 A-OK") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() + .build(), ) // scenario 2: condition fails @@ -3218,13 +3316,13 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} response.newBuilder() .body("B") .status("HTTP/1.1 200 B-OK") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .status("HTTP/1.1 200 C-OK") .body("C") - .build() + .build(), ) val valid = server.url("/valid") val response1 = get(valid) @@ -3254,12 +3352,12 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} MockResponse.Builder() .addHeader("Cache-Control", "immutable, max-age=10") .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("B") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") @@ -3271,18 +3369,18 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} server.enqueue( MockResponse.Builder() .body("A") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .addHeader("Cache-Control", "immutable, max-age=10") .body("B") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("C") - .build() + .build(), ) val url = server.url("/") assertThat(get(url).body.string()).isEqualTo("A") @@ -3297,13 +3395,14 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} // default lifetime: (115 - 15) / 10 = 10 seconds // expires: 10 seconds from served date = 5 seconds ago val lastModifiedDate = formatDate(-115, TimeUnit.SECONDS) - val conditionalRequest = assertConditionallyCached( - MockResponse.Builder() - .addHeader("Cache-Control: immutable") - .addHeader("Last-Modified: $lastModifiedDate") - .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS)) - .build() - ) + val conditionalRequest = + assertConditionallyCached( + MockResponse.Builder() + .addHeader("Cache-Control: immutable") + .addHeader("Last-Modified: $lastModifiedDate") + .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS)) + .build(), + ) assertThat(conditionalRequest.headers["If-Modified-Since"]) .isEqualTo(lastModifiedDate) } @@ -3313,21 +3412,25 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} val events: MutableList = ArrayList() fileSystem.createDirectories(cache.directoryPath) fileSystem.createDirectories(cache.directoryPath) - val loggingFileSystem: FileSystem = object : ForwardingFileSystem(fileSystem) { - override fun onPathParameter( - path: Path, - functionName: String, - parameterName: String - ): Path { - events.add("$functionName:$path") - return path - } - - override fun onPathResult(path: Path, functionName: String): Path { - events.add("$functionName:$path") - return path + val loggingFileSystem: FileSystem = + object : ForwardingFileSystem(fileSystem) { + override fun onPathParameter( + path: Path, + functionName: String, + parameterName: String, + ): Path { + events.add("$functionName:$path") + return path + } + + override fun onPathResult( + path: Path, + functionName: String, + ): Path { + events.add("$functionName:$path") + return path + } } - } val path: Path = "/cache".toPath() val c = Cache(path, 100000L, loggingFileSystem) assertThat(c.directoryPath).isEqualTo(path) @@ -3343,7 +3446,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} "metadataOrNull:/cache/journal", "atomicMove:/cache/journal.tmp", "atomicMove:/cache/journal", - "appendingSink:/cache/journal" + "appendingSink:/cache/journal", ) events.clear() c.size() @@ -3363,7 +3466,8 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} * how clients respond to the premature conclusion of the HTTP body. */ private fun truncateViolently( - builder: MockResponse.Builder, numBytesToKeep: Int + builder: MockResponse.Builder, + numBytesToKeep: Int, ): MockResponse.Builder { val response = builder.build() builder.socketPolicy(DisconnectAtEnd) @@ -3379,26 +3483,46 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} internal enum class TransferKind { CHUNKED { - override fun setBody(response: MockResponse.Builder, content: Buffer, chunkSize: Int) { + override fun setBody( + response: MockResponse.Builder, + content: Buffer, + chunkSize: Int, + ) { response.chunkedBody(content, chunkSize) } }, FIXED_LENGTH { - override fun setBody(response: MockResponse.Builder, content: Buffer, chunkSize: Int) { + override fun setBody( + response: MockResponse.Builder, + content: Buffer, + chunkSize: Int, + ) { response.body(content) } }, END_OF_STREAM { - override fun setBody(response: MockResponse.Builder, content: Buffer, chunkSize: Int) { + override fun setBody( + response: MockResponse.Builder, + content: Buffer, + chunkSize: Int, + ) { response.body(content) response.socketPolicy(DisconnectAtEnd) response.removeHeader("Content-Length") } - }; + }, ; - abstract fun setBody(response: MockResponse.Builder, content: Buffer, chunkSize: Int) + abstract fun setBody( + response: MockResponse.Builder, + content: Buffer, + chunkSize: Int, + ) - fun setBody(response: MockResponse.Builder, content: String, chunkSize: Int) { + fun setBody( + response: MockResponse.Builder, + content: String, + chunkSize: Int, + ) { setBody(response, Buffer().writeUtf8(content), chunkSize) } } diff --git a/okhttp/src/test/java/okhttp3/CallHandshakeTest.kt b/okhttp/src/test/java/okhttp3/CallHandshakeTest.kt index fd8a7f9a4312..1825a1bae04a 100644 --- a/okhttp/src/test/java/okhttp3/CallHandshakeTest.kt +++ b/okhttp/src/test/java/okhttp3/CallHandshakeTest.kt @@ -71,11 +71,13 @@ class CallHandshakeTest { server.enqueue(MockResponse()) - client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) defaultEnabledCipherSuites = @@ -104,7 +106,8 @@ class CallHandshakeTest { // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 assertThat(handshakeEnabledCipherSuites).containsExactly( - *expectedConnectionCipherSuites(client).toTypedArray()) + *expectedConnectionCipherSuites(client).toTypedArray(), + ) } @Test @@ -133,7 +136,7 @@ class CallHandshakeTest { // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // TLS_RSA_WITH_AES_128_CBC_SHA assertThat(handshakeEnabledCipherSuites).containsExactly( - *expectedConnectionCipherSuites(client).toTypedArray() + *expectedConnectionCipherSuites(client).toTypedArray(), ) } @@ -163,7 +166,7 @@ class CallHandshakeTest { // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // TLS_RSA_WITH_AES_128_CBC_SHA assertThat(handshakeEnabledCipherSuites).containsExactly( - *expectedConnectionCipherSuites(client).toTypedArray() + *expectedConnectionCipherSuites(client).toTypedArray(), ) } @@ -174,8 +177,12 @@ class CallHandshakeTest { platform.assumeNotBouncyCastle() val reversed = ConnectionSpec.COMPATIBLE_TLS.cipherSuites!!.reversed() - val client = makeClient(ConnectionSpec.COMPATIBLE_TLS, TlsVersion.TLS_1_2, - reversed) + val client = + makeClient( + ConnectionSpec.COMPATIBLE_TLS, + TlsVersion.TLS_1_2, + reversed, + ) makeRequest(client) @@ -183,7 +190,7 @@ class CallHandshakeTest { // Will choose a poor cipher suite but not plaintext. // assertThat(handshake.cipherSuite).isEqualTo("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256") assertThat(handshakeEnabledCipherSuites).containsExactly( - *expectedConnectionCipherSuites.toTypedArray() + *expectedConnectionCipherSuites.toTypedArray(), ) } @@ -203,7 +210,7 @@ class CallHandshakeTest { handshakeEnabledCipherSuites.sortedBy { ConnectionSpec.MODERN_TLS.cipherSuitesAsString!!.indexOf(it) } assertThat(handshakeEnabledCipherSuites).containsExactly( - *socketOrderedByDefaults.toTypedArray() + *socketOrderedByDefaults.toTypedArray(), ) } @@ -218,7 +225,7 @@ class CallHandshakeTest { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ) } @@ -266,21 +273,25 @@ class CallHandshakeTest { private fun makeClient( connectionSpec: ConnectionSpec? = null, tlsVersion: TlsVersion? = null, - cipherSuites: List? = null + cipherSuites: List? = null, ): OkHttpClient { return this.client.newBuilder() .apply { if (connectionSpec != null) { - connectionSpecs(listOf(ConnectionSpec.Builder(connectionSpec) - .apply { - if (tlsVersion != null) { - tlsVersions(tlsVersion) - } - if (cipherSuites != null) { - cipherSuites(*cipherSuites.toTypedArray()) - } - } - .build())) + connectionSpecs( + listOf( + ConnectionSpec.Builder(connectionSpec) + .apply { + if (tlsVersion != null) { + tlsVersions(tlsVersion) + } + if (cipherSuites != null) { + cipherSuites(*cipherSuites.toTypedArray()) + } + } + .build(), + ), + ) } } .addNetworkInterceptor { diff --git a/okhttp/src/test/java/okhttp3/CallKotlinTest.kt b/okhttp/src/test/java/okhttp3/CallKotlinTest.kt index 974b8d7323bf..9a3d01782233 100644 --- a/okhttp/src/test/java/okhttp3/CallKotlinTest.kt +++ b/okhttp/src/test/java/okhttp3/CallKotlinTest.kt @@ -23,6 +23,7 @@ import java.io.IOException import java.net.Proxy import java.security.cert.X509Certificate import java.time.Duration +import kotlin.test.assertFailsWith import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import mockwebserver3.SocketPolicy.DisconnectAtStart @@ -43,17 +44,19 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.Timeout import org.junit.jupiter.api.extension.RegisterExtension -import assertk.fail -import kotlin.test.assertFailsWith import org.junitpioneer.jupiter.RetryingTest @Timeout(30) class CallKotlinTest { - @JvmField @RegisterExtension val platform = PlatformRule() - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule().apply { - recordFrames = true - recordSslDebug = true - } + @JvmField @RegisterExtension + val platform = PlatformRule() + + @JvmField @RegisterExtension + val clientTestRule = + OkHttpClientTestRule().apply { + recordFrames = true + recordSslDebug = true + } private var client = clientTestRule.newClient() private val handshakeCertificates = platform.localhostHandshakeCertificates() @@ -94,15 +97,19 @@ class CallKotlinTest { response.use { assertEquals(200, response.code) - assertEquals("CN=localhost", - (response.handshake!!.peerCertificates.single() as X509Certificate).subjectDN.name) + assertEquals( + "CN=localhost", + (response.handshake!!.peerCertificates.single() as X509Certificate).subjectDN.name, + ) } } private fun enableTls() { - client = client.newBuilder() + client = + client.newBuilder() .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager) + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } @@ -139,7 +146,8 @@ class CallKotlinTest { val endpointUrl = server.url("/endpoint") - var request = Request.Builder() + var request = + Request.Builder() .url(endpointUrl) .header("Content-Type", "application/xml") .put(ValidRequestBody()) @@ -148,7 +156,8 @@ class CallKotlinTest { assertEquals(201, it.code) } - request = Request.Builder() + request = + Request.Builder() .url(endpointUrl) .head() .build() @@ -156,7 +165,8 @@ class CallKotlinTest { assertEquals(204, it.code) } - request = Request.Builder() + request = + Request.Builder() .url(endpointUrl) .header("Content-Type", "application/xml") .put(ErringRequestBody()) @@ -165,7 +175,8 @@ class CallKotlinTest { client.newCall(request).execute() } - request = Request.Builder() + request = + Request.Builder() .url(endpointUrl) .head() .build() @@ -179,18 +190,21 @@ class CallKotlinTest { fun staleConnectionNotReusedForNonIdempotentRequest() { // Capture the connection so that we can later make it stale. var connection: RealConnection? = null - client = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain -> - connection = chain.connection() as RealConnection - chain.proceed(chain.request()) - }) + client = + client.newBuilder() + .addNetworkInterceptor( + Interceptor { chain -> + connection = chain.connection() as RealConnection + chain.proceed(chain.request()) + }, + ) .build() server.enqueue( MockResponse( body = "a", - socketPolicy = ShutdownOutputAtEnd - ) + socketPolicy = ShutdownOutputAtEnd, + ), ) server.enqueue(MockResponse(body = "b")) @@ -204,10 +218,11 @@ class CallKotlinTest { connection!!.idleAtNs -= IDLE_CONNECTION_HEALTHY_NS Thread.sleep(250) - val requestB = Request( - url = server.url("/"), - body = "b".toRequestBody("text/plain".toMediaType()), - ) + val requestB = + Request( + url = server.url("/"), + body = "b".toRequestBody("text/plain".toMediaType()), + ) val responseB = client.newCall(requestB).execute() assertThat(responseB.body.string()).isEqualTo("b") assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) @@ -220,7 +235,8 @@ class CallKotlinTest { proxySelector.proxies.add(Proxy.NO_PROXY) server.shutdown() - client = client.newBuilder() + client = + client.newBuilder() .proxySelector(proxySelector) .readTimeout(Duration.ofMillis(100)) .connectTimeout(Duration.ofMillis(100)) @@ -243,7 +259,8 @@ class CallKotlinTest { server.enqueue(MockResponse(socketPolicy = DisconnectAtStart)) server.enqueue(MockResponse(socketPolicy = DisconnectAtStart)) - client = client.newBuilder() + client = + client.newBuilder() .dns(DoubleInetAddressDns()) // Two routes so we get two failures. .build() @@ -265,7 +282,7 @@ class CallKotlinTest { MockResponse( code = 302, headers = headersOf("Location", "/b"), - ) + ), ) server.enqueue(MockResponse()) diff --git a/okhttp/src/test/java/okhttp3/CallTest.kt b/okhttp/src/test/java/okhttp3/CallTest.kt index 013cf25524d8..b9c71c10fe39 100644 --- a/okhttp/src/test/java/okhttp3/CallTest.kt +++ b/okhttp/src/test/java/okhttp3/CallTest.kt @@ -139,20 +139,22 @@ open class CallTest { private var listener = RecordingEventListener() private val handshakeCertificates = platform.localhostHandshakeCertificates() - private var client = clientTestRule.newClientBuilder() - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + private var client = + clientTestRule.newClientBuilder() + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() private val callback = RecordingCallback() - private val cache = Cache( - directory = "/cache".toPath(), - maxSize = Int.MAX_VALUE.toLong(), - fileSystem = LoggingFilesystem(fileSystem) - ) + private val cache = + Cache( + directory = "/cache".toPath(), + maxSize = Int.MAX_VALUE.toLong(), + fileSystem = LoggingFilesystem(fileSystem), + ) @BeforeEach fun setUp( server: MockWebServer, - @MockWebServerInstance("server2") server2: MockWebServer + @MockWebServerInstance("server2") server2: MockWebServer, ) { this.server = server this.server2 = server2 @@ -174,7 +176,8 @@ open class CallTest { .clearHeaders() .addHeader("content-type: text/plain") .addHeader("content-length", "3") - .build()) + .build(), + ) val sentAt = System.currentTimeMillis() val recordedResponse = executeSynchronously("/", "User-Agent", "SyncApiTest") val receivedAt = System.currentTimeMillis() @@ -184,7 +187,7 @@ open class CallTest { Headers.Builder() .add("content-type", "text/plain") .add("content-length", "3") - .build() + .build(), ) .assertBody("abc") .assertSentRequestAtMillis(sentAt, receivedAt) @@ -246,11 +249,14 @@ open class CallTest { fun repeatedHeaderNames() { server.enqueue( MockResponse( - headers = headersOf( - "B", "123", - "B", "234", - ) - ) + headers = + headersOf( + "B", + "123", + "B", + "234", + ), + ), ) executeSynchronously("/", "A", "345", "A", "456") .assertCode(200) @@ -277,14 +283,15 @@ open class CallTest { fun head() { server.enqueue( MockResponse( - headers = headersOf("Content-Type", "text/plain") - ) + headers = headersOf("Content-Type", "text/plain"), + ), ) - val request = Request.Builder() - .url(server.url("/")) - .head() - .header("User-Agent", "SyncApiTest") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .head() + .header("User-Agent", "SyncApiTest") + .build() executeSynchronously(request) .assertCode(200) .assertHeader("Content-Type", "text/plain") @@ -301,14 +308,16 @@ open class CallTest { MockResponse.Builder() .clearHeaders() .addHeader("Content-Length", "100") - .build()) + .build(), + ) server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) - val headRequest = Request.Builder() - .url(server.url("/")) - .head() - .build() + val headRequest = + Request.Builder() + .url(server.url("/")) + .head() + .build() val response = client.newCall(headRequest).execute() assertThat(response.code).isEqualTo(200) assertArrayEquals(ByteArray(0), response.body.bytes()) @@ -326,12 +335,14 @@ open class CallTest { MockResponse.Builder() .clearHeaders() .addHeader("Content-Encoding", "chunked") - .build()) + .build(), + ) server.enqueue(MockResponse(body = "abc")) - val headRequest = Request.Builder() - .url(server.url("/")) - .head() - .build() + val headRequest = + Request.Builder() + .url(server.url("/")) + .head() + .build() executeSynchronously(headRequest) .assertCode(200) .assertHeader("Content-Encoding", "chunked") @@ -359,10 +370,11 @@ open class CallTest { @Test fun post() { server.enqueue(MockResponse(body = "abc")) - val request = Request( - url = server.url("/"), - body = "def".toRequestBody("text/plain".toMediaType()), - ) + val request = + Request( + url = server.url("/"), + body = "def".toRequestBody("text/plain".toMediaType()), + ) executeSynchronously(request) .assertCode(200) .assertBody("abc") @@ -388,10 +400,11 @@ open class CallTest { @Test fun postZeroLength() { server.enqueue(MockResponse(body = "abc")) - val request = Request.Builder() - .url(server.url("/")) - .method("POST", ByteArray(0).toRequestBody(null)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .method("POST", ByteArray(0).toRequestBody(null)) + .build() executeSynchronously(request) .assertCode(200) .assertBody("abc") @@ -452,14 +465,16 @@ open class CallTest { private fun postBodyRetransmittedAfterAuthorizationFail(body: String) { server.enqueue(MockResponse(code = 401)) server.enqueue(MockResponse()) - val request = Request.Builder() - .url(server.url("/")) - .method("POST", body.toRequestBody(null)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .method("POST", body.toRequestBody(null)) + .build() val credential = basic("jesse", "secret") - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(credential, null)) - .build() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(credential, null)) + .build() val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -480,9 +495,10 @@ open class CallTest { } server.enqueue(MockResponse(body = "Success!")) val credential = basic("jesse", "secret") - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(credential, null)) - .build() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(credential, null)) + .build() executeSynchronously("/") .assertCode(200) .assertBody("Success!") @@ -494,9 +510,10 @@ open class CallTest { server.enqueue(MockResponse(code = 401)) } val credential = basic("jesse", "secret") - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(credential, null)) - .build() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(credential, null)) + .build() assertFailsWith { client.newCall(Request.Builder().url(server.url("/0")).build()).execute() }.also { expected -> @@ -514,13 +531,14 @@ open class CallTest { MockResponse( code = 401, headers = headersOf("Connection", "close"), - socketPolicy = DisconnectAtEnd - ) + socketPolicy = DisconnectAtEnd, + ), ) val authenticator = RecordingOkAuthenticator(null, null) - client = client.newBuilder() - .authenticator(authenticator) - .build() + client = + client.newBuilder() + .authenticator(authenticator) + .build() executeSynchronously("/") .assertCode(401) assertThat(authenticator.onlyRoute()).isNotNull() @@ -529,10 +547,11 @@ open class CallTest { @Test fun delete() { server.enqueue(MockResponse(body = "abc")) - val request = Request.Builder() - .url(server.url("/")) - .delete() - .build() + val request = + Request.Builder() + .url(server.url("/")) + .delete() + .build() executeSynchronously(request) .assertCode(200) .assertBody("abc") @@ -558,10 +577,11 @@ open class CallTest { @Test fun deleteWithRequestBody() { server.enqueue(MockResponse(body = "abc")) - val request = Request.Builder() - .url(server.url("/")) - .method("DELETE", "def".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .method("DELETE", "def".toRequestBody("text/plain".toMediaType())) + .build() executeSynchronously(request) .assertCode(200) .assertBody("abc") @@ -573,10 +593,11 @@ open class CallTest { @Test fun put() { server.enqueue(MockResponse(body = "abc")) - val request = Request.Builder() - .url(server.url("/")) - .put("def".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .put("def".toRequestBody("text/plain".toMediaType())) + .build() executeSynchronously(request) .assertCode(200) .assertBody("abc") @@ -585,7 +606,7 @@ open class CallTest { assertThat(recordedRequest.body.readUtf8()).isEqualTo("def") assertThat(recordedRequest.headers["Content-Length"]).isEqualTo("3") assertThat(recordedRequest.headers["Content-Type"]).isEqualTo( - "text/plain; charset=utf-8" + "text/plain; charset=utf-8", ) } @@ -604,10 +625,11 @@ open class CallTest { @Test fun patch() { server.enqueue(MockResponse(body = "abc")) - val request = Request.Builder() - .url(server.url("/")) - .patch("def".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .patch("def".toRequestBody("text/plain".toMediaType())) + .build() executeSynchronously(request) .assertCode(200) .assertBody("abc") @@ -633,10 +655,11 @@ open class CallTest { @Test fun customMethodWithBody() { server.enqueue(MockResponse(body = "abc")) - val request = Request.Builder() - .url(server.url("/")) - .method("CUSTOM", "def".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .method("CUSTOM", "def".toRequestBody("text/plain".toMediaType())) + .build() executeSynchronously(request) .assertCode(200) .assertBody("abc") @@ -651,10 +674,11 @@ open class CallTest { @Test fun unspecifiedRequestBodyContentTypeDoesNotGetDefault() { server.enqueue(MockResponse()) - val request = Request.Builder() - .url(server.url("/")) - .method("POST", "abc".toRequestBody(null)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .method("POST", "abc".toRequestBody(null)) + .build() executeSynchronously(request).assertCode(200) val recordedRequest = server.takeRequest() assertThat(recordedRequest.headers["Content-Type"]).isNull() @@ -668,12 +692,13 @@ open class CallTest { MockResponse( headers = headersOf("Content-Type", "text/plain"), body = "abc", - ) + ), ) - val request = Request.Builder() - .url(server.url("/")) - .header("User-Agent", "SyncApiTest") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("User-Agent", "SyncApiTest") + .build() val call = client.newCall(request) val response = call.execute() response.body.close() @@ -696,12 +721,13 @@ open class CallTest { MockResponse( headers = headersOf("Content-Type", "text/plain"), body = "abc", - ) + ), ) - val request = Request.Builder() - .url(server.url("/")) - .header("User-Agent", "SyncApiTest") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("User-Agent", "SyncApiTest") + .build() val call = client.newCall(request) call.enqueue(callback) assertFailsWith { @@ -755,12 +781,13 @@ open class CallTest { MockResponse( headers = headersOf("Content-Type", "text/plain"), body = "abc", - ) + ), ) - val request = Request.Builder() - .url(server.url("/")) - .header("User-Agent", "AsyncApiTest") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("User-Agent", "AsyncApiTest") + .build() client.newCall(request).enqueue(callback) callback.await(request.url) .assertCode(200) @@ -773,15 +800,23 @@ open class CallTest { fun exceptionThrownByOnResponseIsRedactedAndLogged() { server.enqueue(MockResponse()) val request = Request(server.url("/secret")) - client.newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - fail("") - } + client.newCall(request).enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + fail("") + } - override fun onResponse(call: Call, response: Response) { - throw IOException("a") - } - }) + override fun onResponse( + call: Call, + response: Response, + ) { + throw IOException("a") + } + }, + ) assertThat(testLogHandler.take()) .isEqualTo("INFO: Callback failure for call to " + server.url("/") + "...") } @@ -810,20 +845,23 @@ open class CallTest { server.enqueue(MockResponse(body = "abc")) server.enqueue(MockResponse(body = "def")) server.enqueue(MockResponse(body = "ghi")) - client = OkHttpClient.Builder() - .connectionPool(client.connectionPool) - .proxy(server.toProxyAddress()) - .build() + client = + OkHttpClient.Builder() + .connectionPool(client.connectionPool) + .proxy(server.toProxyAddress()) + .build() executeSynchronously("/a").assertBody("abc") - client = OkHttpClient.Builder() - .connectionPool(client.connectionPool) - .proxy(server.toProxyAddress()) - .build() + client = + OkHttpClient.Builder() + .connectionPool(client.connectionPool) + .proxy(server.toProxyAddress()) + .build() executeSynchronously("/b").assertBody("def") - client = OkHttpClient.Builder() - .connectionPool(client.connectionPool) - .proxy(server.toProxyAddress()) - .build() + client = + OkHttpClient.Builder() + .connectionPool(client.connectionPool) + .proxy(server.toProxyAddress()) + .build() executeSynchronously("/c").assertBody("ghi") assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) @@ -832,9 +870,10 @@ open class CallTest { @Test fun connectionPoolingWithClientBuiltOffProxy() { - client = OkHttpClient.Builder() - .proxy(server.toProxyAddress()) - .build() + client = + OkHttpClient.Builder() + .proxy(server.toProxyAddress()) + .build() server.enqueue(MockResponse(body = "abc")) server.enqueue(MockResponse(body = "def")) server.enqueue(MockResponse(body = "ghi")) @@ -870,21 +909,29 @@ open class CallTest { server.enqueue(MockResponse(body = "abc")) server.enqueue(MockResponse(body = "def")) val request = Request.Builder().url(server.url("/a")).build() - client.newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - throw AssertionError() - } - - override fun onResponse(call: Call, response: Response) { - val bytes = response.body.byteStream() - assertThat(bytes.read()).isEqualTo('a'.code) - assertThat(bytes.read()).isEqualTo('b'.code) - assertThat(bytes.read()).isEqualTo('c'.code) + client.newCall(request).enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + throw AssertionError() + } - // This request will share a connection with 'A' cause it's all done. - client.newCall(Request.Builder().url(server.url("/b")).build()).enqueue(callback) - } - }) + override fun onResponse( + call: Call, + response: Response, + ) { + val bytes = response.body.byteStream() + assertThat(bytes.read()).isEqualTo('a'.code) + assertThat(bytes.read()).isEqualTo('b'.code) + assertThat(bytes.read()).isEqualTo('c'.code) + + // This request will share a connection with 'A' cause it's all done. + client.newCall(Request.Builder().url(server.url("/b")).build()).enqueue(callback) + } + }, + ) callback.await(server.url("/b")).assertCode(200).assertBody("def") // New connection. assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) @@ -895,21 +942,25 @@ open class CallTest { @Test fun timeoutsUpdatedOnReusedConnections() { server.enqueue(MockResponse(body = "abc")) - server.enqueue(MockResponse.Builder() - .body("def") - .throttleBody(1, 750, TimeUnit.MILLISECONDS) - .build()) + server.enqueue( + MockResponse.Builder() + .body("def") + .throttleBody(1, 750, TimeUnit.MILLISECONDS) + .build(), + ) // First request: time out after 1s. - client = client.newBuilder() - .readTimeout(Duration.ofSeconds(1)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofSeconds(1)) + .build() executeSynchronously("/a").assertBody("abc") // Second request: time out after 250ms. - client = client.newBuilder() - .readTimeout(Duration.ofMillis(250)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofMillis(250)) + .build() val request = Request.Builder().url(server.url("/b")).build() val response = client.newCall(request).execute() val bodySource = response.body.source() @@ -935,9 +986,10 @@ open class CallTest { enableTls() server.enqueue(MockResponse(socketPolicy = NoResponse)) server.enqueue(MockResponse(body = "unreachable!")) - client = client.newBuilder() - .readTimeout(Duration.ofMillis(100)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofMillis(100)) + .build() val request = Request.Builder().url(server.url("/")).build() assertFailsWith { // If this succeeds, too many requests were made. @@ -955,11 +1007,12 @@ open class CallTest { proxySelector.proxies.add(Proxy(Proxy.Type.HTTP, TestUtil.UNREACHABLE_ADDRESS_IPV4)) proxySelector.proxies.add(server.toProxyAddress()) server.enqueue(MockResponse(body = "success!")) - client = client.newBuilder() - .proxySelector(proxySelector) - .readTimeout(Duration.ofMillis(100)) - .connectTimeout(Duration.ofMillis(100)) - .build() + client = + client.newBuilder() + .proxySelector(proxySelector) + .readTimeout(Duration.ofMillis(100)) + .connectTimeout(Duration.ofMillis(100)) + .build() val request = Request.Builder().url("http://android.com/").build() executeSynchronously(request) .assertCode(200) @@ -971,16 +1024,19 @@ open class CallTest { fun interceptorRecoversWhenRoutesExhausted() { server.enqueue(MockResponse(socketPolicy = DisconnectAtStart)) server.enqueue(MockResponse()) - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - try { - chain.proceed(chain.request()) - throw AssertionError() - } catch (expected: IOException) { - chain.proceed(chain.request()) - } - }) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + try { + chain.proceed(chain.request()) + throw AssertionError() + } catch (expected: IOException) { + chain.proceed(chain.request()) + } + }, + ) + .build() val request = Request(server.url("/")) executeSynchronously(request) .assertCode(200) @@ -990,21 +1046,25 @@ open class CallTest { @Test fun interceptorCallsProceedWithoutClosingPriorResponse() { server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) - client = clientTestRule.newClientBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - val response = chain.proceed( - chain.request() + client = + clientTestRule.newClientBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + val response = + chain.proceed( + chain.request(), + ) + assertFailsWith { + chain.proceed(chain.request()) + }.also { expected -> + assertThat(expected.message!!).contains("please call response.close()") + } + response + }, ) - assertFailsWith { - chain.proceed(chain.request()) - }.also { expected -> - assertThat(expected.message!!).contains("please call response.close()") - } - response - }) - .build() + .build() val request = Request(server.url("/")) executeSynchronously(request).assertBody("abc") } @@ -1017,15 +1077,16 @@ open class CallTest { fun readTimeoutFails() { server.enqueue(MockResponse(socketPolicy = StallSocketAtStart)) server2.enqueue( - MockResponse(body = "success!") + MockResponse(body = "success!"), ) val proxySelector = RecordingProxySelector() proxySelector.proxies.add(server.toProxyAddress()) proxySelector.proxies.add(server2.toProxyAddress()) - client = client.newBuilder() - .proxySelector(proxySelector) - .readTimeout(Duration.ofMillis(100)) - .build() + client = + client.newBuilder() + .proxySelector(proxySelector) + .readTimeout(Duration.ofMillis(100)) + .build() val request = Request.Builder().url("http://android.com/").build() executeSynchronously(request) .assertFailure(SocketTimeoutException::class.java) @@ -1037,9 +1098,10 @@ open class CallTest { /** https://github.com/square/okhttp/issues/1801 */ @Test fun asyncCallEngineInitialized() { - val c = client.newBuilder() - .addInterceptor(Interceptor { throw IOException() }) - .build() + val c = + client.newBuilder() + .addInterceptor(Interceptor { throw IOException() }) + .build() val request = Request.Builder().url(server.url("/")).build() c.newCall(request).enqueue(callback) val response = callback.await(request.url) @@ -1052,34 +1114,38 @@ open class CallTest { server.enqueue(MockResponse()) // Call 1: set a deadline on the request body. - val requestBody1: RequestBody = object : RequestBody() { - override fun contentType(): MediaType = "text/plain".toMediaType() + val requestBody1: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType = "text/plain".toMediaType() - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("abc") - sink.timeout().deadline(5, TimeUnit.SECONDS) + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("abc") + sink.timeout().deadline(5, TimeUnit.SECONDS) + } } - } - val request1 = Request.Builder() - .url(server.url("/")) - .method("POST", requestBody1) - .build() + val request1 = + Request.Builder() + .url(server.url("/")) + .method("POST", requestBody1) + .build() val response1 = client.newCall(request1).execute() assertThat(response1.code).isEqualTo(200) // Call 2: check for the absence of a deadline on the request body. - val requestBody2: RequestBody = object : RequestBody() { - override fun contentType(): MediaType = "text/plain".toMediaType() + val requestBody2: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType = "text/plain".toMediaType() - override fun writeTo(sink: BufferedSink) { - assertThat(sink.timeout().hasDeadline()).isFalse() - sink.writeUtf8("def") + override fun writeTo(sink: BufferedSink) { + assertThat(sink.timeout().hasDeadline()).isFalse() + sink.writeUtf8("def") + } } - } - val request2 = Request.Builder() - .url(server.url("/")) - .method("POST", requestBody2) - .build() + val request2 = + Request.Builder() + .url(server.url("/")) + .method("POST", requestBody2) + .build() val response2 = client.newCall(request2).execute() assertThat(response2.code).isEqualTo(200) @@ -1119,7 +1185,7 @@ open class CallTest { MockResponse( headers = headersOf("Content-Type", "text/plain"), body = "abc", - ) + ), ) executeSynchronously("/").assertHandshake() } @@ -1131,7 +1197,7 @@ open class CallTest { MockResponse( headers = headersOf("Content-Type", "text/plain"), body = "abc", - ) + ), ) val request = Request(server.url("/")) client.newCall(request).enqueue(callback) @@ -1142,28 +1208,34 @@ open class CallTest { fun recoverWhenRetryOnConnectionFailureIsTrue() { // Set to 2 because the seeding request will count down before the retried request does. val requestFinished = CountDownLatch(2) - val dispatcher: QueueDispatcher = object : QueueDispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse { - if (peek().socketPolicy === DisconnectAfterRequest) { - requestFinished.await() + val dispatcher: QueueDispatcher = + object : QueueDispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + if (peek().socketPolicy === DisconnectAfterRequest) { + requestFinished.await() + } + return super.dispatch(request) } - return super.dispatch(request) } - } dispatcher.enqueueResponse(MockResponse(body = "seed connection pool")) dispatcher.enqueueResponse(MockResponse(socketPolicy = DisconnectAfterRequest)) dispatcher.enqueueResponse(MockResponse(body = "retry success")) server.dispatcher = dispatcher - listener = object : RecordingEventListener() { - override fun requestHeadersEnd(call: Call, request: Request) { - requestFinished.countDown() - super.responseHeadersStart(call) + listener = + object : RecordingEventListener() { + override fun requestHeadersEnd( + call: Call, + request: Request, + ) { + requestFinished.countDown() + super.responseHeadersStart(call) + } } - } - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() assertThat(client.retryOnConnectionFailure).isTrue() executeSynchronously("/").assertBody("seed connection pool") executeSynchronously("/").assertBody("retry success") @@ -1191,10 +1263,11 @@ open class CallTest { server.enqueue(MockResponse(body = "seed connection pool")) server.enqueue(MockResponse(socketPolicy = DisconnectAfterRequest)) server.enqueue(MockResponse(body = "unreachable!")) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .retryOnConnectionFailure(false) - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .retryOnConnectionFailure(false) + .build() executeSynchronously("/").assertBody("seed connection pool") // If this succeeds, too many requests were made. @@ -1202,7 +1275,7 @@ open class CallTest { .assertFailure(IOException::class.java) .assertFailureMatches( "stream was reset: CANCEL", - "unexpected end of stream on " + server.url("/").redact() + "unexpected end of stream on " + server.url("/").redact(), ) } @@ -1224,12 +1297,10 @@ open class CallTest { response.assertFailure( // JDK 11 response to the FAIL_HANDSHAKE: SSLException::class.java, - // RI response to the FAIL_HANDSHAKE: SSLProtocolException::class.java, - // Android's response to the FAIL_HANDSHAKE: - SSLHandshakeException::class.java + SSLHandshakeException::class.java, ) assertThat(client.connectionSpecs).doesNotContain(ConnectionSpec.COMPATIBLE_TLS) } @@ -1241,20 +1312,21 @@ open class CallTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(socketPolicy = FailHandshake)) server.enqueue(MockResponse(body = "abc")) - client = client.newBuilder() - .hostnameVerifier(RecordingHostnameVerifier()) - .connectionSpecs( - // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. - listOf( - ConnectionSpec.RESTRICTED_TLS, - ConnectionSpec.MODERN_TLS, + client = + client.newBuilder() + .hostnameVerifier(RecordingHostnameVerifier()) + .connectionSpecs( + // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. + listOf( + ConnectionSpec.RESTRICTED_TLS, + ConnectionSpec.MODERN_TLS, + ), ) - ) - .sslSocketFactory( - suppressTlsFallbackClientSocketFactory(), - handshakeCertificates.trustManager - ) - .build() + .sslSocketFactory( + suppressTlsFallbackClientSocketFactory(), + handshakeCertificates.trustManager, + ) + .build() executeSynchronously("/").assertBody("abc") } @@ -1269,16 +1341,18 @@ open class CallTest { } server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(socketPolicy = FailHandshake)) - val clientSocketFactory = RecordingSSLSocketFactory( - handshakeCertificates.sslSocketFactory() - ) - client = client.newBuilder() - .sslSocketFactory( - clientSocketFactory, handshakeCertificates.trustManager - ) // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. - .connectionSpecs(listOf(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS)) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + val clientSocketFactory = + RecordingSSLSocketFactory( + handshakeCertificates.sslSocketFactory(), + ) + client = + client.newBuilder() + .sslSocketFactory( + clientSocketFactory, handshakeCertificates.trustManager, + ) // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. + .connectionSpecs(listOf(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS)) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val request = Request.Builder().url(server.url("/")).build() assertFailsWith { client.newCall(request).execute() @@ -1298,16 +1372,17 @@ open class CallTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(socketPolicy = FailHandshake)) server.enqueue(MockResponse(body = "abc")) - client = client.newBuilder() - .hostnameVerifier( - RecordingHostnameVerifier() - ) // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. - .connectionSpecs(listOf(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS)) - .sslSocketFactory( - suppressTlsFallbackClientSocketFactory(), - handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .hostnameVerifier( + RecordingHostnameVerifier(), + ) // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. + .connectionSpecs(listOf(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS)) + .sslSocketFactory( + suppressTlsFallbackClientSocketFactory(), + handshakeCertificates.trustManager, + ) + .build() val request = Request(server.url("/")) client.newCall(request).enqueue(callback) callback.await(request.url).assertBody("abc") @@ -1317,14 +1392,15 @@ open class CallTest { fun noRecoveryFromTlsHandshakeFailureWhenTlsFallbackIsDisabled() { platform.assumeNotBouncyCastle() - client = client.newBuilder() - .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT)) - .hostnameVerifier(RecordingHostnameVerifier()) - .sslSocketFactory( - suppressTlsFallbackClientSocketFactory(), - handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT)) + .hostnameVerifier(RecordingHostnameVerifier()) + .sslSocketFactory( + suppressTlsFallbackClientSocketFactory(), + handshakeCertificates.trustManager, + ) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(socketPolicy = FailHandshake)) val request = Request.Builder().url(server.url("/")).build() @@ -1354,19 +1430,23 @@ open class CallTest { platform.assumeNotBouncyCastle() server.enqueue(MockResponse()) - val serverCertificate = HeldCertificate.Builder() - .commonName("localhost") // Unusued for hostname verification. - .addSubjectAlternativeName("wronghostname") - .build() - val serverCertificates = HandshakeCertificates.Builder() - .heldCertificate(serverCertificate) - .build() - val clientCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(serverCertificate.certificate) - .build() - client = client.newBuilder() - .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) - .build() + val serverCertificate = + HeldCertificate.Builder() + .commonName("localhost") // Unusued for hostname verification. + .addSubjectAlternativeName("wronghostname") + .build() + val serverCertificates = + HandshakeCertificates.Builder() + .heldCertificate(serverCertificate) + .build() + val clientCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(serverCertificate.certificate) + .build() + client = + client.newBuilder() + .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) + .build() server.useHttps(serverCertificates.sslSocketFactory()) executeSynchronously("/") .assertFailureMatches("(?s)Hostname localhost not verified.*") @@ -1383,29 +1463,32 @@ open class CallTest { // The _anon_ suites became unsupported in "1.8.0_201" and "11.0.2". assumeFalse( - System.getProperty("java.version", "unknown").matches(Regex("1\\.8\\.0_1\\d\\d")) + System.getProperty("java.version", "unknown").matches(Regex("1\\.8\\.0_1\\d\\d")), ) server.enqueue(MockResponse()) val cipherSuite = CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256 - val clientCertificates = HandshakeCertificates.Builder() - .build() - client = client.newBuilder() - .sslSocketFactory( - socketFactoryWithCipherSuite(clientCertificates.sslSocketFactory(), cipherSuite), - clientCertificates.trustManager - ) - .connectionSpecs( - listOf( - ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .cipherSuites(cipherSuite) - .build() + val clientCertificates = + HandshakeCertificates.Builder() + .build() + client = + client.newBuilder() + .sslSocketFactory( + socketFactoryWithCipherSuite(clientCertificates.sslSocketFactory(), cipherSuite), + clientCertificates.trustManager, ) - ) - .build() - val serverCertificates = HandshakeCertificates.Builder() - .build() + .connectionSpecs( + listOf( + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .cipherSuites(cipherSuite) + .build(), + ), + ) + .build() + val serverCertificates = + HandshakeCertificates.Builder() + .build() server.useHttps( - socketFactoryWithCipherSuite(serverCertificates.sslSocketFactory(), cipherSuite) + socketFactoryWithCipherSuite(serverCertificates.sslSocketFactory(), cipherSuite), ) executeSynchronously("/") .assertFailure(SSLHandshakeException::class.java) @@ -1414,25 +1497,27 @@ open class CallTest { @Test fun cleartextCallsFailWhenCleartextIsDisabled() { // Configure the client with only TLS configurations. No cleartext! - client = client.newBuilder() - .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS)) - .build() + client = + client.newBuilder() + .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS)) + .build() server.enqueue(MockResponse()) val request = Request.Builder().url(server.url("/")).build() assertFailsWith { client.newCall(request).execute() }.also { expected -> assertThat(expected.message).isEqualTo( - "CLEARTEXT communication not enabled for client" + "CLEARTEXT communication not enabled for client", ) } } @Test fun httpsCallsFailWhenProtocolIsH2PriorKnowledge() { - client = client.newBuilder() - .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) - .build() + client = + client.newBuilder() + .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse()) val call = client.newCall(Request(server.url("/"))) @@ -1450,11 +1535,12 @@ open class CallTest { MockResponse( code = 301, headers = headersOf("Location", "http://square.com"), - ) + ), ) - client = client.newBuilder() - .followSslRedirects(false) - .build() + client = + client.newBuilder() + .followSslRedirects(false) + .build() val request = Request.Builder().url(server.url("/")).build() val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(301) @@ -1474,19 +1560,21 @@ open class CallTest { val certificatePinnerBuilder = CertificatePinner.Builder() for (certificate in response1.handshake!!.peerCertificates) { certificatePinnerBuilder.add( - server.hostName, pin(certificate) + server.hostName, + pin(certificate), ) } response1.body.close() // Make another request with certificate pinning. It should complete normally. - client = client.newBuilder() - .certificatePinner(certificatePinnerBuilder.build()) - .build() + client = + client.newBuilder() + .certificatePinner(certificatePinnerBuilder.build()) + .build() val request2 = Request.Builder().url(server.url("/")).build() val response2 = client.newCall(request2).execute() assertThat(response1.handshake).isNotSameAs( - response2.handshake + response2.handshake, ) response2.body.close() } @@ -1497,13 +1585,14 @@ open class CallTest { server.enqueue(MockResponse()) // Pin publicobject.com's cert. - client = client.newBuilder() - .certificatePinner( - CertificatePinner.Builder() - .add(server.hostName, "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=") - .build() - ) - .build() + client = + client.newBuilder() + .certificatePinner( + CertificatePinner.Builder() + .add(server.hostName, "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=") + .build(), + ) + .build() // When we pin the wrong certificate, connectivity fails. val request = Request.Builder().url(server.url("/")).build() @@ -1517,10 +1606,11 @@ open class CallTest { @Test fun post_Async() { server.enqueue(MockResponse(body = "abc")) - val request = Request( - url = server.url("/"), - body = "def".toRequestBody("text/plain".toMediaType()) - ) + val request = + Request( + url = server.url("/"), + body = "def".toRequestBody("text/plain".toMediaType()), + ) client.newCall(request).enqueue(callback) callback.await(request.url) .assertCode(200) @@ -1537,9 +1627,10 @@ open class CallTest { server.enqueue(MockResponse(socketPolicy = HalfCloseAfterRequest)) server.enqueue(MockResponse(body = "abc")) - val client = client.newBuilder() - .retryOnConnectionFailure(false) - .build() + val client = + client.newBuilder() + .retryOnConnectionFailure(false) + .build() // Seed the connection pool so we have something that can fail. val request1 = Request.Builder().url(server.url("/")).build() @@ -1548,10 +1639,11 @@ open class CallTest { listener.clearAllEvents() - val request2 = Request( - url = server.url("/"), - body = "body!".toRequestBody("text/plain".toMediaType()), - ) + val request2 = + Request( + url = server.url("/"), + body = "body!".toRequestBody("text/plain".toMediaType()), + ) assertFailsWith { client.newCall(request2).execute() }.also { expected -> @@ -1560,7 +1652,7 @@ open class CallTest { assertThat(listener.recordedEventTypes()).containsExactly( "CallStart", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", - "RequestBodyStart", "RequestBodyEnd", "ResponseFailed", "ConnectionReleased", "CallFailed" + "RequestBodyStart", "RequestBodyEnd", "ResponseFailed", "ConnectionReleased", "CallFailed", ) listener.clearAllEvents() @@ -1571,7 +1663,7 @@ open class CallTest { "CallStart", "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", - "ConnectionReleased", "CallEnd" + "ConnectionReleased", "CallEnd", ) val get = server.takeRequest() @@ -1595,10 +1687,11 @@ open class CallTest { val request1 = Request.Builder().url(server.url("/")).build() val response1 = client.newCall(request1).execute() assertThat(response1.body.string()).isEqualTo("abc") - val request2 = Request( - server.url("/"), - body = "body!".toRequestBody("text/plain".toMediaType()), - ) + val request2 = + Request( + server.url("/"), + body = "body!".toRequestBody("text/plain".toMediaType()), + ) val response2 = client.newCall(request2).execute() assertThat(response2.body.string()).isEqualTo("def") val get = server.takeRequest() @@ -1621,17 +1714,22 @@ open class CallTest { fun cacheHit() { server.enqueue( MockResponse( - headers = headersOf( - "ETag", "v1", - "Cache-Control", "max-age=60", - "Vary", "Accept-Charset", - ), + headers = + headersOf( + "ETag", + "v1", + "Cache-Control", + "max-age=60", + "Vary", + "Accept-Charset", + ), body = "A", - ) + ), ) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() // Store a response in the cache. val url = server.url("/") @@ -1644,9 +1742,14 @@ open class CallTest { // Hit that stored response. It's different, but Vary says it doesn't matter. Thread.sleep(10) // Make sure the timestamps are unique. - val cacheHit = executeSynchronously( - "/", "Accept-Language", "en-US", "Accept-Charset", "UTF-8" - ) + val cacheHit = + executeSynchronously( + "/", + "Accept-Language", + "en-US", + "Accept-Charset", + "UTF-8", + ) // Check the merged response. The request is the application's original request. cacheHit.assertCode(200) @@ -1657,7 +1760,7 @@ open class CallTest { .add("Cache-Control", "max-age=60") .add("Vary", "Accept-Charset") .add("Content-Length", "1") - .build() + .build(), ) .assertRequestUrl(url) .assertRequestHeader("Accept-Language", "en-US") @@ -1674,7 +1777,7 @@ open class CallTest { .add("Cache-Control", "max-age=60") .add("Vary", "Accept-Charset") .add("Content-Length", "1") - .build() + .build(), ) .assertRequestMethod("GET") .assertRequestUrl(url) @@ -1689,23 +1792,29 @@ open class CallTest { fun conditionalCacheHit() { server.enqueue( MockResponse( - headers = headersOf( - "ETag", "v1", - "Vary", "Accept-Charset", - "Donut", "a", - ), + headers = + headersOf( + "ETag", + "v1", + "Vary", + "Accept-Charset", + "Donut", + "a", + ), body = "A", - ) + ), ) server.enqueue( MockResponse.Builder() .clearHeaders() .addHeader("Donut: b") .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build()) - client = client.newBuilder() - .cache(cache) - .build() + .build(), + ) + client = + client.newBuilder() + .cache(cache) + .build() // Store a response in the cache. val request1SentAt = System.currentTimeMillis() @@ -1719,9 +1828,14 @@ open class CallTest { // Hit that stored response. It's different, but Vary says it doesn't matter. Thread.sleep(10) // Make sure the timestamps are unique. val request2SentAt = System.currentTimeMillis() - val cacheHit = executeSynchronously( - "/", "Accept-Language", "en-US", "Accept-Charset", "UTF-8" - ) + val cacheHit = + executeSynchronously( + "/", + "Accept-Language", + "en-US", + "Accept-Charset", + "UTF-8", + ) val request2ReceivedAt = System.currentTimeMillis() assertThat(server.takeRequest().headers["If-None-Match"]).isEqualTo("v1") @@ -1765,16 +1879,18 @@ open class CallTest { MockResponse( headers = headersOf("ETag", "v1"), body = "A", - ) + ), ) server.enqueue( MockResponse.Builder() .clearHeaders() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build()) - client = client.newBuilder() - .cache(cache) - .build() + .build(), + ) + client = + client.newBuilder() + .cache(cache) + .build() val request1 = Request(server.url("/")) client.newCall(request1).enqueue(callback) callback.await(request1.url).assertCode(200).assertBody("A") @@ -1789,23 +1905,28 @@ open class CallTest { fun conditionalCacheMiss() { server.enqueue( MockResponse( - headers = headersOf( - "ETag", "v1", - "Vary", "Accept-Charset", - "Donut", "a", - ), + headers = + headersOf( + "ETag", + "v1", + "Vary", + "Accept-Charset", + "Donut", + "a", + ), body = "A", - ) + ), ) server.enqueue( MockResponse( headers = headersOf("Donut", "b"), body = "B", - ) + ), ) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() val request1SentAt = System.currentTimeMillis() executeSynchronously("/", "Accept-Language", "fr-CA", "Accept-Charset", "UTF-8") .assertCode(200) @@ -1816,9 +1937,14 @@ open class CallTest { // Different request, but Vary says it doesn't matter. Thread.sleep(10) // Make sure the timestamps are unique. val request2SentAt = System.currentTimeMillis() - val cacheMiss = executeSynchronously( - "/", "Accept-Language", "en-US", "Accept-Charset", "UTF-8" - ) + val cacheMiss = + executeSynchronously( + "/", + "Accept-Language", + "en-US", + "Accept-Charset", + "UTF-8", + ) val request2ReceivedAt = System.currentTimeMillis() assertThat(server.takeRequest().headers["If-None-Match"]).isEqualTo("v1") @@ -1854,13 +1980,14 @@ open class CallTest { server.enqueue( MockResponse( body = "A", - headers = headersOf("ETag", "v1") - ) + headers = headersOf("ETag", "v1"), + ), ) server.enqueue(MockResponse(body = "B")) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() val request1 = Request(server.url("/")) client.newCall(request1).enqueue(callback) callback.await(request1.url).assertCode(200).assertBody("A") @@ -1882,25 +2009,27 @@ open class CallTest { @Test fun networkDropsOnConditionalGet() { - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() // Seed the cache. server.enqueue( MockResponse( headers = headersOf("ETag", "v1"), body = "A", - ) + ), ) executeSynchronously("/") .assertCode(200) .assertBody("A") // Attempt conditional cache validation and a DNS miss. - client = client.newBuilder() - .dns(FakeDns()) - .build() + client = + client.newBuilder() + .dns(FakeDns()) + .build() executeSynchronously("/").assertFailure(UnknownHostException::class.java) } @@ -1909,22 +2038,28 @@ open class CallTest { server.enqueue( MockResponse( code = 301, - headers = headersOf( - "Location", "/b", - "Test", "Redirect from /a to /b", - ), + headers = + headersOf( + "Location", + "/b", + "Test", + "Redirect from /a to /b", + ), body = "/a has moved!", - ) + ), ) server.enqueue( MockResponse( code = 302, - headers = headersOf( - "Location", "/c", - "Test", "Redirect from /b to /c", - ), + headers = + headersOf( + "Location", + "/c", + "Test", + "Redirect from /b to /c", + ), body = "/b has moved!", - ) + ), ) server.enqueue(MockResponse(body = "C")) executeSynchronously("/a") @@ -1952,15 +2087,16 @@ open class CallTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "/page2"), body = "This page has moved!", - ) + ), ) server.enqueue(MockResponse(body = "Page 2")) - val response = client.newCall( - Request( - url = server.url("/page1"), - body = "Request Body".toRequestBody("text/plain".toMediaType()), - ) - ).execute() + val response = + client.newCall( + Request( + url = server.url("/page1"), + body = "Request Body".toRequestBody("text/plain".toMediaType()), + ), + ).execute() assertThat(response.body.string()).isEqualTo("Page 2") val page1 = server.takeRequest() assertThat(page1.requestLine).isEqualTo("POST /page1 HTTP/1.1") @@ -1977,7 +2113,7 @@ open class CallTest { headers = headersOf("Connection", "Close"), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue(MockResponse(body = "Body")) val request = Request(server.url("/")) @@ -1990,13 +2126,16 @@ open class CallTest { server.enqueue( MockResponse( code = 408, - headers = headersOf( - "Connection", "Close", - "Retry-After", "1", - ), + headers = + headersOf( + "Connection", + "Close", + "Retry-After", + "1", + ), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) val request = Request(server.url("/")) val response = client.newCall(request).execute() @@ -2011,13 +2150,14 @@ open class CallTest { headers = headersOf("Connection", "Close"), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue(MockResponse(body = "Body")) - val request = Request( - server.url("/"), - body = "Hello".toRequestBody("text/plain".toMediaType()), - ) + val request = + Request( + server.url("/"), + body = "Hello".toRequestBody("text/plain".toMediaType()), + ) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("Body") val request1 = server.takeRequest() @@ -2034,11 +2174,12 @@ open class CallTest { headers = headersOf("Connection", "Close"), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) - client = client.newBuilder() - .retryOnConnectionFailure(false) - .build() + client = + client.newBuilder() + .retryOnConnectionFailure(false) + .build() val request = Request(server.url("/")) val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(408) @@ -2053,7 +2194,7 @@ open class CallTest { headers = headersOf("Connection", "Close"), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue( MockResponse( @@ -2061,7 +2202,7 @@ open class CallTest { headers = headersOf("Connection", "Close"), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) val request = Request(server.url("/")) val response = client.newCall(request).execute() @@ -2075,24 +2216,30 @@ open class CallTest { server.enqueue( MockResponse( code = 503, - headers = headersOf( - "Connection", "Close", - "Retry-After", "0", - ), + headers = + headersOf( + "Connection", + "Close", + "Retry-After", + "0", + ), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue( MockResponse( code = 503, - headers = headersOf( - "Connection", "Close", - "Retry-After", "0", - ), + headers = + headersOf( + "Connection", + "Close", + "Retry-After", + "0", + ), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) val request = Request(server.url("/")) val response = client.newCall(request).execute() @@ -2106,13 +2253,16 @@ open class CallTest { server.enqueue( MockResponse( code = 503, - headers = headersOf( - "Connection", "Close", - "Retry-After", "0", - ), + headers = + headersOf( + "Connection", + "Close", + "Retry-After", + "0", + ), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue(MockResponse(body = "Body")) val request = Request(server.url("/")) @@ -2127,24 +2277,27 @@ open class CallTest { code = 503, headers = headersOf("Retry-After", "0"), body = "please retry", - ) + ), ) server.enqueue( - MockResponse(body = "thank you for retrying") - ) - val request = Request( - url = server.url("/"), - body = object : RequestBody() { - var attempt = 0 - override fun contentType(): MediaType? { - return null - } - - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("attempt " + attempt++) - } - }, + MockResponse(body = "thank you for retrying"), ) + val request = + Request( + url = server.url("/"), + body = + object : RequestBody() { + var attempt = 0 + + override fun contentType(): MediaType? { + return null + } + + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("attempt " + attempt++) + } + }, + ) val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isEqualTo("thank you for retrying") @@ -2160,28 +2313,31 @@ open class CallTest { code = 503, headers = headersOf("Retry-After", "0"), body = "please retry", - ) + ), ) server.enqueue( - MockResponse(body = "thank you for retrying") - ) - val request = Request( - url = server.url("/"), - body = object : RequestBody() { - var attempt = 0 - override fun contentType(): MediaType? { - return null - } - - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("attempt " + attempt++) - } - - override fun isOneShot(): Boolean { - return true - } - }, + MockResponse(body = "thank you for retrying"), ) + val request = + Request( + url = server.url("/"), + body = + object : RequestBody() { + var attempt = 0 + + override fun contentType(): MediaType? { + return null + } + + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("attempt " + attempt++) + } + + override fun isOneShot(): Boolean { + return true + } + }, + ) val response = client.newCall(request).execute() assertThat(response.code).isEqualTo(503) assertThat(response.body.string()).isEqualTo("please retry") @@ -2197,17 +2353,18 @@ open class CallTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "/page2"), body = "This page has moved!", - ) + ), ) server.enqueue(MockResponse(body = "Page 2")) // when - val response = client.newCall( - Request.Builder() - .url(server.url("/page1")) - .method("PROPFIND", "Request Body".toRequestBody("text/plain".toMediaType())) - .build() - ).execute() + val response = + client.newCall( + Request.Builder() + .url(server.url("/page1")) + .method("PROPFIND", "Request Body".toRequestBody("text/plain".toMediaType())) + .build(), + ).execute() // then assertThat(response.body.string()).isEqualTo("Page 2") @@ -2223,16 +2380,20 @@ open class CallTest { fun responseCookies() { server.enqueue( MockResponse( - headers = headersOf( - "Set-Cookie", "a=b; Expires=Thu, 01 Jan 1970 00:00:00 GMT", - "Set-Cookie", "c=d; Expires=Fri, 02 Jan 1970 23:59:59 GMT; path=/bar; secure", - ) - ) + headers = + headersOf( + "Set-Cookie", + "a=b; Expires=Thu, 01 Jan 1970 00:00:00 GMT", + "Set-Cookie", + "c=d; Expires=Fri, 02 Jan 1970 23:59:59 GMT; path=/bar; secure", + ), + ), ) val cookieJar = RecordingCookieJar() - client = client.newBuilder() - .cookieJar(cookieJar) - .build() + client = + client.newBuilder() + .cookieJar(cookieJar) + .build() executeSynchronously("/").assertCode(200) val responseCookies = cookieJar.takeResponseCookies() assertThat(responseCookies.size).isEqualTo(2) @@ -2248,11 +2409,12 @@ open class CallTest { val cookieJar = RecordingCookieJar() cookieJar.enqueueRequestCookies( Cookie.Builder().name("a").value("b").domain(server.hostName).build(), - Cookie.Builder().name("c").value("d").domain(server.hostName).build() + Cookie.Builder().name("c").value("d").domain(server.hostName).build(), ) - client = client.newBuilder() - .cookieJar(cookieJar) - .build() + client = + client.newBuilder() + .cookieJar(cookieJar) + .build() executeSynchronously("/").assertCode(200) val recordedRequest = server.takeRequest() assertThat(recordedRequest.headers["Cookie"]).isEqualTo("a=b; c=d") @@ -2265,7 +2427,7 @@ open class CallTest { MockResponse( code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", server2.url("/").toString()), - ) + ), ) val cookieManager = CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) val cookie = HttpCookie("c", "cookie") @@ -2274,9 +2436,10 @@ open class CallTest { val portList = server.port.toString() cookie.portlist = portList cookieManager.cookieStore.add(server.url("/").toUri(), cookie) - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + client.newBuilder() + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() val response = client.newCall(Request(server.url("/page1"))).execute() assertThat(response.body.string()).isEqualTo("Page 2") val request1 = server.takeRequest() @@ -2293,11 +2456,12 @@ open class CallTest { MockResponse( code = 302, headers = headersOf("Location", server2.url("/b").toString()), - ) + ), ) - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(basic("jesse", "secret"), null)) - .build() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(basic("jesse", "secret"), null)) + .build() val request = Request.Builder().url(server.url("/a")).build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("Page 2") @@ -2311,22 +2475,28 @@ open class CallTest { server.enqueue( MockResponse( code = 301, - headers = headersOf( - "Location", "/b", - "Test", "Redirect from /a to /b" - ), + headers = + headersOf( + "Location", + "/b", + "Test", + "Redirect from /a to /b", + ), body = "/a has moved!", - ) + ), ) server.enqueue( MockResponse( code = 302, - headers = headersOf( - "Location", "/c", - "Test", "Redirect from /b to /c" - ), + headers = + headersOf( + "Location", + "/c", + "Test", + "Redirect from /b to /c", + ), body = "/b has moved!", - ) + ), ) server.enqueue(MockResponse(body = "C")) val request = Request.Builder().url(server.url("/a")).build() @@ -2358,7 +2528,7 @@ open class CallTest { code = 301, headers = headersOf("Location", "/${i + 1}"), body = "Redirecting to /" + (i + 1), - ) + ), ) } server.enqueue(MockResponse(body = "Success!")) @@ -2376,7 +2546,7 @@ open class CallTest { code = 301, headers = headersOf("Location", "/" + (i + 1)), body = "Redirecting to /" + (i + 1), - ) + ), ) } server.enqueue(MockResponse(body = "Success!")) @@ -2396,7 +2566,7 @@ open class CallTest { code = 301, headers = headersOf("Location", "/${i + 1}"), body = "Redirecting to /${i + 1}", - ) + ), ) } assertFailsWith { @@ -2415,7 +2585,7 @@ open class CallTest { code = 301, headers = headersOf("Location", "/${i + 1}"), body = "Redirecting to /${i + 1}", - ) + ), ) } val request = Request.Builder().url(server.url("/0")).build() @@ -2429,7 +2599,7 @@ open class CallTest { MockResponse( code = 204, body = "I'm not even supposed to be here today.", - ) + ), ) executeSynchronously("/") .assertFailure("HTTP 204 had non-zero Content-Length: 39") @@ -2441,7 +2611,7 @@ open class CallTest { MockResponse( code = 205, body = "I'm not even supposed to be here today.", - ) + ), ) executeSynchronously("/") .assertFailure("HTTP 205 had non-zero Content-Length: 39") @@ -2455,12 +2625,16 @@ open class CallTest { MockResponse.Builder() .status(longLine) .body("I'm not even supposed to be here today.") - .build()) + .build(), + ) executeSynchronously("/") .assertFailureMatches(".*unexpected end of stream on " + server.url("/").redact()) } - private fun stringFill(fillChar: Char, length: Int): String { + private fun stringFill( + fillChar: Char, + length: Int, + ): String { val value = CharArray(length) Arrays.fill(value, fillChar) return String(value) @@ -2507,16 +2681,19 @@ open class CallTest { fun cancelImmediatelyAfterEnqueue() { server.enqueue(MockResponse()) val latch = CountDownLatch(1) - client = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain -> - try { - latch.await() - } catch (e: InterruptedException) { - throw AssertionError(e) - } - chain.proceed(chain.request()) - }) - .build() + client = + client.newBuilder() + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain -> + try { + latch.await() + } catch (e: InterruptedException) { + throw AssertionError(e) + } + chain.proceed(chain.request()) + }, + ) + .build() val call = client.newCall(Request(server.url("/a"))) call.enqueue(callback) call.cancel() @@ -2535,16 +2712,17 @@ open class CallTest { @Test fun cancelWhileRequestHeadersAreSent() { server.enqueue(MockResponse(body = "A")) - val listener: EventListener = object : EventListener() { - override fun requestHeadersStart(call: Call) { - try { - // Cancel call from another thread to avoid reentrance. - cancelLater(call, 0).join() - } catch (e: InterruptedException) { - throw AssertionError() + val listener: EventListener = + object : EventListener() { + override fun requestHeadersStart(call: Call) { + try { + // Cancel call from another thread to avoid reentrance. + cancelLater(call, 0).join() + } catch (e: InterruptedException) { + throw AssertionError() + } } } - } client = client.newBuilder().eventListener(listener).build() val call = client.newCall(Request(server.url("/a"))) assertFailsWith { @@ -2560,10 +2738,12 @@ open class CallTest { @Test fun cancelBeforeBodyIsRead() { - server.enqueue(MockResponse.Builder() - .body("def") - .throttleBody(1, 750, TimeUnit.MILLISECONDS) - .build()) + server.enqueue( + MockResponse.Builder() + .body("def") + .throttleBody(1, 750, TimeUnit.MILLISECONDS) + .build(), + ) val call = client.newCall(Request(server.url("/a"))) val executor = Executors.newSingleThreadExecutor() val result = executor.submit { call.execute() } @@ -2579,12 +2759,13 @@ open class CallTest { fun cancelInFlightBeforeResponseReadThrowsIOE() { val request = Request(server.url("/a")) val call = client.newCall(request) - server.dispatcher = object : mockwebserver3.Dispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse { - call.cancel() - return MockResponse(body = "A") + server.dispatcher = + object : mockwebserver3.Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + call.cancel() + return MockResponse(body = "A") + } } - } assertFailsWith { call.execute() } @@ -2612,20 +2793,23 @@ open class CallTest { // Force requests to be executed serially. val dispatcher = Dispatcher(client.dispatcher.executorService) dispatcher.maxRequests = 1 - client = client.newBuilder() - .dispatcher(dispatcher) - .build() + client = + client.newBuilder() + .dispatcher(dispatcher) + .build() val requestA = Request(server.url("/a")) val requestB = Request(server.url("/b")) val callA = client.newCall(requestA) val callB = client.newCall(requestB) - server.dispatcher = object : mockwebserver3.Dispatcher() { - var nextResponse = 'A' - override fun dispatch(request: RecordedRequest): MockResponse { - callB.cancel() - return MockResponse(body = (nextResponse++).toString()) + server.dispatcher = + object : mockwebserver3.Dispatcher() { + var nextResponse = 'A' + + override fun dispatch(request: RecordedRequest): MockResponse { + callB.cancel() + return MockResponse(body = (nextResponse++).toString()) + } } - } callA.enqueue(callback) callB.enqueue(callback) assertThat(server.takeRequest().path).isEqualTo("/a") @@ -2650,17 +2834,19 @@ open class CallTest { fun canceledBeforeResponseReadSignalsOnFailure() { val requestA = Request(server.url("/a")) val call = client.newCall(requestA) - server.dispatcher = object : mockwebserver3.Dispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse { - call.cancel() - return MockResponse(body = "A") + server.dispatcher = + object : mockwebserver3.Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + call.cancel() + return MockResponse(body = "A") + } } - } call.enqueue(callback) assertThat(server.takeRequest().path).isEqualTo("/a") callback.await(requestA.url).assertFailure( - "Canceled", "stream was reset: CANCEL", - "Socket closed" + "Canceled", + "stream was reset: CANCEL", + "Socket closed", ) } @@ -2688,24 +2874,33 @@ open class CallTest { val failureRef = AtomicBoolean() val request = Request(server.url("/a")) val call = client.newCall(request) - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - failureRef.set(true) - latch.countDown() - } - - override fun onResponse(call: Call, response: Response) { - call.cancel() - try { - bodyRef.set(response.body.string()) - } catch (e: IOException) { // It is ok if this broke the stream. - bodyRef.set("A") - throw e // We expect to not loop into onFailure in this case. - } finally { + call.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + failureRef.set(true) latch.countDown() } - } - }) + + override fun onResponse( + call: Call, + response: Response, + ) { + call.cancel() + try { + bodyRef.set(response.body.string()) + } catch (e: IOException) { + // It is ok if this broke the stream. + bodyRef.set("A") + throw e // We expect to not loop into onFailure in this case. + } finally { + latch.countDown() + } + } + }, + ) latch.await() assertThat(bodyRef.get()).isEqualTo("A") assertThat(failureRef.get()).isFalse() @@ -2725,12 +2920,15 @@ open class CallTest { @Test fun cancelWithInterceptor() { - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - chain.proceed(chain.request()) - throw AssertionError() // We expect an exception. - }) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + chain.proceed(chain.request()) + throw AssertionError() // We expect an exception. + }, + ) + .build() val call = client.newCall(Request(server.url("/a"))) call.cancel() assertFailsWith { @@ -2747,7 +2945,8 @@ open class CallTest { MockResponse.Builder() .body(gzippedBody) .addHeader("Content-Encoding: gzip") - .build()) + .build(), + ) // Confirm that the user request doesn't have Accept-Encoding, and the user // response doesn't have a Content-Encoding or Content-Length. @@ -2773,10 +2972,12 @@ open class CallTest { MockResponse.Builder() .body(gzip("abcabcabc")) .addHeader("Content-Encoding: gzip") - .build()) - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator("password", null)) - .build() + .build(), + ) + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator("password", null)) + .build() executeSynchronously("/").assertBody("abcabcabc") } @@ -2791,20 +2992,22 @@ open class CallTest { .body(gzippedBody) .addHeader("Content-Encoding: gzip") .addHeader("Content-Range: bytes 0-" + (gzippedBody.size - 1)) - .build()) + .build(), + ) // Make a range request. - val request = Request.Builder() - .url(server.url("/")) - .header("Range", "bytes=0-") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Range", "bytes=0-") + .build() val call = client.newCall(request) // The response is not decompressed. val response = call.execute() assertThat(response.header("Content-Encoding")).isEqualTo("gzip") assertThat(response.body.source().readByteString()).isEqualTo( - gzippedBody.snapshot() + gzippedBody.snapshot(), ) // The request did not offer gzip support. @@ -2816,24 +3019,33 @@ open class CallTest { fun asyncResponseCanBeConsumedLater() { server.enqueue(MockResponse(body = "abc")) server.enqueue(MockResponse(body = "def")) - val request = Request.Builder() - .url(server.url("/")) - .header("User-Agent", "SyncApiTest") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("User-Agent", "SyncApiTest") + .build() val responseRef: BlockingQueue = SynchronousQueue() - client.newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - throw AssertionError() - } - - override fun onResponse(call: Call, response: Response) { - try { - responseRef.put(response) - } catch (e: InterruptedException) { + client.newCall(request).enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { throw AssertionError() } - } - }) + + override fun onResponse( + call: Call, + response: Response, + ) { + try { + responseRef.put(response) + } catch (e: InterruptedException) { + throw AssertionError() + } + } + }, + ) val response = responseRef.take() assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isEqualTo("abc") @@ -2864,12 +3076,13 @@ open class CallTest { code = 302, headers = headersOf("Location", "/b"), body = "A", - ) + ), ) server.enqueue(MockResponse(body = "B")) - client = client.newBuilder() - .followRedirects(false) - .build() + client = + client.newBuilder() + .followRedirects(false) + .build() executeSynchronously("/a") .assertBody("A") .assertCode(302) @@ -2877,14 +3090,17 @@ open class CallTest { @Test fun expect100ContinueNonEmptyRequestBody() { - server.enqueue(MockResponse.Builder() + server.enqueue( + MockResponse.Builder() .add100Continue() - .build()) - val request = Request.Builder() - .url(server.url("/")) - .header("Expect", "100-continue") - .post("abc".toRequestBody("text/plain".toMediaType())) - .build() + .build(), + ) + val request = + Request.Builder() + .url(server.url("/")) + .header("Expect", "100-continue") + .post("abc".toRequestBody("text/plain".toMediaType())) + .build() executeSynchronously(request) .assertCode(200) .assertSuccessful() @@ -2894,11 +3110,12 @@ open class CallTest { @Test fun expect100ContinueEmptyRequestBody() { server.enqueue(MockResponse()) - val request = Request.Builder() - .url(server.url("/")) - .header("Expect", "100-continue") - .post("".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Expect", "100-continue") + .post("".toRequestBody("text/plain".toMediaType())) + .build() executeSynchronously(request) .assertCode(200) .assertSuccessful() @@ -2914,14 +3131,16 @@ open class CallTest { @Test fun expect100ContinueTimesOutWithoutContinue() { server.enqueue(MockResponse(socketPolicy = NoResponse)) - client = client.newBuilder() - .readTimeout(Duration.ofMillis(500)) - .build() - val request = Request.Builder() - .url(server.url("/")) - .header("Expect", "100-continue") - .post("abc".toRequestBody("text/plain".toMediaType())) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofMillis(500)) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Expect", "100-continue") + .post("abc".toRequestBody("text/plain".toMediaType())) + .build() val call = client.newCall(request) assertFailsWith { call.execute() @@ -2942,11 +3161,13 @@ open class CallTest { server.enqueue( MockResponse.Builder() .add100Continue() - .build()) - val request = Request( - url = server.url("/"), - body = "abc".toRequestBody("text/plain".toMediaType()), + .build(), ) + val request = + Request( + url = server.url("/"), + body = "abc".toRequestBody("text/plain".toMediaType()), + ) executeSynchronously(request) .assertCode(200) .assertSuccessful() @@ -2968,13 +3189,14 @@ open class CallTest { MockResponse( code = HTTP_EARLY_HINTS, headers = headersOf("Link", "; rel=preload; as=style"), - ) - ).build() - ) - val request = Request( - url = server.url("/"), - body = "abc".toRequestBody("text/plain".toMediaType()), + ), + ).build(), ) + val request = + Request( + url = server.url("/"), + body = "abc".toRequestBody("text/plain".toMediaType()), + ) executeSynchronously(request) .assertCode(200) .assertSuccessful() @@ -2996,13 +3218,14 @@ open class CallTest { .addInformationalResponse( MockResponse( code = HTTP_PROCESSING, - ) - ).build() - ) - val request = Request( - url = server.url("/"), - body = "abc".toRequestBody("text/plain".toMediaType()), + ), + ).build(), ) + val request = + Request( + url = server.url("/"), + body = "abc".toRequestBody("text/plain".toMediaType()), + ) executeSynchronously(request) .assertCode(200) .assertSuccessful() @@ -3019,14 +3242,16 @@ open class CallTest { @Tag("Slow") @Test fun serverRespondsWith100ContinueOnly() { - client = client.newBuilder() - .readTimeout(Duration.ofSeconds(1)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofSeconds(1)) + .build() server.enqueue(MockResponse(code = 100)) - val request = Request( - url = server.url("/"), - body = "abc".toRequestBody("text/plain".toMediaType()), - ) + val request = + Request( + url = server.url("/"), + body = "abc".toRequestBody("text/plain".toMediaType()), + ) val call = client.newCall(request) assertFailsWith { call.execute() @@ -3047,14 +3272,15 @@ open class CallTest { server.enqueue( MockResponse.Builder() .add100Continue() - .build()) + .build(), + ) server.enqueue(MockResponse()) executeSynchronously( Request.Builder() .url(server.url("/")) .header("Expect", "100-continue") .post("abc".toRequestBody("text/plain".toMediaType())) - .build() + .build(), ) executeSynchronously(Request(server.url("/"))) assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) @@ -3078,7 +3304,7 @@ open class CallTest { .url(server.url("/")) .header("Expect", "100-continue") .post("abc".toRequestBody("text/plain".toMediaType())) - .build() + .build(), ) executeSynchronously(Request(server.url("/"))) assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) @@ -3096,7 +3322,7 @@ open class CallTest { .url(server.url("/")) .header("Expect", "100-continue") .post("abc".toRequestBody("text/plain".toMediaType())) - .build() + .build(), ) executeSynchronously(Request(server.url("/"))) assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) @@ -3124,9 +3350,10 @@ open class CallTest { // Configure a DNS that returns our local MockWebServer for android.com. val dns = FakeDns() dns["android.com"] = Dns.SYSTEM.lookup(server.url("/").host) - client = client.newBuilder() - .dns(dns) - .build() + client = + client.newBuilder() + .dns(dns) + .build() server.enqueue(MockResponse()) val request = Request(server.url("/").newBuilder().host("android.com").build()) executeSynchronously(request).assertCode(200) @@ -3139,9 +3366,10 @@ open class CallTest { val dns = FakeDns() val ipAddresses = mutableListOf() dns["android.com"] = ipAddresses - client = client.newBuilder() - .dns(dns) - .build() + client = + client.newBuilder() + .dns(dns) + .build() server.enqueue(MockResponse()) val request = Request(server.url("/").newBuilder().host("android.com").build()) executeSynchronously(request).assertFailure("$dns returned no addresses for android.com") @@ -3155,33 +3383,36 @@ open class CallTest { enableProtocol(Protocol.HTTP_2) server.enqueue(MockResponse(body = "Response 1")) server.enqueue(MockResponse(body = "Response 2")) - val requestBody: RequestBody = object : RequestBody() { - override fun contentType(): MediaType? { - return null - } + val requestBody: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType? { + return null + } - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("abc") - sink.flush() - makeFailingCall() - sink.writeUtf8("def") - sink.flush() + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("abc") + sink.flush() + makeFailingCall() + sink.writeUtf8("def") + sink.flush() + } } - } - val call = client.newCall( - Request( - url = server.url("/"), - body = requestBody + val call = + client.newCall( + Request( + url = server.url("/"), + body = requestBody, + ), ) - ) call.execute().use { response -> assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isNotEmpty() } if (!platform.isJdk8()) { - val connectCount = listener.eventSequence.stream() - .filter { event: CallEvent? -> event is ConnectStart } - .count() + val connectCount = + listener.eventSequence.stream() + .filter { event: CallEvent? -> event is ConnectStart } + .count() assertThat(connectCount).isEqualTo(1) } } @@ -3191,27 +3422,30 @@ open class CallTest { fun proxyConnectOmitsApplicationHeaders() { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue( - MockResponse(inTunnel = true)) + MockResponse(inTunnel = true), + ) server.enqueue( - MockResponse(body = "encrypted response from the origin server") + MockResponse(body = "encrypted response from the origin server"), ) val hostnameVerifier = RecordingHostnameVerifier() - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .hostnameVerifier(hostnameVerifier) - .build() - val request = Request.Builder() - .url("https://android.com/foo") - .header("Private", "Secret") - .header("User-Agent", "App 1.0") - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .hostnameVerifier(hostnameVerifier) + .build() + val request = + Request.Builder() + .url("https://android.com/foo") + .header("Private", "Secret") + .header("User-Agent", "App 1.0") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo( - "encrypted response from the origin server" + "encrypted response from the origin server", ) val connect = server.takeRequest() assertThat(connect.headers["Private"]).isNull() @@ -3235,16 +3469,18 @@ open class CallTest { .body("abc") .setHeader("Content-Length", "5") .socketPolicy(DisconnectAtEnd) - .build()) + .build(), + ) val hostnameVerifier = RecordingHostnameVerifier() - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .hostnameVerifier(hostnameVerifier) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .hostnameVerifier(hostnameVerifier) + .build() val request = Request("https://android.com/foo".toHttpUrl()) assertFailsWith { client.newCall(request).execute() @@ -3262,22 +3498,24 @@ open class CallTest { code = 407, headers = headersOf("Proxy-Authenticate", "Basic realm=\"localhost\""), inTunnel = true, - ) + ), ) server.enqueue( - MockResponse(inTunnel = true)) + MockResponse(inTunnel = true), + ) server.enqueue( - MockResponse(body = "response body") + MockResponse(body = "response body"), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val request = Request("https://android.com/foo".toHttpUrl()) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") @@ -3299,15 +3537,16 @@ open class CallTest { MockResponse( code = 407, headers = headersOf("Proxy-Authenticate", "Basic realm=\"localhost\""), - ) + ), ) server.enqueue( - MockResponse(body = "response body") + MockResponse(body = "response body"), ) - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) - .build() + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) + .build() val request = Request("http://android.com/foo".toHttpUrl()) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") @@ -3330,25 +3569,30 @@ open class CallTest { server.enqueue( MockResponse( code = 407, - headers = headersOf( - "Proxy-Authenticate", "Basic realm=\"localhost\"", - "Connection", "close", - ), + headers = + headersOf( + "Proxy-Authenticate", + "Basic realm=\"localhost\"", + "Connection", + "close", + ), inTunnel = true, - ) + ), ) server.enqueue(MockResponse(inTunnel = true)) - server.enqueue(MockResponse(body = "response body") + server.enqueue( + MockResponse(body = "response body"), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val request = Request("https://android.com/foo".toHttpUrl()) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") @@ -3371,23 +3615,27 @@ open class CallTest { server.enqueue( MockResponse( code = 407, - headers = headersOf( - "Proxy-Authenticate", "Basic realm=\"localhost\"", - "Connection", "close", - ), + headers = + headersOf( + "Proxy-Authenticate", + "Basic realm=\"localhost\"", + "Connection", + "close", + ), inTunnel = true, - ) + ), ) } - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val request = Request("https://android.com/foo".toHttpUrl()) assertFailsWith { client.newCall(request).execute() @@ -3404,18 +3652,20 @@ open class CallTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "response body")) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() - val request = Request.Builder() - .url("https://android.com/foo") - .header("Proxy-Authorization", "password") - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() + val request = + Request.Builder() + .url("https://android.com/foo") + .header("Proxy-Authorization", "password") + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") val connect1 = server.takeRequest() @@ -3431,24 +3681,25 @@ open class CallTest { server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "encrypted response from the origin server")) val credential = basic("jesse", "password1") - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .hostnameVerifier(RecordingHostnameVerifier()) - .proxyAuthenticator { _: Route?, response: Response? -> - assertThat(response!!.request.method).isEqualTo("CONNECT") - assertThat(response.code).isEqualTo(HttpURLConnection.HTTP_PROXY_AUTH) - assertThat(response.request.url.host).isEqualTo("android.com") - val challenges = response.challenges() - assertThat(challenges[0].scheme).isEqualTo("OkHttp-Preemptive") - response.request.newBuilder() - .header("Proxy-Authorization", credential) - .build() - } - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .hostnameVerifier(RecordingHostnameVerifier()) + .proxyAuthenticator { _: Route?, response: Response? -> + assertThat(response!!.request.method).isEqualTo("CONNECT") + assertThat(response.code).isEqualTo(HttpURLConnection.HTTP_PROXY_AUTH) + assertThat(response.request.url.host).isEqualTo("android.com") + val challenges = response.challenges() + assertThat(challenges[0].scheme).isEqualTo("OkHttp-Preemptive") + response.request.newBuilder() + .header("Proxy-Authorization", credential) + .build() + } + .build() val request = Request("https://android.com/foo".toHttpUrl()) executeSynchronously(request).assertSuccessful() val connect = server.takeRequest() @@ -3470,27 +3721,28 @@ open class CallTest { headers = headersOf("Proxy-Authenticate", "Basic realm=\"localhost\""), body = "proxy auth required", inTunnel = true, - ) + ), ) server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse()) val challengeSchemes: MutableList = ArrayList() val credential = basic("jesse", "password1") - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .hostnameVerifier(RecordingHostnameVerifier()) - .proxyAuthenticator { _: Route?, response: Response -> - val challenges = response.challenges() - challengeSchemes.add(challenges[0].scheme) - response.request.newBuilder() - .header("Proxy-Authorization", credential) - .build() - } - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .hostnameVerifier(RecordingHostnameVerifier()) + .proxyAuthenticator { _: Route?, response: Response -> + val challenges = response.challenges() + challengeSchemes.add(challenges[0].scheme) + response.request.newBuilder() + .header("Proxy-Authorization", credential) + .build() + } + .build() val request = Request("https://android.com/foo".toHttpUrl()) executeSynchronously(request).assertSuccessful() val connect1 = server.takeRequest() @@ -3511,15 +3763,16 @@ open class CallTest { MockResponse( inTunnel = true, socketPolicy = DisconnectAfterRequest, - ) + ), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .proxy(server.toProxyAddress()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .proxy(server.toProxyAddress()) + .build() val request = Request(server.url("/")) assertFailsWith { client.newCall(request).execute() @@ -3533,13 +3786,15 @@ open class CallTest { // Capture the protocol as it is observed by the interceptor. val protocolRef = AtomicReference() - val interceptor = Interceptor { chain: Interceptor.Chain -> - protocolRef.set(chain.connection()!!.protocol()) - chain.proceed(chain.request()) - } - client = client.newBuilder() - .addNetworkInterceptor(interceptor) - .build() + val interceptor = + Interceptor { chain: Interceptor.Chain -> + protocolRef.set(chain.connection()!!.protocol()) + chain.proceed(chain.request()) + } + client = + client.newBuilder() + .addNetworkInterceptor(interceptor) + .build() // Make an HTTP/2 request and confirm that the protocol matches. server.enqueue(MockResponse()) @@ -3552,7 +3807,8 @@ open class CallTest { server.enqueue( MockResponse.Builder() .status("HTP/1.1 200 OK") - .build()) + .build(), + ) executeSynchronously("/") .assertFailure("Unexpected status line: HTP/1.1 200 OK") } @@ -3562,7 +3818,8 @@ open class CallTest { server.enqueue( MockResponse.Builder() .status("HTTP/1.1 2147483648 OK") - .build()) + .build(), + ) executeSynchronously("/") .assertFailure("Unexpected status line: HTTP/1.1 2147483648 OK") } @@ -3572,7 +3829,8 @@ open class CallTest { server.enqueue( MockResponse.Builder() .status("HTTP/1.1 00a OK") - .build()) + .build(), + ) executeSynchronously("/") .assertFailure("Unexpected status line: HTTP/1.1 00a OK") } @@ -3582,7 +3840,8 @@ open class CallTest { server.enqueue( MockResponse.Builder() .status(" HTTP/1.1 200 OK") - .build()) + .build(), + ) executeSynchronously("/") .assertFailure("Unexpected status line: HTTP/1.1 200 OK") } @@ -3612,7 +3871,8 @@ open class CallTest { .clearHeaders() .addHeader("content-length: 0") .addHeaderLenient("a b", "c") - .build()) + .build(), + ) val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.header("a b")).isEqualTo("c") @@ -3625,7 +3885,8 @@ open class CallTest { .clearHeaders() .addHeader("content-length: 0") .addHeaderLenient("a\tb", "c") - .build()) + .build(), + ) val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.header("a\tb")).isEqualTo("c") @@ -3643,18 +3904,20 @@ open class CallTest { server.enqueue(MockResponse()) // Enable a misconfigured proxy selector to guarantee that the request is retried. - client = client.newBuilder() - .proxySelector( - FakeProxySelector() - .addProxy(server2.toProxyAddress()) - .addProxy(Proxy.NO_PROXY) - ) - .build() + client = + client.newBuilder() + .proxySelector( + FakeProxySelector() + .addProxy(server2.toProxyAddress()) + .addProxy(Proxy.NO_PROXY), + ) + .build() server2.shutdown() - val request = Request( - url = server.url("/"), - body = "abc".toRequestBody("text/plain".toMediaType()), - ) + val request = + Request( + url = server.url("/"), + body = "abc".toRequestBody("text/plain".toMediaType()), + ) executeSynchronously(request) assertThat(server.takeRequest().body.readUtf8()).isEqualTo("abc") } @@ -3699,13 +3962,17 @@ open class CallTest { assertThat(recordedRequest.chunkSizes).isEmpty() } - private fun upload(chunked: Boolean, size: Int, writeSize: Int) { + private fun upload( + chunked: Boolean, + size: Int, + writeSize: Int, + ) { server.enqueue(MockResponse()) executeSynchronously( Request( url = server.url("/"), body = requestBody(chunked, size.toLong(), writeSize), - ) + ), ) } @@ -3714,13 +3981,14 @@ open class CallTest { fun ipv6HostHasSquareBracesHttp1() { configureClientAndServerProxies(http2 = false) server.enqueue( - MockResponse(body = "response body") + MockResponse(body = "response body"), ) val port = server.port - val url = server.url("/").newBuilder() - .host("::1") - .port(port) - .build() + val url = + server.url("/").newBuilder() + .host("::1") + .port(port) + .build() val request = Request(url) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") @@ -3739,29 +4007,30 @@ open class CallTest { fun ipv6HostHasSquareBracesHttp2() { configureClientAndServerProxies(http2 = true) server.enqueue( - MockResponse(body = "response body") + MockResponse(body = "response body"), ) val port = server.port - val url = server.url("/").newBuilder() - .host("::1") - .port(port) - .build() + val url = + server.url("/").newBuilder() + .host("::1") + .port(port) + .build() val request = Request(url) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") val connect = server.takeRequest() assertThat(connect.requestLine).isEqualTo( - "CONNECT [::1]:$port HTTP/1.1" + "CONNECT [::1]:$port HTTP/1.1", ) assertThat(connect.headers["Host"]).isEqualTo( - "[::1]:$port" + "[::1]:$port", ) assertThat(connect.headers[":authority"]).isNull() val get = server.takeRequest() assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1") assertThat(get.headers["Host"]).isNull() assertThat(get.headers[":authority"]).isEqualTo( - "[::1]:$port" + "[::1]:$port", ) assertThat(get.requestUrl).isEqualTo(url) } @@ -3770,28 +4039,29 @@ open class CallTest { fun ipv4IpHostHasNoSquareBracesHttp1() { configureClientAndServerProxies(http2 = false) server.enqueue( - MockResponse(body = "response body") + MockResponse(body = "response body"), ) val port = server.port - val url = server.url("/").newBuilder() - .host("127.0.0.1") - .port(port) - .build() + val url = + server.url("/").newBuilder() + .host("127.0.0.1") + .port(port) + .build() val request = Request(url) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") val connect = server.takeRequest() assertThat(connect.requestLine).isEqualTo( - "CONNECT 127.0.0.1:$port HTTP/1.1" + "CONNECT 127.0.0.1:$port HTTP/1.1", ) assertThat(connect.headers["Host"]).isEqualTo( - "127.0.0.1:$port" + "127.0.0.1:$port", ) assertThat(connect.headers[":authority"]).isNull() val get = server.takeRequest() assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1") assertThat(get.headers["Host"]).isEqualTo( - "127.0.0.1:$port" + "127.0.0.1:$port", ) assertThat(get.headers[":authority"]).isNull() assertThat(get.requestUrl).isEqualTo(url) @@ -3801,13 +4071,14 @@ open class CallTest { fun ipv4IpHostHasNoSquareBracesHttp2() { configureClientAndServerProxies(http2 = true) server.enqueue( - MockResponse(body = "response body") + MockResponse(body = "response body"), ) val port = server.port - val url = server.url("/").newBuilder() - .host("127.0.0.1") - .port(port) - .build() + val url = + server.url("/").newBuilder() + .host("127.0.0.1") + .port(port) + .build() val request = Request(url) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") @@ -3826,13 +4097,14 @@ open class CallTest { fun hostnameRequestHostHasNoSquareBracesHttp1() { configureClientAndServerProxies(http2 = false) server.enqueue( - MockResponse(body = "response body") + MockResponse(body = "response body"), ) val port = server.port - val url = server.url("/").newBuilder() - .host("any-host-name") - .port(port) - .build() + val url = + server.url("/").newBuilder() + .host("any-host-name") + .port(port) + .build() val request = Request(url) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") @@ -3851,13 +4123,14 @@ open class CallTest { fun hostnameRequestHostHasNoSquareBracesHttp2() { configureClientAndServerProxies(http2 = true) server.enqueue( - MockResponse(body = "response body") + MockResponse(body = "response body"), ) val port = server.port - val url = server.url("/").newBuilder() - .host("any-host-name") - .port(port) - .build() + val url = + server.url("/").newBuilder() + .host("any-host-name") + .port(port) + .build() val request = Request(url) val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("response body") @@ -3875,21 +4148,27 @@ open class CallTest { /** Use a proxy to fake IPv6 connectivity, even if localhost doesn't have IPv6. */ private fun configureClientAndServerProxies(http2: Boolean) { server.useHttps(handshakeCertificates.sslSocketFactory()) - server.protocols = when { - http2 -> listOf(Protocol.HTTP_2, Protocol.HTTP_1_1) - else -> listOf(Protocol.HTTP_1_1) - } + server.protocols = + when { + http2 -> listOf(Protocol.HTTP_2, Protocol.HTTP_1_1) + else -> listOf(Protocol.HTTP_1_1) + } server.enqueue(MockResponse(inTunnel = true)) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .proxy(server.toProxyAddress()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .proxy(server.toProxyAddress()) + .build() } - private fun requestBody(chunked: Boolean, size: Long, writeSize: Int): RequestBody { + private fun requestBody( + chunked: Boolean, + size: Long, + writeSize: Int, + ): RequestBody { val buffer = ByteArray(writeSize) Arrays.fill(buffer, 'x'.code.toByte()) return object : RequestBody() { @@ -3912,7 +4191,7 @@ open class CallTest { @Test fun emptyResponseBody() { server.enqueue( - MockResponse(headers = headersOf("abc", "def")) + MockResponse(headers = headersOf("abc", "def")), ) executeSynchronously("/") .assertCode(200) @@ -3923,17 +4202,18 @@ open class CallTest { @Test fun leakedResponseBodyLogsStackTrace() { server.enqueue( - MockResponse(body = "This gets leaked.") + MockResponse(body = "This gets leaked."), ) - client = clientTestRule.newClientBuilder() - .connectionPool(ConnectionPool(0, 10, TimeUnit.MILLISECONDS)) - .build() + client = + clientTestRule.newClientBuilder() + .connectionPool(ConnectionPool(0, 10, TimeUnit.MILLISECONDS)) + .build() val request = Request(server.url("/")) client.newCall(request).execute() // Ignore the response so it gets leaked then GC'd. awaitGarbageCollection() val message = testLogHandler.take() assertThat(message).contains( - "A connection to ${server.url("/")} was leaked. Did you forget to close a response body?" + "A connection to ${server.url("/")} was leaked. Did you forget to close a response body?", ) } @@ -3941,21 +4221,30 @@ open class CallTest { @Test fun asyncLeakedResponseBodyLogsStackTrace() { server.enqueue(MockResponse(body = "This gets leaked.")) - client = clientTestRule.newClientBuilder() - .connectionPool(ConnectionPool(0, 10, TimeUnit.MILLISECONDS)) - .build() + client = + clientTestRule.newClientBuilder() + .connectionPool(ConnectionPool(0, 10, TimeUnit.MILLISECONDS)) + .build() val request = Request(server.url("/")) val latch = CountDownLatch(1) - client.newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - fail("") - } + client.newCall(request).enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + fail("") + } - override fun onResponse(call: Call, response: Response) { - // Ignore the response so it gets leaked then GC'd. - latch.countDown() - } - }) + override fun onResponse( + call: Call, + response: Response, + ) { + // Ignore the response so it gets leaked then GC'd. + latch.countDown() + } + }, + ) latch.await() // There's some flakiness when triggering a GC for objects in a separate thread. Adding a // small delay appears to ensure the objects will get GC'd. @@ -3963,16 +4252,17 @@ open class CallTest { awaitGarbageCollection() val message = testLogHandler.take() assertThat(message).contains( - "A connection to ${server.url("/")} was leaked. Did you forget to close a response body?" + "A connection to ${server.url("/")} was leaked. Did you forget to close a response body?", ) } @Test fun failedAuthenticatorReleasesConnection() { server.enqueue(MockResponse(code = 401)) - client = client.newBuilder() - .authenticator { _: Route?, _: Response -> throw IOException("IOException!") } - .build() + client = + client.newBuilder() + .authenticator { _: Route?, _: Response -> throw IOException("IOException!") } + .build() val request = Request(server.url("/")) executeSynchronously(request) .assertFailure(IOException::class.java) @@ -3982,13 +4272,14 @@ open class CallTest { @Test fun failedProxyAuthenticatorReleasesConnection() { server.enqueue( - MockResponse(code = 407) + MockResponse(code = 407), ) - client = client.newBuilder() - .proxyAuthenticator { _: Route?, _: Response -> - throw IOException("IOException!") - } - .build() + client = + client.newBuilder() + .proxyAuthenticator { _: Route?, _: Response -> + throw IOException("IOException!") + } + .build() val request = Request(server.url("/")) executeSynchronously(request) .assertFailure(IOException::class.java) @@ -4002,30 +4293,34 @@ open class CallTest { val localIpAddress = InetAddress.getLoopbackAddress().hostAddress // Create a certificate with an IP address in the subject alt name. - val heldCertificate = HeldCertificate.Builder() - .commonName("example.com") - .addSubjectAlternativeName(localIpAddress!!) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate(heldCertificate) - .addTrustedCertificate(heldCertificate.certificate) - .build() + val heldCertificate = + HeldCertificate.Builder() + .commonName("example.com") + .addSubjectAlternativeName(localIpAddress!!) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate(heldCertificate) + .addTrustedCertificate(heldCertificate.certificate) + .build() // Use that certificate on the server and trust it on the client. server.useHttps(handshakeCertificates.sslSocketFactory()) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .protocols(listOf(Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .protocols(listOf(Protocol.HTTP_1_1)) + .build() // Make a request. server.enqueue(MockResponse()) - val url = server.url("/").newBuilder() - .host(localIpAddress) - .build() + val url = + server.url("/").newBuilder() + .host(localIpAddress) + .build() val request = Request(url) executeSynchronously(request) .assertCode(200) @@ -4038,21 +4333,24 @@ open class CallTest { @Test fun postWithFileNotFound() { val called = AtomicInteger(0) - val body: RequestBody = object : RequestBody() { - override fun contentType(): MediaType = "application/octet-stream".toMediaType() + val body: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType = "application/octet-stream".toMediaType() - override fun writeTo(sink: BufferedSink) { - called.incrementAndGet() - throw FileNotFoundException() + override fun writeTo(sink: BufferedSink) { + called.incrementAndGet() + throw FileNotFoundException() + } } - } - val request = Request( - url = server.url("/"), - body = body, - ) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() + val request = + Request( + url = server.url("/"), + body = body, + ) + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() executeSynchronously(request) .assertFailure(FileNotFoundException::class.java) assertThat(called.get()).isEqualTo(1) @@ -4060,13 +4358,15 @@ open class CallTest { @Test fun clientReadsHeadersDataTrailersHttp1ChunkedTransferEncoding() { - server.enqueue(MockResponse.Builder() - .clearHeaders() - .addHeader("h1", "v1") - .addHeader("h2", "v2") - .chunkedBody("HelloBonjour", 1024) - .trailers(headersOf("trailers", "boom")) - .build()) + server.enqueue( + MockResponse.Builder() + .clearHeaders() + .addHeader("h1", "v1") + .addHeader("h2", "v2") + .chunkedBody("HelloBonjour", 1024) + .trailers(headersOf("trailers", "boom")) + .build(), + ) val call = client.newCall(Request(server.url("/"))) val response = call.execute() val source = response.body.source() @@ -4081,13 +4381,15 @@ open class CallTest { @Test fun clientReadsHeadersDataTrailersHttp2() { platform.assumeHttp2Support() - server.enqueue(MockResponse.Builder() - .clearHeaders() - .addHeader("h1", "v1") - .addHeader("h2", "v2") - .body("HelloBonjour") - .trailers(headersOf("trailers", "boom")) - .build()) + server.enqueue( + MockResponse.Builder() + .clearHeaders() + .addHeader("h1", "v1") + .addHeader("h2", "v2") + .body("HelloBonjour") + .trailers(headersOf("trailers", "boom")) + .build(), + ) enableProtocol(Protocol.HTTP_2) val call = client.newCall(Request(server.url("/"))) call.execute().use { response -> @@ -4103,14 +4405,19 @@ open class CallTest { @Test fun connectionIsImmediatelyUnhealthy() { - val listener: EventListener = object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - connection.socket().closeQuietly() + val listener: EventListener = + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + connection.socket().closeQuietly() + } } - } - client = client.newBuilder() - .eventListener(listener) - .build() + client = + client.newBuilder() + .eventListener(listener) + .build() executeSynchronously("/") .assertFailure(IOException::class.java) .assertFailure("Socket closed", "Socket is closed") @@ -4119,19 +4426,21 @@ open class CallTest { @Test fun requestBodyThrowsUnrelatedToNetwork() { server.enqueue(MockResponse()) - val request = Request( - url = server.url("/"), - body = object : RequestBody() { - override fun contentType(): MediaType? { - return null - } - - override fun writeTo(sink: BufferedSink) { - sink.flush() // For determinism, always send a partial request to the server. - throw IOException("boom") - } - }, - ) + val request = + Request( + url = server.url("/"), + body = + object : RequestBody() { + override fun contentType(): MediaType? { + return null + } + + override fun writeTo(sink: BufferedSink) { + sink.flush() // For determinism, always send a partial request to the server. + throw IOException("boom") + } + }, + ) executeSynchronously(request).assertFailure("boom") assertThat(server.takeRequest().failure).isNotNull() } @@ -4152,16 +4461,23 @@ open class CallTest { enableTls() server.enqueue(MockResponse(body = "abc")) server.enqueue(MockResponse(body = "def")) - client = client.newBuilder() - .protocols(listOf(Protocol.HTTP_1_1)) - .build() - val cancelClient = client.newBuilder() - .eventListener(object : EventListener() { - override fun responseBodyEnd(call: Call, byteCount: Long) { - call.cancel() - } - }) - .build() + client = + client.newBuilder() + .protocols(listOf(Protocol.HTTP_1_1)) + .build() + val cancelClient = + client.newBuilder() + .eventListener( + object : EventListener() { + override fun responseBodyEnd( + call: Call, + byteCount: Long, + ) { + call.cancel() + } + }, + ) + .build() val call = cancelClient.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("abc") @@ -4172,24 +4488,28 @@ open class CallTest { @Test fun lateCancelCallsOnFailure() { server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) val closed = AtomicBoolean() - client = client.newBuilder() - .addInterceptor(Interceptor { chain -> - val response = chain.proceed(chain.request()) - chain.call().cancel() // Cancel after we have the response. - val closeTrackingSource = object : ForwardingSource(response.body.source()) { - override fun close() { - closed.set(true) - super.close() - } - } - response.newBuilder() - .body(closeTrackingSource.buffer().asResponseBody()) - .build() - }) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain -> + val response = chain.proceed(chain.request()) + chain.call().cancel() // Cancel after we have the response. + val closeTrackingSource = + object : ForwardingSource(response.body.source()) { + override fun close() { + closed.set(true) + super.close() + } + } + response.newBuilder() + .body(closeTrackingSource.buffer().asResponseBody()) + .build() + }, + ) + .build() executeSynchronously("/").assertFailure("Canceled") assertThat(closed.get()).isTrue() } @@ -4199,16 +4519,20 @@ open class CallTest { server.enqueue( MockResponse( code = 301, - headers = headersOf( - "Location", "/b", - "Content-Type", "text/plain; charset=UTF-8", - "Test", "Redirect from /a to /b", - ), + headers = + headersOf( + "Location", + "/b", + "Content-Type", + "text/plain; charset=UTF-8", + "Test", + "Redirect from /a to /b", + ), body = "/a has moved!", - ) + ), ) server.enqueue( - MockResponse(body = "this is the redirect target") + MockResponse(body = "this is the redirect target"), ) val call = client.newCall(Request(server.url("/"))) @@ -4224,25 +4548,28 @@ open class CallTest { } private fun makeFailingCall() { - val requestBody: RequestBody = object : RequestBody() { - override fun contentType() = null + val requestBody: RequestBody = + object : RequestBody() { + override fun contentType() = null - override fun contentLength() = 1L + override fun contentLength() = 1L - override fun writeTo(sink: BufferedSink) { - sink.flush() // For determinism, always send a partial request to the server. - throw IOException("write body fail!") + override fun writeTo(sink: BufferedSink) { + sink.flush() // For determinism, always send a partial request to the server. + throw IOException("write body fail!") + } } - } - val nonRetryingClient = client.newBuilder() - .retryOnConnectionFailure(false) - .build() - val call = nonRetryingClient.newCall( - Request( - url = server.url("/"), - body = requestBody, + val nonRetryingClient = + client.newBuilder() + .retryOnConnectionFailure(false) + .build() + val call = + nonRetryingClient.newCall( + Request( + url = server.url("/"), + body = requestBody, + ), ) - ) assertFailsWith { call.execute() }.also { expected -> @@ -4250,7 +4577,10 @@ open class CallTest { } } - private fun executeSynchronously(path: String, vararg headers: String?): RecordedResponse { + private fun executeSynchronously( + path: String, + vararg headers: String?, + ): RecordedResponse { val builder = Request.Builder() builder.url(server.url(path)) var i = 0 @@ -4278,19 +4608,21 @@ open class CallTest { */ private fun enableProtocol(protocol: Protocol) { enableTls() - client = client.newBuilder() - .protocols(listOf(protocol, Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .protocols(listOf(protocol, Protocol.HTTP_1_1)) + .build() server.protocols = client.protocols } private fun enableTls() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } @@ -4302,17 +4634,21 @@ open class CallTest { return result } - private fun cancelLater(call: Call, delay: Long): Thread { - val thread = object : Thread("canceler") { - override fun run() { - try { - sleep(delay) - } catch (e: InterruptedException) { - throw AssertionError() + private fun cancelLater( + call: Call, + delay: Long, + ): Thread { + val thread = + object : Thread("canceler") { + override fun run() { + try { + sleep(delay) + } catch (e: InterruptedException) { + throw AssertionError() + } + call.cancel() } - call.cancel() } - } thread.start() return thread } @@ -4330,7 +4666,7 @@ open class CallTest { } private class RecordingSSLSocketFactory( - delegate: SSLSocketFactory + delegate: SSLSocketFactory, ) : DelegatingSSLSocketFactory(delegate) { val socketsCreated = mutableListOf() diff --git a/okhttp/src/test/java/okhttp3/CertificateChainCleanerTest.kt b/okhttp/src/test/java/okhttp3/CertificateChainCleanerTest.kt index 11a76141bd95..d36ca69e0772 100644 --- a/okhttp/src/test/java/okhttp3/CertificateChainCleanerTest.kt +++ b/okhttp/src/test/java/okhttp3/CertificateChainCleanerTest.kt @@ -28,12 +28,14 @@ import org.junit.jupiter.api.Test class CertificateChainCleanerTest { @Test fun equalsFromCertificate() { - val rootA = HeldCertificate.Builder() - .serialNumber(1L) - .build() - val rootB = HeldCertificate.Builder() - .serialNumber(2L) - .build() + val rootA = + HeldCertificate.Builder() + .serialNumber(1L) + .build() + val rootB = + HeldCertificate.Builder() + .serialNumber(2L) + .build() assertThat(get(rootB.certificate, rootA.certificate)) .isEqualTo(get(rootA.certificate, rootB.certificate)) } @@ -47,18 +49,20 @@ class CertificateChainCleanerTest { @Test fun normalizeSingleSelfSignedCertificate() { - val root = HeldCertificate.Builder() - .serialNumber(1L) - .build() + val root = + HeldCertificate.Builder() + .serialNumber(1L) + .build() val cleaner = get(root.certificate) assertThat(cleaner.clean(list(root), "hostname")).isEqualTo(list(root)) } @Test fun normalizeUnknownSelfSignedCertificate() { - val root = HeldCertificate.Builder() - .serialNumber(1L) - .build() + val root = + HeldCertificate.Builder() + .serialNumber(1L) + .build() val cleaner = get() assertFailsWith { cleaner.clean(list(root), "hostname") @@ -67,19 +71,22 @@ class CertificateChainCleanerTest { @Test fun orderedChainOfCertificatesWithRoot() { - val root = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .build() - val certA = HeldCertificate.Builder() - .serialNumber(2L) - .certificateAuthority(0) - .signedBy(root) - .build() - val certB = HeldCertificate.Builder() - .serialNumber(3L) - .signedBy(certA) - .build() + val root = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .build() + val certA = + HeldCertificate.Builder() + .serialNumber(2L) + .certificateAuthority(0) + .signedBy(root) + .build() + val certB = + HeldCertificate.Builder() + .serialNumber(3L) + .signedBy(certA) + .build() val cleaner = get(root.certificate) assertThat(cleaner.clean(list(certB, certA, root), "hostname")) .isEqualTo(list(certB, certA, root)) @@ -87,166 +94,191 @@ class CertificateChainCleanerTest { @Test fun orderedChainOfCertificatesWithoutRoot() { - val root = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .build() - val certA = HeldCertificate.Builder() - .serialNumber(2L) - .certificateAuthority(0) - .signedBy(root) - .build() - val certB = HeldCertificate.Builder() - .serialNumber(3L) - .signedBy(certA) - .build() + val root = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .build() + val certA = + HeldCertificate.Builder() + .serialNumber(2L) + .certificateAuthority(0) + .signedBy(root) + .build() + val certB = + HeldCertificate.Builder() + .serialNumber(3L) + .signedBy(certA) + .build() val cleaner = get(root.certificate) // Root is added! assertThat(cleaner.clean(list(certB, certA), "hostname")).isEqualTo( - list(certB, certA, root) + list(certB, certA, root), ) } @Test fun unorderedChainOfCertificatesWithRoot() { - val root = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(2) - .build() - val certA = HeldCertificate.Builder() - .serialNumber(2L) - .certificateAuthority(1) - .signedBy(root) - .build() - val certB = HeldCertificate.Builder() - .serialNumber(3L) - .certificateAuthority(0) - .signedBy(certA) - .build() - val certC = HeldCertificate.Builder() - .serialNumber(4L) - .signedBy(certB) - .build() + val root = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(2) + .build() + val certA = + HeldCertificate.Builder() + .serialNumber(2L) + .certificateAuthority(1) + .signedBy(root) + .build() + val certB = + HeldCertificate.Builder() + .serialNumber(3L) + .certificateAuthority(0) + .signedBy(certA) + .build() + val certC = + HeldCertificate.Builder() + .serialNumber(4L) + .signedBy(certB) + .build() val cleaner = get(root.certificate) assertThat(cleaner.clean(list(certC, certA, root, certB), "hostname")).isEqualTo( - list(certC, certB, certA, root) + list(certC, certB, certA, root), ) } @Test fun unorderedChainOfCertificatesWithoutRoot() { - val root = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(2) - .build() - val certA = HeldCertificate.Builder() - .serialNumber(2L) - .certificateAuthority(1) - .signedBy(root) - .build() - val certB = HeldCertificate.Builder() - .serialNumber(3L) - .certificateAuthority(0) - .signedBy(certA) - .build() - val certC = HeldCertificate.Builder() - .serialNumber(4L) - .signedBy(certB) - .build() + val root = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(2) + .build() + val certA = + HeldCertificate.Builder() + .serialNumber(2L) + .certificateAuthority(1) + .signedBy(root) + .build() + val certB = + HeldCertificate.Builder() + .serialNumber(3L) + .certificateAuthority(0) + .signedBy(certA) + .build() + val certC = + HeldCertificate.Builder() + .serialNumber(4L) + .signedBy(certB) + .build() val cleaner = get(root.certificate) assertThat(cleaner.clean(list(certC, certA, certB), "hostname")).isEqualTo( - list(certC, certB, certA, root) + list(certC, certB, certA, root), ) } @Test fun unrelatedCertificatesAreOmitted() { - val root = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .build() - val certA = HeldCertificate.Builder() - .serialNumber(2L) - .certificateAuthority(0) - .signedBy(root) - .build() - val certB = HeldCertificate.Builder() - .serialNumber(3L) - .signedBy(certA) - .build() - val certUnnecessary = HeldCertificate.Builder() - .serialNumber(4L) - .build() + val root = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .build() + val certA = + HeldCertificate.Builder() + .serialNumber(2L) + .certificateAuthority(0) + .signedBy(root) + .build() + val certB = + HeldCertificate.Builder() + .serialNumber(3L) + .signedBy(certA) + .build() + val certUnnecessary = + HeldCertificate.Builder() + .serialNumber(4L) + .build() val cleaner = get(root.certificate) assertThat(cleaner.clean(list(certB, certUnnecessary, certA, root), "hostname")) .isEqualTo( - list(certB, certA, root) + list(certB, certA, root), ) } @Test fun chainGoesAllTheWayToSelfSignedRoot() { - val selfSigned = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(2) - .build() - val trusted = HeldCertificate.Builder() - .serialNumber(2L) - .signedBy(selfSigned) - .certificateAuthority(1) - .build() - val certA = HeldCertificate.Builder() - .serialNumber(3L) - .certificateAuthority(0) - .signedBy(trusted) - .build() - val certB = HeldCertificate.Builder() - .serialNumber(4L) - .signedBy(certA) - .build() - val cleaner = get( - selfSigned.certificate, trusted.certificate - ) + val selfSigned = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(2) + .build() + val trusted = + HeldCertificate.Builder() + .serialNumber(2L) + .signedBy(selfSigned) + .certificateAuthority(1) + .build() + val certA = + HeldCertificate.Builder() + .serialNumber(3L) + .certificateAuthority(0) + .signedBy(trusted) + .build() + val certB = + HeldCertificate.Builder() + .serialNumber(4L) + .signedBy(certA) + .build() + val cleaner = + get( + selfSigned.certificate, + trusted.certificate, + ) assertThat(cleaner.clean(list(certB, certA), "hostname")).isEqualTo( - list(certB, certA, trusted, selfSigned) + list(certB, certA, trusted, selfSigned), ) assertThat(cleaner.clean(list(certB, certA, trusted), "hostname")).isEqualTo( - list(certB, certA, trusted, selfSigned) + list(certB, certA, trusted, selfSigned), ) assertThat(cleaner.clean(list(certB, certA, trusted, selfSigned), "hostname")) .isEqualTo( - list(certB, certA, trusted, selfSigned) + list(certB, certA, trusted, selfSigned), ) } @Test fun trustedRootNotSelfSigned() { - val unknownSigner = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(2) - .build() - val trusted = HeldCertificate.Builder() - .signedBy(unknownSigner) - .certificateAuthority(1) - .serialNumber(2L) - .build() - val intermediateCa = HeldCertificate.Builder() - .signedBy(trusted) - .certificateAuthority(0) - .serialNumber(3L) - .build() - val certificate = HeldCertificate.Builder() - .signedBy(intermediateCa) - .serialNumber(4L) - .build() + val unknownSigner = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(2) + .build() + val trusted = + HeldCertificate.Builder() + .signedBy(unknownSigner) + .certificateAuthority(1) + .serialNumber(2L) + .build() + val intermediateCa = + HeldCertificate.Builder() + .signedBy(trusted) + .certificateAuthority(0) + .serialNumber(3L) + .build() + val certificate = + HeldCertificate.Builder() + .signedBy(intermediateCa) + .serialNumber(4L) + .build() val cleaner = get(trusted.certificate) assertThat(cleaner.clean(list(certificate, intermediateCa), "hostname")) .isEqualTo( - list(certificate, intermediateCa, trusted) + list(certificate, intermediateCa, trusted), ) assertThat(cleaner.clean(list(certificate, intermediateCa, trusted), "hostname")) .isEqualTo( - list(certificate, intermediateCa, trusted) + list(certificate, intermediateCa, trusted), ) } @@ -261,7 +293,7 @@ class CertificateChainCleanerTest { val cleaner = get(root) assertThat(cleaner.clean(certificates, "hostname")).isEqualTo(certificates) assertThat(cleaner.clean(certificates.subList(0, 9), "hostname")).isEqualTo( - certificates + certificates, ) } @@ -284,11 +316,12 @@ class CertificateChainCleanerTest { val result = mutableListOf() for (i in 1..length) { result.add( - 0, HeldCertificate.Builder() + 0, + HeldCertificate.Builder() .signedBy(if (result.isNotEmpty()) result[0] else null) .certificateAuthority(length - i) .serialNumber(i.toLong()) - .build() + .build(), ) } return result diff --git a/okhttp/src/test/java/okhttp3/CertificatePinnerKotlinTest.kt b/okhttp/src/test/java/okhttp3/CertificatePinnerKotlinTest.kt index 3d974e5d9992..c0b9f85e23c6 100644 --- a/okhttp/src/test/java/okhttp3/CertificatePinnerKotlinTest.kt +++ b/okhttp/src/test/java/okhttp3/CertificatePinnerKotlinTest.kt @@ -29,10 +29,10 @@ import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test class CertificatePinnerKotlinTest { - @Test fun successfulCheckSha1Pin() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("example.com", "sha1/" + certA1.certificate.sha1Hash().base64()) .build() @@ -40,33 +40,40 @@ class CertificatePinnerKotlinTest { } @Test fun successfulFindMatchingPins() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("first.com", certA1Sha256Pin, certB1Sha256Pin) .add("second.com", certC1Sha256Pin) .build() - val expectedPins = listOf( + val expectedPins = + listOf( Pin("first.com", certA1Sha256Pin), - Pin("first.com", certB1Sha256Pin)) + Pin("first.com", certB1Sha256Pin), + ) assertThat(certificatePinner.findMatchingPins("first.com")).isEqualTo(expectedPins) } @Test fun successfulFindMatchingPinsForWildcardAndDirectCertificates() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("*.example.com", certA1Sha256Pin) .add("a.example.com", certB1Sha256Pin) .add("b.example.com", certC1Sha256Pin) .build() - val expectedPins = listOf( + val expectedPins = + listOf( Pin("*.example.com", certA1Sha256Pin), - Pin("a.example.com", certB1Sha256Pin)) + Pin("a.example.com", certB1Sha256Pin), + ) assertThat(certificatePinner.findMatchingPins("a.example.com")).isEqualTo(expectedPins) } @Test fun wildcardHostnameShouldNotMatchThroughDot() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("*.example.com", certA1Sha256Pin) .build() @@ -78,7 +85,8 @@ class CertificatePinnerKotlinTest { @Test fun doubleWildcardHostnameShouldMatchThroughDot() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("**.example.com", certA1Sha256Pin) .build() @@ -92,7 +100,8 @@ class CertificatePinnerKotlinTest { @Test fun doubleWildcardHostnameShouldNotMatchSuffix() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("**.example.com", certA1Sha256Pin) .build() @@ -102,7 +111,8 @@ class CertificatePinnerKotlinTest { } @Test fun successfulFindMatchingPinsIgnoresCase() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("EXAMPLE.com", certA1Sha256Pin) .add("*.MyExample.Com", certB1Sha256Pin) .build() @@ -115,7 +125,8 @@ class CertificatePinnerKotlinTest { } @Test fun successfulFindMatchingPinPunycode() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("σkhttp.com", certA1Sha256Pin) .build() @@ -126,7 +137,8 @@ class CertificatePinnerKotlinTest { /** https://github.com/square/okhttp/issues/3324 */ @Test fun checkSubstringMatch() { - val certificatePinner = CertificatePinner.Builder() + val certificatePinner = + CertificatePinner.Builder() .add("*.example.com", certA1Sha256Pin) .build() @@ -142,14 +154,15 @@ class CertificatePinnerKotlinTest { assertThat(certificatePinner.findMatchingPins("a.example.com")).containsExactly(expectedPin) assertThat(certificatePinner.findMatchingPins(".example.com")).containsExactly(expectedPin) assertThat(certificatePinner.findMatchingPins("example.example.com")) - .containsExactly(expectedPin) + .containsExactly(expectedPin) } @Test fun testGoodPin() { - val pin = Pin( + val pin = + Pin( "**.example.co.uk", - "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - ) + "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + ) assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".decodeBase64(), pin.hash) assertEquals("sha256", pin.hashAlgorithm) assertEquals("**.example.co.uk", pin.pattern) @@ -171,31 +184,37 @@ class CertificatePinnerKotlinTest { } @Test fun pinList() { - val builder = CertificatePinner.Builder() + val builder = + CertificatePinner.Builder() .add("example.com", CertificatePinnerTest.certA1Sha256Pin) .add("www.example.com", CertificatePinnerTest.certA1Sha256Pin) val certificatePinner = builder.build() val expectedPins = - listOf(Pin("example.com", CertificatePinnerTest.certA1Sha256Pin), - Pin("www.example.com", CertificatePinnerTest.certA1Sha256Pin)) + listOf( + Pin("example.com", CertificatePinnerTest.certA1Sha256Pin), + Pin("www.example.com", CertificatePinnerTest.certA1Sha256Pin), + ) assertEquals(expectedPins, builder.pins) assertEquals(expectedPins.toSet(), certificatePinner.pins) } companion object { - internal var certA1: HeldCertificate = HeldCertificate.Builder() + internal var certA1: HeldCertificate = + HeldCertificate.Builder() .serialNumber(100L) .build() internal var certA1Sha256Pin = CertificatePinner.pin(certA1.certificate) - private var certB1 = HeldCertificate.Builder() + private var certB1 = + HeldCertificate.Builder() .serialNumber(200L) .build() internal var certB1Sha256Pin = CertificatePinner.pin(certB1.certificate) - private var certC1 = HeldCertificate.Builder() + private var certC1 = + HeldCertificate.Builder() .serialNumber(300L) .build() internal var certC1Sha256Pin = CertificatePinner.pin(certC1.certificate) diff --git a/okhttp/src/test/java/okhttp3/CertificatePinnerTest.kt b/okhttp/src/test/java/okhttp3/CertificatePinnerTest.kt index 2c5559e4d536..5aacd87056d2 100644 --- a/okhttp/src/test/java/okhttp3/CertificatePinnerTest.kt +++ b/okhttp/src/test/java/okhttp3/CertificatePinnerTest.kt @@ -18,7 +18,6 @@ package okhttp3 import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isNotEqualTo -import assertk.fail import java.util.Arrays import javax.net.ssl.SSLPeerUnverifiedException import kotlin.test.assertFailsWith @@ -50,15 +49,17 @@ class CertificatePinnerTest { /** Multiple certificates generated from the same keypair have the same pin. */ @Test fun sameKeypairSamePin() { - val heldCertificateA2 = HeldCertificate.Builder() - .keyPair(certA1.keyPair) - .serialNumber(101L) - .build() + val heldCertificateA2 = + HeldCertificate.Builder() + .keyPair(certA1.keyPair) + .serialNumber(101L) + .build() val keypairACertificate2Pin = pin(heldCertificateA2.certificate) - val heldCertificateB2 = HeldCertificate.Builder() - .keyPair(certB1.keyPair) - .serialNumber(201L) - .build() + val heldCertificateB2 = + HeldCertificate.Builder() + .keyPair(certB1.keyPair) + .serialNumber(201L) + .build() val keypairBCertificate2Pin = pin(heldCertificateB2.certificate) assertThat(keypairACertificate2Pin).isEqualTo(certA1Sha256Pin) assertThat(keypairBCertificate2Pin).isEqualTo(certB1Sha256Pin) @@ -67,36 +68,40 @@ class CertificatePinnerTest { @Test fun successfulCheck() { - val certificatePinner = CertificatePinner.Builder() - .add("example.com", certA1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("example.com", certA1Sha256Pin) + .build() certificatePinner.check("example.com", listOf(certA1.certificate)) } @Test fun successfulMatchAcceptsAnyMatchingCertificateOld() { - val certificatePinner = CertificatePinner.Builder() - .add("example.com", certB1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("example.com", certB1Sha256Pin) + .build() certificatePinner.check("example.com", certA1.certificate, certB1.certificate) } @Test fun successfulMatchAcceptsAnyMatchingCertificate() { - val certificatePinner = CertificatePinner.Builder() - .add("example.com", certB1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("example.com", certB1Sha256Pin) + .build() certificatePinner.check( "example.com", - Arrays.asList(certA1.certificate, certB1.certificate) + Arrays.asList(certA1.certificate, certB1.certificate), ) } @Test fun unsuccessfulCheck() { - val certificatePinner = CertificatePinner.Builder() - .add("example.com", certA1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("example.com", certA1Sha256Pin) + .build() assertFailsWith { certificatePinner.check("example.com", certB1.certificate) } @@ -104,19 +109,21 @@ class CertificatePinnerTest { @Test fun multipleCertificatesForOneHostname() { - val certificatePinner = CertificatePinner.Builder() - .add("example.com", certA1Sha256Pin, certB1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("example.com", certA1Sha256Pin, certB1Sha256Pin) + .build() certificatePinner.check("example.com", listOf(certA1.certificate)) certificatePinner.check("example.com", listOf(certB1.certificate)) } @Test fun multipleHostnamesForOneCertificate() { - val certificatePinner = CertificatePinner.Builder() - .add("example.com", certA1Sha256Pin) - .add("www.example.com", certA1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("example.com", certA1Sha256Pin) + .add("www.example.com", certA1Sha256Pin) + .build() certificatePinner.check("example.com", listOf(certA1.certificate)) certificatePinner.check("www.example.com", listOf(certA1.certificate)) } @@ -129,28 +136,31 @@ class CertificatePinnerTest { @Test fun successfulCheckForWildcardHostname() { - val certificatePinner = CertificatePinner.Builder() - .add("*.example.com", certA1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("*.example.com", certA1Sha256Pin) + .build() certificatePinner.check("a.example.com", listOf(certA1.certificate)) } @Test fun successfulMatchAcceptsAnyMatchingCertificateForWildcardHostname() { - val certificatePinner = CertificatePinner.Builder() - .add("*.example.com", certB1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("*.example.com", certB1Sha256Pin) + .build() certificatePinner.check( "a.example.com", - Arrays.asList(certA1.certificate, certB1.certificate) + Arrays.asList(certA1.certificate, certB1.certificate), ) } @Test fun unsuccessfulCheckForWildcardHostname() { - val certificatePinner = CertificatePinner.Builder() - .add("*.example.com", certA1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("*.example.com", certA1Sha256Pin) + .build() assertFailsWith { certificatePinner.check("a.example.com", listOf(certB1.certificate)) } @@ -158,29 +168,32 @@ class CertificatePinnerTest { @Test fun multipleCertificatesForOneWildcardHostname() { - val certificatePinner = CertificatePinner.Builder() - .add("*.example.com", certA1Sha256Pin, certB1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("*.example.com", certA1Sha256Pin, certB1Sha256Pin) + .build() certificatePinner.check("a.example.com", listOf(certA1.certificate)) certificatePinner.check("a.example.com", listOf(certB1.certificate)) } @Test fun successfulCheckForOneHostnameWithWildcardAndDirectCertificate() { - val certificatePinner = CertificatePinner.Builder() - .add("*.example.com", certA1Sha256Pin) - .add("a.example.com", certB1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("*.example.com", certA1Sha256Pin) + .add("a.example.com", certB1Sha256Pin) + .build() certificatePinner.check("a.example.com", listOf(certA1.certificate)) certificatePinner.check("a.example.com", listOf(certB1.certificate)) } @Test fun unsuccessfulCheckForOneHostnameWithWildcardAndDirectCertificate() { - val certificatePinner = CertificatePinner.Builder() - .add("*.example.com", certA1Sha256Pin) - .add("a.example.com", certB1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("*.example.com", certA1Sha256Pin) + .add("a.example.com", certB1Sha256Pin) + .build() assertFailsWith { certificatePinner.check("a.example.com", listOf(certC1.certificate)) } @@ -188,9 +201,10 @@ class CertificatePinnerTest { @Test fun checkForHostnameWithDoubleAsterisk() { - val certificatePinner = CertificatePinner.Builder() - .add("**.example.co.uk", certA1Sha256Pin) - .build() + val certificatePinner = + CertificatePinner.Builder() + .add("**.example.co.uk", certA1Sha256Pin) + .build() // Should be pinned: assertFailsWith { @@ -218,7 +232,7 @@ class CertificatePinnerTest { assertFailsWith { CertificatePinner.Pin( "example.co.uk", - "sha256/a" + "sha256/a", ) } } @@ -228,7 +242,7 @@ class CertificatePinnerTest { assertFailsWith { CertificatePinner.Pin( "example.co.uk", - "sha512/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + "sha512/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", ) } } @@ -238,20 +252,21 @@ class CertificatePinnerTest { assertFailsWith { CertificatePinner.Pin( "example.*", - "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", ) } } @Test fun testGoodPin() { - val pin = CertificatePinner.Pin( - "**.example.co.uk", - "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - ) + val pin = + CertificatePinner.Pin( + "**.example.co.uk", + "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + ) assertEquals( "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".decodeBase64(), - pin.hash + pin.hash, ) assertEquals("sha256", pin.hashAlgorithm) assertEquals("**.example.co.uk", pin.pattern) @@ -276,30 +291,35 @@ class CertificatePinnerTest { @Test fun pinList() { - val builder = CertificatePinner.Builder() - .add("example.com", certA1Sha256Pin) - .add("www.example.com", certA1Sha256Pin) + val builder = + CertificatePinner.Builder() + .add("example.com", certA1Sha256Pin) + .add("www.example.com", certA1Sha256Pin) val certificatePinner = builder.build() - val expectedPins = Arrays.asList( - CertificatePinner.Pin("example.com", certA1Sha256Pin), - CertificatePinner.Pin("www.example.com", certA1Sha256Pin) - ) + val expectedPins = + Arrays.asList( + CertificatePinner.Pin("example.com", certA1Sha256Pin), + CertificatePinner.Pin("www.example.com", certA1Sha256Pin), + ) assertEquals(expectedPins, builder.pins) assertEquals(HashSet(expectedPins), certificatePinner.pins) } companion object { - val certA1 = HeldCertificate.Builder() - .serialNumber(100L) - .build() + val certA1 = + HeldCertificate.Builder() + .serialNumber(100L) + .build() val certA1Sha256Pin = pin(certA1.certificate) - val certB1 = HeldCertificate.Builder() - .serialNumber(200L) - .build() + val certB1 = + HeldCertificate.Builder() + .serialNumber(200L) + .build() val certB1Sha256Pin = pin(certB1.certificate) - val certC1 = HeldCertificate.Builder() - .serialNumber(300L) - .build() + val certC1 = + HeldCertificate.Builder() + .serialNumber(300L) + .build() val certC1Sha1Pin = "sha1/" + certC1.certificate.sha1Hash().base64() } } diff --git a/okhttp/src/test/java/okhttp3/ChannelSocketFactory.kt b/okhttp/src/test/java/okhttp3/ChannelSocketFactory.kt index b8ce85cfe0b4..27b5119e6f5c 100644 --- a/okhttp/src/test/java/okhttp3/ChannelSocketFactory.kt +++ b/okhttp/src/test/java/okhttp3/ChannelSocketFactory.kt @@ -25,22 +25,27 @@ class ChannelSocketFactory : SocketFactory() { return SocketChannel.open().socket() } - override fun createSocket(host: String, port: Int): Socket = TODO("Not yet implemented") + override fun createSocket( + host: String, + port: Int, + ): Socket = TODO("Not yet implemented") override fun createSocket( host: String, port: Int, localHost: InetAddress, - localPort: Int + localPort: Int, ): Socket = TODO("Not yet implemented") - override fun createSocket(host: InetAddress, port: Int): Socket = - TODO("Not yet implemented") + override fun createSocket( + host: InetAddress, + port: Int, + ): Socket = TODO("Not yet implemented") override fun createSocket( address: InetAddress, port: Int, localAddress: InetAddress, - localPort: Int + localPort: Int, ): Socket = TODO("Not yet implemented") -} \ No newline at end of file +} diff --git a/okhttp/src/test/java/okhttp3/CipherSuiteTest.kt b/okhttp/src/test/java/okhttp3/CipherSuiteTest.kt index 5b38579ce545..255a3ad181b1 100644 --- a/okhttp/src/test/java/okhttp3/CipherSuiteTest.kt +++ b/okhttp/src/test/java/okhttp3/CipherSuiteTest.kt @@ -119,10 +119,11 @@ class CipherSuiteTest { socket.enabledProtocols = arrayOf("TLSv1") socket.supportedCipherSuites = arrayOf("SSL_A", "SSL_B", "SSL_C", "SSL_D", "SSL_E") socket.enabledCipherSuites = arrayOf("SSL_A", "SSL_B", "SSL_C") - val connectionSpec = ConnectionSpec.Builder(true) - .tlsVersions(TlsVersion.TLS_1_0) - .cipherSuites("TLS_A", "TLS_C", "TLS_E") - .build() + val connectionSpec = + ConnectionSpec.Builder(true) + .tlsVersions(TlsVersion.TLS_1_0) + .cipherSuites("TLS_A", "TLS_C", "TLS_E") + .build() applyConnectionSpec(connectionSpec, socket, false) assertArrayEquals(arrayOf("TLS_A", "TLS_C"), socket.enabledCipherSuites) } @@ -134,10 +135,11 @@ class CipherSuiteTest { socket.supportedCipherSuites = arrayOf("TLS_A", "TLS_B", "TLS_C", "TLS_D", "TLS_E") socket.enabledCipherSuites = arrayOf("TLS_A", "TLS_B", "TLS_C") - val connectionSpec = ConnectionSpec.Builder(true) - .tlsVersions(TlsVersion.TLS_1_0) - .cipherSuites("SSL_A", "SSL_C", "SSL_E") - .build() + val connectionSpec = + ConnectionSpec.Builder(true) + .tlsVersions(TlsVersion.TLS_1_0) + .cipherSuites("SSL_A", "SSL_C", "SSL_E") + .build() applyConnectionSpec(connectionSpec, socket, false) assertArrayEquals(arrayOf("SSL_A", "SSL_C"), socket.enabledCipherSuites) } @@ -148,14 +150,15 @@ class CipherSuiteTest { socket.enabledProtocols = arrayOf("TLSv1") socket.supportedCipherSuites = arrayOf("SSL_A", "SSL_FALLBACK_SCSV") socket.enabledCipherSuites = arrayOf("SSL_A") - val connectionSpec = ConnectionSpec.Builder(true) - .tlsVersions(TlsVersion.TLS_1_0) - .cipherSuites("SSL_A") - .build() + val connectionSpec = + ConnectionSpec.Builder(true) + .tlsVersions(TlsVersion.TLS_1_0) + .cipherSuites("SSL_A") + .build() applyConnectionSpec(connectionSpec, socket, true) assertArrayEquals( arrayOf("SSL_A", "SSL_FALLBACK_SCSV"), - socket.enabledCipherSuites + socket.enabledCipherSuites, ) } @@ -165,14 +168,15 @@ class CipherSuiteTest { socket.enabledProtocols = arrayOf("TLSv1") socket.supportedCipherSuites = arrayOf("TLS_A", "TLS_FALLBACK_SCSV") socket.enabledCipherSuites = arrayOf("TLS_A") - val connectionSpec = ConnectionSpec.Builder(true) - .tlsVersions(TlsVersion.TLS_1_0) - .cipherSuites("TLS_A") - .build() + val connectionSpec = + ConnectionSpec.Builder(true) + .tlsVersions(TlsVersion.TLS_1_0) + .cipherSuites("TLS_A") + .build() applyConnectionSpec(connectionSpec, socket, true) assertArrayEquals( arrayOf("TLS_A", "TLS_FALLBACK_SCSV"), - socket.enabledCipherSuites + socket.enabledCipherSuites, ) } @@ -182,10 +186,11 @@ class CipherSuiteTest { socket.enabledProtocols = arrayOf("TLSv1", "TLSv1.1", "TLSv1.2") socket.supportedCipherSuites = arrayOf("TLS_A") socket.enabledCipherSuites = arrayOf("TLS_A") - val connectionSpec = ConnectionSpec.Builder(true) - .tlsVersions(TlsVersion.TLS_1_1, TlsVersion.TLS_1_2, TlsVersion.TLS_1_3) - .cipherSuites("TLS_A") - .build() + val connectionSpec = + ConnectionSpec.Builder(true) + .tlsVersions(TlsVersion.TLS_1_1, TlsVersion.TLS_1_2, TlsVersion.TLS_1_3) + .cipherSuites("TLS_A") + .build() applyConnectionSpec(connectionSpec, socket, false) assertArrayEquals(arrayOf("TLSv1.1", "TLSv1.2"), socket.enabledProtocols) } @@ -194,6 +199,7 @@ class CipherSuiteTest { private lateinit var enabledProtocols: Array private lateinit var supportedCipherSuites: Array private lateinit var enabledCipherSuites: Array + override fun getEnabledProtocols(): Array { return enabledProtocols } diff --git a/okhttp/src/test/java/okhttp3/ConnectionCoalescingTest.kt b/okhttp/src/test/java/okhttp3/ConnectionCoalescingTest.kt index 6d4d2b59cbf5..4c42bb0f9bd0 100644 --- a/okhttp/src/test/java/okhttp3/ConnectionCoalescingTest.kt +++ b/okhttp/src/test/java/okhttp3/ConnectionCoalescingTest.kt @@ -63,39 +63,44 @@ class ConnectionCoalescingTest { this.server = server platform.assumeHttp2Support() platform.assumeNotBouncyCastle() - rootCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(0) - .commonName("root") - .build() - certificate = HeldCertificate.Builder() - .signedBy(rootCa) - .serialNumber(2L) - .commonName(server.hostName) - .addSubjectAlternativeName(server.hostName) - .addSubjectAlternativeName("san.com") - .addSubjectAlternativeName("*.wildcard.com") - .addSubjectAlternativeName("differentdns.com") - .build() + rootCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(0) + .commonName("root") + .build() + certificate = + HeldCertificate.Builder() + .signedBy(rootCa) + .serialNumber(2L) + .commonName(server.hostName) + .addSubjectAlternativeName(server.hostName) + .addSubjectAlternativeName("san.com") + .addSubjectAlternativeName("*.wildcard.com") + .addSubjectAlternativeName("differentdns.com") + .build() serverIps = Dns.SYSTEM.lookup(server.hostName) dns[server.hostName] = serverIps dns["san.com"] = serverIps dns["nonsan.com"] = serverIps dns["www.wildcard.com"] = serverIps dns["differentdns.com"] = listOf() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(rootCa.certificate) - .build() - client = clientTestRule.newClientBuilder() - .fastFallback(false) // Avoid data races. - .dns(dns) - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .build() - val serverHandshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate(certificate) - .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(rootCa.certificate) + .build() + client = + clientTestRule.newClientBuilder() + .fastFallback(false) // Avoid data races. + .dns(dns) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .build() + val serverHandshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate(certificate) + .build() server.useHttps(serverHandshakeCertificates.sslSocketFactory()) url = server.url("/robots.txt") } @@ -134,12 +139,15 @@ class ConnectionCoalescingTest { server.enqueue(MockResponse()) server.enqueue(MockResponse()) val connection = AtomicReference() - client = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain? -> - connection.set(chain!!.connection()) - chain.proceed(chain.request()) - }) - .build() + client = + client.newBuilder() + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain? -> + connection.set(chain!!.connection()) + chain.proceed(chain.request()) + }, + ) + .build() dns["san.com"] = Dns.SYSTEM.lookup(server.hostName).subList(0, 1) assert200Http2Response(execute(url), server.hostName) @@ -170,81 +178,104 @@ class ConnectionCoalescingTest { val latch2 = CountDownLatch(1) val latch3 = CountDownLatch(1) val latch4 = CountDownLatch(1) - val listener1: EventListener = object : EventListener() { - override fun connectStart( - call: Call, inetSocketAddress: InetSocketAddress, - proxy: Proxy - ) { - try { - // Wait for request2 to guarantee we make 2 separate connections to the server. - latch1.await() - } catch (e: InterruptedException) { - throw AssertionError(e) + val listener1: EventListener = + object : EventListener() { + override fun connectStart( + call: Call, + inetSocketAddress: InetSocketAddress, + proxy: Proxy, + ) { + try { + // Wait for request2 to guarantee we make 2 separate connections to the server. + latch1.await() + } catch (e: InterruptedException) { + throw AssertionError(e) + } } - } - override fun connectionAcquired(call: Call, connection: Connection) { - // We have the connection and it's in the pool. Let request2 proceed to make a connection. - latch2.countDown() - } - } - val request2Listener: EventListener = object : EventListener() { - override fun connectStart( - call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, - ) { - // Let request1 proceed to make a connection. - latch1.countDown() - try { - // Wait until request1 makes the connection and puts it in the connection pool. - latch2.await() - } catch (e: InterruptedException) { - throw AssertionError(e) + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + // We have the connection and it's in the pool. Let request2 proceed to make a connection. + latch2.countDown() } } + val request2Listener: EventListener = + object : EventListener() { + override fun connectStart( + call: Call, + inetSocketAddress: InetSocketAddress, + proxy: Proxy, + ) { + // Let request1 proceed to make a connection. + latch1.countDown() + try { + // Wait until request1 makes the connection and puts it in the connection pool. + latch2.await() + } catch (e: InterruptedException) { + throw AssertionError(e) + } + } - override fun connectionAcquired(call: Call, connection: Connection) { - // We obtained the coalesced connection. Let request1 violently destroy it. - latch3.countDown() - try { - latch4.await() - } catch (e: InterruptedException) { - throw AssertionError(e) + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + // We obtained the coalesced connection. Let request1 violently destroy it. + latch3.countDown() + try { + latch4.await() + } catch (e: InterruptedException) { + throw AssertionError(e) + } } } - } // Get a reference to the connection so we can violently destroy it. val connection = AtomicReference() - val client1 = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain? -> - connection.set(chain!!.connection()) - chain.proceed(chain.request()) - }) - .eventListenerFactory(clientTestRule.wrap(listener1)) - .build() + val client1 = + client.newBuilder() + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain? -> + connection.set(chain!!.connection()) + chain.proceed(chain.request()) + }, + ) + .eventListenerFactory(clientTestRule.wrap(listener1)) + .build() val request = Request.Builder().url(sanUrl).build() val call1 = client1.newCall(request) - call1.enqueue(object : Callback { - @Throws(IOException::class) - override fun onResponse(call: Call, response: Response) { - try { - // Wait until request2 acquires the connection before we destroy it violently. - latch3.await() - } catch (e: InterruptedException) { - throw AssertionError(e) + call1.enqueue( + object : Callback { + @Throws(IOException::class) + override fun onResponse( + call: Call, + response: Response, + ) { + try { + // Wait until request2 acquires the connection before we destroy it violently. + latch3.await() + } catch (e: InterruptedException) { + throw AssertionError(e) + } + assert200Http2Response(response, "san.com") + connection.get()!!.socket().close() + latch4.countDown() } - assert200Http2Response(response, "san.com") - connection.get()!!.socket().close() - latch4.countDown() - } - override fun onFailure(call: Call, e: IOException) { - fail("") - } - }) - val client2 = client.newBuilder() - .eventListenerFactory(clientTestRule.wrap(request2Listener)) - .build() + override fun onFailure( + call: Call, + e: IOException, + ) { + fail("") + } + }, + ) + val client2 = + client.newBuilder() + .eventListenerFactory(clientTestRule.wrap(request2Listener)) + .build() val call2 = client2.newCall(request) val response = call2.execute() assert200Http2Response(response, "san.com") @@ -267,12 +298,12 @@ class ConnectionCoalescingTest { MockResponse.Builder() .code(301) .addHeader("Location", url.newBuilder().host("differentdns.com").build()) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("unexpected call") - .build() + .build(), ) assertFailsWith { val response = execute(url) @@ -298,7 +329,7 @@ class ConnectionCoalescingTest { MockResponse.Builder() .code(301) .addHeader("Location", url.newBuilder().host("nonsan.com").build()) - .build() + .build(), ) server.enqueue(MockResponse()) assertFailsWith { @@ -310,9 +341,10 @@ class ConnectionCoalescingTest { /** Can still coalesce when pinning is used if pins match. */ @Test fun coalescesWhenCertificatePinsMatch() { - val pinner = CertificatePinner.Builder() - .add("san.com", pin(certificate.certificate)) - .build() + val pinner = + CertificatePinner.Builder() + .add("san.com", pin(certificate.certificate)) + .build() client = client.newBuilder().certificatePinner(pinner).build() server.enqueue(MockResponse()) server.enqueue(MockResponse()) @@ -325,9 +357,10 @@ class ConnectionCoalescingTest { /** Certificate pinning used and not a match will avoid coalescing and try to connect. */ @Test fun skipsWhenCertificatePinningFails() { - val pinner = CertificatePinner.Builder() - .add("san.com", "sha1/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") - .build() + val pinner = + CertificatePinner.Builder() + .add("san.com", "sha1/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") + .build() client = client.newBuilder().certificatePinner(pinner).build() server.enqueue(MockResponse()) assert200Http2Response(execute(url), server.hostName) @@ -339,15 +372,16 @@ class ConnectionCoalescingTest { @Test fun skipsOnRedirectWhenCertificatePinningFails() { - val pinner = CertificatePinner.Builder() - .add("san.com", "sha1/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") - .build() + val pinner = + CertificatePinner.Builder() + .add("san.com", "sha1/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") + .build() client = client.newBuilder().certificatePinner(pinner).build() server.enqueue( MockResponse.Builder() .code(301) .addHeader("Location", url.newBuilder().host("san.com").build()) - .build() + .build(), ) server.enqueue(MockResponse()) assertFailsWith { @@ -379,7 +413,7 @@ class ConnectionCoalescingTest { MockResponse.Builder() .code(301) .addHeader("Location", url.newBuilder().host("san.com").build()) - .build() + .build(), ) server.enqueue(MockResponse()) assert200Http2Response(execute(url), "san.com") @@ -399,22 +433,27 @@ class ConnectionCoalescingTest { server.enqueue(MockResponse()) server.enqueue(MockResponse()) val connectCount = AtomicInteger() - val listener: EventListener = object : EventListener() { - override fun connectStart( - call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy - ) { - connectCount.getAndIncrement() + val listener: EventListener = + object : EventListener() { + override fun connectStart( + call: Call, + inetSocketAddress: InetSocketAddress, + proxy: Proxy, + ) { + connectCount.getAndIncrement() + } } - } - client = client.newBuilder() - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + client = + client.newBuilder() + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() assert200Http2Response(execute(url), server.hostName) val sanUrl = url.newBuilder().host("san.com").build() - dns["san.com"] = Arrays.asList( - InetAddress.getByAddress("san.com", byteArrayOf(0, 0, 0, 0)), - serverIps[0] - ) + dns["san.com"] = + Arrays.asList( + InetAddress.getByAddress("san.com", byteArrayOf(0, 0, 0, 0)), + serverIps[0], + ) assert200Http2Response(execute(sanUrl), "san.com") assertThat(client.connectionPool.connectionCount()).isEqualTo(1) assertThat(connectCount.get()).isEqualTo(1) @@ -434,13 +473,16 @@ class ConnectionCoalescingTest { /** Network interceptors check for changes to target. */ @Test fun worksWithNetworkInterceptors() { - client = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain? -> - chain!!.proceed( - chain.request() + client = + client.newBuilder() + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain? -> + chain!!.proceed( + chain.request(), + ) + }, ) - }) - .build() + .build() server.enqueue(MockResponse()) server.enqueue(MockResponse()) assert200Http2Response(execute(url), server.hostName) @@ -454,27 +496,28 @@ class ConnectionCoalescingTest { server.enqueue( MockResponse.Builder() .body("seed connection") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(421) .body("misdirected!") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("after misdirect") - .build() + .build(), ) // Seed the connection pool. assert200Http2Response(execute(url), server.hostName) // Use the coalesced connection which should retry on a fresh connection. - val sanUrl = url.newBuilder() - .host("san.com") - .build() + val sanUrl = + url.newBuilder() + .host("san.com") + .build() execute(sanUrl).use { response -> assertThat(response.code).isEqualTo(200) assertThat(response.priorResponse!!.code).isEqualTo(421) @@ -492,20 +535,28 @@ class ConnectionCoalescingTest { */ @Test fun redirectWithDevSetup() { - val trustManager: X509TrustManager = object : X509TrustManager { - override fun checkClientTrusted(x509Certificates: Array, s: String) { - } + val trustManager: X509TrustManager = + object : X509TrustManager { + override fun checkClientTrusted( + x509Certificates: Array, + s: String, + ) { + } - override fun checkServerTrusted(x509Certificates: Array, s: String) { - } + override fun checkServerTrusted( + x509Certificates: Array, + s: String, + ) { + } - override fun getAcceptedIssuers(): Array { - return arrayOf() + override fun getAcceptedIssuers(): Array { + return arrayOf() + } } - } - client = client.newBuilder() - .sslSocketFactory(client.sslSocketFactory, trustManager) - .build() + client = + client.newBuilder() + .sslSocketFactory(client.sslSocketFactory, trustManager) + .build() server.enqueue(MockResponse()) server.enqueue(MockResponse()) assert200Http2Response(execute(url), server.hostName) @@ -516,7 +567,10 @@ class ConnectionCoalescingTest { private fun execute(url: HttpUrl) = client.newCall(Request(url = url)).execute() - private fun assert200Http2Response(response: Response, expectedHost: String) { + private fun assert200Http2Response( + response: Response, + expectedHost: String, + ) { assertThat(response.code).isEqualTo(200) assertThat(response.request.url.host).isEqualTo(expectedHost) assertThat(response.protocol).isEqualTo(Protocol.HTTP_2) diff --git a/okhttp/src/test/java/okhttp3/ConnectionListenerTest.kt b/okhttp/src/test/java/okhttp3/ConnectionListenerTest.kt index e4ecd1764f4a..a0bb42b7c635 100644 --- a/okhttp/src/test/java/okhttp3/ConnectionListenerTest.kt +++ b/okhttp/src/test/java/okhttp3/ConnectionListenerTest.kt @@ -20,7 +20,6 @@ import assertk.assertions.containsExactly import assertk.assertions.hasMessage import assertk.assertions.isEqualTo import assertk.assertions.isIn -import assertk.fail import java.io.IOException import java.net.InetSocketAddress import java.net.UnknownHostException @@ -60,10 +59,11 @@ open class ConnectionListenerTest { open val fastFallback: Boolean get() = true - private var client: OkHttpClient = clientTestRule.newClientBuilder() - .connectionPool(ConnectionPool(connectionListener = listener)) - .fastFallback(fastFallback) - .build() + private var client: OkHttpClient = + clientTestRule.newClientBuilder() + .connectionPool(ConnectionPool(connectionListener = listener)) + .fastFallback(fastFallback) + .build() @BeforeEach fun setUp(server: MockWebServer?) { @@ -78,9 +78,12 @@ open class ConnectionListenerTest { @ValueSource(booleans = [true, false]) fun successfulCallEventSequence() { server!!.enqueue(MockResponse(body = "abc")) - val call = client.newCall(Request.Builder() - .url(server!!.url("/")) - .build()) + val call = + client.newCall( + Request.Builder() + .url(server!!.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isEqualTo("abc") @@ -89,22 +92,27 @@ open class ConnectionListenerTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @Test fun failedCallEventSequence() { - server!!.enqueue(MockResponse.Builder() - .headersDelay(2, TimeUnit.SECONDS) - .build() + server!!.enqueue( + MockResponse.Builder() + .headersDelay(2, TimeUnit.SECONDS) + .build(), ) - client = client.newBuilder() - .readTimeout(Duration.ofMillis(250)) - .build() - val call = client.newCall(Request.Builder() - .url(server!!.url("/")) - .build()) + client = + client.newBuilder() + .readTimeout(Duration.ofMillis(250)) + .build() + val call = + client.newCall( + Request.Builder() + .url(server!!.url("/")) + .build(), + ) assertFailsWith { call.execute() }.also { expected -> @@ -122,9 +130,12 @@ open class ConnectionListenerTest { @Throws(IOException::class) private fun assertSuccessfulEventOrder() { - val call = client.newCall(Request.Builder() - .url(server!!.url("/")) - .build()) + val call = + client.newCall( + Request.Builder() + .url(server!!.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.string() @@ -133,7 +144,7 @@ open class ConnectionListenerTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @@ -157,7 +168,7 @@ open class ConnectionListenerTest { "ConnectionAcquired", "ConnectionReleased", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @@ -173,20 +184,26 @@ open class ConnectionListenerTest { @Test @Throws(IOException::class) fun multipleDnsLookupsForSingleCall() { - server!!.enqueue(MockResponse( - code = 301, - headers = headersOf("Location", "http://www.fakeurl:" + server!!.port) - )) + server!!.enqueue( + MockResponse( + code = 301, + headers = headersOf("Location", "http://www.fakeurl:" + server!!.port), + ), + ) server!!.enqueue(MockResponse()) val dns = FakeDns() dns["fakeurl"] = client.dns.lookup(server!!.hostName) dns["www.fakeurl"] = client.dns.lookup(server!!.hostName) - client = client.newBuilder() - .dns(dns) - .build() - val call = client.newCall(Request.Builder() - .url("http://fakeurl:" + server!!.port) - .build()) + client = + client.newBuilder() + .dns(dns) + .build() + val call = + client.newCall( + Request.Builder() + .url("http://fakeurl:" + server!!.port) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -200,9 +217,12 @@ open class ConnectionListenerTest { @Throws(IOException::class) fun successfulConnect() { server!!.enqueue(MockResponse()) - val call = client.newCall(Request.Builder() - .url(server!!.url("/")) - .build()) + val call = + client.newCall( + Request.Builder() + .url(server!!.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -217,9 +237,12 @@ open class ConnectionListenerTest { fun failedConnect() { enableTls() server!!.enqueue(MockResponse(socketPolicy = FailHandshake)) - val call = client.newCall(Request.Builder() - .url(server!!.url("/")) - .build()) + val call = + client.newCall( + Request.Builder() + .url(server!!.url("/")) + .build(), + ) assertFailsWith { call.execute() } @@ -240,12 +263,16 @@ open class ConnectionListenerTest { enableTls() server!!.enqueue(MockResponse(socketPolicy = FailHandshake)) server!!.enqueue(MockResponse()) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() - val call = client.newCall(Request.Builder() - .url(server!!.url("/")) - .build()) + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() + val call = + client.newCall( + Request.Builder() + .url(server!!.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -255,7 +282,7 @@ open class ConnectionListenerTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @@ -264,12 +291,16 @@ open class ConnectionListenerTest { fun successfulHttpProxyConnect() { server!!.enqueue(MockResponse()) val proxy = server!!.toProxyAddress() - client = client.newBuilder() - .proxy(proxy) - .build() - val call = client.newCall(Request.Builder() - .url("http://www.fakeurl") - .build()) + client = + client.newBuilder() + .proxy(proxy) + .build() + val call = + client.newCall( + Request.Builder() + .url("http://www.fakeurl") + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -277,17 +308,20 @@ open class ConnectionListenerTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased") + "ConnectionReleased", + ) val event = listener.removeUpToEvent(ConnectionEvent.ConnectEnd::class.java) assertThat(event.connection.route().proxy).isEqualTo(proxy) } private fun enableTls() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() server!!.useHttps(handshakeCertificates.sslSocketFactory()) } } @@ -295,6 +329,6 @@ open class ConnectionListenerTest { @Flaky // STDOUT logging enabled for test @Timeout(30) @Tag("Slow") -class ConnectionListenerLegacyTest: ConnectionListenerTest() { +class ConnectionListenerLegacyTest : ConnectionListenerTest() { override val fastFallback get() = false } diff --git a/okhttp/src/test/java/okhttp3/ConnectionReuseTest.kt b/okhttp/src/test/java/okhttp3/ConnectionReuseTest.kt index c27615f6d684..eb03a60f58ea 100644 --- a/okhttp/src/test/java/okhttp3/ConnectionReuseTest.kt +++ b/okhttp/src/test/java/okhttp3/ConnectionReuseTest.kt @@ -17,11 +17,9 @@ package okhttp3 import assertk.assertThat import assertk.assertions.isEqualTo -import assertk.assertions.isIn import java.io.IOException import java.util.concurrent.TimeUnit import javax.net.ssl.SSLException -import kotlin.math.exp import kotlin.test.assertFailsWith import mockwebserver3.MockResponse import mockwebserver3.MockWebServer @@ -71,10 +69,11 @@ class ConnectionReuseTest { fun connectionsAreReusedForPosts() { server.enqueue(MockResponse(body = "a")) server.enqueue(MockResponse(body = "b")) - val request = Request( - url = server.url("/"), - body = "request body".toRequestBody("text/plain".toMediaType()), - ) + val request = + Request( + url = server.url("/"), + body = "request body".toRequestBody("text/plain".toMediaType()), + ) assertConnectionReused(request, request) } @@ -91,10 +90,11 @@ class ConnectionReuseTest { fun connectionsAreNotReusedWithRequestConnectionClose() { server.enqueue(MockResponse(body = "a")) server.enqueue(MockResponse(body = "b")) - val requestA = Request.Builder() - .url(server.url("/")) - .header("Connection", "close") - .build() + val requestA = + Request.Builder() + .url(server.url("/")) + .header("Connection", "close") + .build() val requestB = Request(server.url("/")) assertConnectionNotReused(requestA, requestB) } @@ -105,7 +105,7 @@ class ConnectionReuseTest { MockResponse( headers = headersOf("Connection", "close"), body = "a", - ) + ), ) server.enqueue(MockResponse(body = "b")) val requestA = Request(server.url("/")) @@ -120,7 +120,7 @@ class ConnectionReuseTest { .body("a") .clearHeaders() .socketPolicy(DisconnectAtEnd) - .build() + .build(), ) server.enqueue(MockResponse(body = "b")) val request = Request(server.url("/")) @@ -129,9 +129,10 @@ class ConnectionReuseTest { @Test fun connectionsAreNotReusedIfPoolIsSizeZero() { - client = client.newBuilder() - .connectionPool(ConnectionPool(0, 5, TimeUnit.SECONDS)) - .build() + client = + client.newBuilder() + .connectionPool(ConnectionPool(0, 5, TimeUnit.SECONDS)) + .build() server.enqueue(MockResponse(body = "a")) server.enqueue(MockResponse(body = "b")) val request = Request(server.url("/")) @@ -140,15 +141,16 @@ class ConnectionReuseTest { @Test fun connectionsReusedWithRedirectEvenIfPoolIsSizeZero() { - client = client.newBuilder() - .connectionPool(ConnectionPool(0, 5, TimeUnit.SECONDS)) - .build() + client = + client.newBuilder() + .connectionPool(ConnectionPool(0, 5, TimeUnit.SECONDS)) + .build() server.enqueue( MockResponse( code = 301, headers = headersOf("Location", "/b"), - body = "a" - ) + body = "a", + ), ) server.enqueue(MockResponse(body = "b")) val request = Request(server.url("/")) @@ -160,16 +162,18 @@ class ConnectionReuseTest { @Test fun connectionsNotReusedWithRedirectIfDiscardingResponseIsSlow() { - client = client.newBuilder() - .connectionPool(ConnectionPool(0, 5, TimeUnit.SECONDS)) - .build() + client = + client.newBuilder() + .connectionPool(ConnectionPool(0, 5, TimeUnit.SECONDS)) + .build() server.enqueue( MockResponse.Builder() .code(301) .addHeader("Location: /b") .bodyDelay(1, TimeUnit.SECONDS) .body("a") - .build()) + .build(), + ) server.enqueue(MockResponse(body = "b")) val request = Request(server.url("/")) val response = client.newCall(request).execute() @@ -211,9 +215,10 @@ class ConnectionReuseTest { fun connectionsAreEvicted() { server.enqueue(MockResponse(body = "a")) server.enqueue(MockResponse(body = "b")) - client = client.newBuilder() - .connectionPool(ConnectionPool(5, 250, TimeUnit.MILLISECONDS)) - .build() + client = + client.newBuilder() + .connectionPool(ConnectionPool(5, 250, TimeUnit.MILLISECONDS)) + .build() val request = Request(server.url("/")) val response1 = client.newCall(request).execute() assertThat(response1.body.string()).isEqualTo("a") @@ -237,11 +242,13 @@ class ConnectionReuseTest { // This client shares a connection pool but has a different SSL socket factory. val handshakeCertificates2 = HandshakeCertificates.Builder().build() - val anotherClient = client.newBuilder() - .sslSocketFactory( - handshakeCertificates2.sslSocketFactory(), handshakeCertificates2.trustManager - ) - .build() + val anotherClient = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates2.sslSocketFactory(), + handshakeCertificates2.trustManager, + ) + .build() // This client fails to connect because the new SSL socket factory refuses. assertFailsWith { @@ -264,9 +271,10 @@ class ConnectionReuseTest { response1.body.close() // This client shares a connection pool but has a different SSL socket factory. - val anotherClient = client.newBuilder() - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + val anotherClient = + client.newBuilder() + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val response2 = anotherClient.newCall(request).execute() response2.body.close() assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) @@ -292,32 +300,35 @@ class ConnectionReuseTest { // Since this test knowingly leaks a connection, avoid using the default shared connection // pool, which should remain clean for subsequent tests. .connectionPool(ConnectionPool()) - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain? -> - val response = chain!!.proceed( - chain.request() - ) - responsesNotClosed.add(response) - response - .newBuilder() - .body("unrelated response body!".toResponseBody(null)) - .build() - }) + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain? -> + val response = + chain!!.proceed( + chain.request(), + ) + responsesNotClosed.add(response) + response + .newBuilder() + .body("unrelated response body!".toResponseBody(null)) + .build() + }, + ) .build() server.enqueue( MockResponse( code = 301, headers = headersOf("Location", "/b"), body = "/a has moved!", - ) + ), ) server.enqueue( - MockResponse(body = "/b is here") + MockResponse(body = "/b is here"), ) val request = Request(server.url("/")) val call = client.newCall(request) call.execute().use { response -> assertThat( - response.body.string() + response.body.string(), ).isEqualTo("unrelated response body!") } assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) @@ -338,14 +349,15 @@ class ConnectionReuseTest { } private fun enableHttpsAndAlpn(vararg protocols: Protocol) { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .protocols(protocols.toList()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .protocols(protocols.toList()) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) server.protocols = client.protocols } diff --git a/okhttp/src/test/java/okhttp3/ConnectionSpecTest.kt b/okhttp/src/test/java/okhttp3/ConnectionSpecTest.kt index c1fb68aa7fd5..2f7e0a676985 100644 --- a/okhttp/src/test/java/okhttp3/ConnectionSpecTest.kt +++ b/okhttp/src/test/java/okhttp3/ConnectionSpecTest.kt @@ -70,11 +70,12 @@ class ConnectionSpecTest { @Test fun tlsBuilder_explicitCiphers() { - val tlsSpec = ConnectionSpec.Builder(true) - .cipherSuites(CipherSuite.TLS_RSA_WITH_RC4_128_MD5) - .tlsVersions(TlsVersion.TLS_1_2) - .supportsTlsExtensions(true) - .build() + val tlsSpec = + ConnectionSpec.Builder(true) + .cipherSuites(CipherSuite.TLS_RSA_WITH_RC4_128_MD5) + .tlsVersions(TlsVersion.TLS_1_2) + .supportsTlsExtensions(true) + .build() assertThat(tlsSpec.cipherSuites!!.toList()) .containsExactly(CipherSuite.TLS_RSA_WITH_RC4_128_MD5) assertThat(tlsSpec.tlsVersions!!.toList()) @@ -84,10 +85,11 @@ class ConnectionSpecTest { @Test fun tlsBuilder_defaultCiphers() { - val tlsSpec = ConnectionSpec.Builder(true) - .tlsVersions(TlsVersion.TLS_1_2) - .supportsTlsExtensions(true) - .build() + val tlsSpec = + ConnectionSpec.Builder(true) + .tlsVersions(TlsVersion.TLS_1_2) + .supportsTlsExtensions(true) + .build() assertThat(tlsSpec.cipherSuites).isNull() assertThat(tlsSpec.tlsVersions!!.toList()) .containsExactly(TlsVersion.TLS_1_2) @@ -98,28 +100,31 @@ class ConnectionSpecTest { fun tls_defaultCiphers_noFallbackIndicator() { platform.assumeNotConscrypt() platform.assumeNotBouncyCastle() - val tlsSpec = ConnectionSpec.Builder(true) - .tlsVersions(TlsVersion.TLS_1_2) - .supportsTlsExtensions(false) - .build() + val tlsSpec = + ConnectionSpec.Builder(true) + .tlsVersions(TlsVersion.TLS_1_2) + .supportsTlsExtensions(false) + .build() val socket = SSLSocketFactory.getDefault().createSocket() as SSLSocket - socket.enabledCipherSuites = arrayOf( - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName - ) - socket.enabledProtocols = arrayOf( - TlsVersion.TLS_1_2.javaName, - TlsVersion.TLS_1_1.javaName - ) + socket.enabledCipherSuites = + arrayOf( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, + ) + socket.enabledProtocols = + arrayOf( + TlsVersion.TLS_1_2.javaName, + TlsVersion.TLS_1_1.javaName, + ) assertThat(tlsSpec.isCompatible(socket)).isTrue() applyConnectionSpec(tlsSpec, socket, isFallback = false) assertThat(socket.enabledProtocols).containsExactly( - TlsVersion.TLS_1_2.javaName + TlsVersion.TLS_1_2.javaName, ) assertThat(socket.enabledCipherSuites.toList()) .containsExactlyInAnyOrder( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, ) } @@ -127,23 +132,26 @@ class ConnectionSpecTest { fun tls_defaultCiphers_withFallbackIndicator() { platform.assumeNotConscrypt() platform.assumeNotBouncyCastle() - val tlsSpec = ConnectionSpec.Builder(true) - .tlsVersions(TlsVersion.TLS_1_2) - .supportsTlsExtensions(false) - .build() + val tlsSpec = + ConnectionSpec.Builder(true) + .tlsVersions(TlsVersion.TLS_1_2) + .supportsTlsExtensions(false) + .build() val socket = SSLSocketFactory.getDefault().createSocket() as SSLSocket - socket.enabledCipherSuites = arrayOf( - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName - ) - socket.enabledProtocols = arrayOf( - TlsVersion.TLS_1_2.javaName, - TlsVersion.TLS_1_1.javaName - ) + socket.enabledCipherSuites = + arrayOf( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, + ) + socket.enabledProtocols = + arrayOf( + TlsVersion.TLS_1_2.javaName, + TlsVersion.TLS_1_1.javaName, + ) assertThat(tlsSpec.isCompatible(socket)).isTrue() applyConnectionSpec(tlsSpec, socket, isFallback = true) assertThat(socket.enabledProtocols).containsExactly( - TlsVersion.TLS_1_2.javaName + TlsVersion.TLS_1_2.javaName, ) val expectedCipherSuites: MutableList = ArrayList() expectedCipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName) @@ -159,24 +167,27 @@ class ConnectionSpecTest { fun tls_explicitCiphers() { platform.assumeNotConscrypt() platform.assumeNotBouncyCastle() - val tlsSpec = ConnectionSpec.Builder(true) - .cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) - .tlsVersions(TlsVersion.TLS_1_2) - .supportsTlsExtensions(false) - .build() + val tlsSpec = + ConnectionSpec.Builder(true) + .cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + .tlsVersions(TlsVersion.TLS_1_2) + .supportsTlsExtensions(false) + .build() val socket = SSLSocketFactory.getDefault().createSocket() as SSLSocket - socket.enabledCipherSuites = arrayOf( - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName - ) - socket.enabledProtocols = arrayOf( - TlsVersion.TLS_1_2.javaName, - TlsVersion.TLS_1_1.javaName - ) + socket.enabledCipherSuites = + arrayOf( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, + ) + socket.enabledProtocols = + arrayOf( + TlsVersion.TLS_1_2.javaName, + TlsVersion.TLS_1_1.javaName, + ) assertThat(tlsSpec.isCompatible(socket)).isTrue() applyConnectionSpec(tlsSpec, socket, isFallback = true) assertThat(socket.enabledProtocols).containsExactly( - TlsVersion.TLS_1_2.javaName + TlsVersion.TLS_1_2.javaName, ) val expectedCipherSuites: MutableList = ArrayList() expectedCipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName) @@ -201,24 +212,28 @@ class ConnectionSpecTest { fun tls_missingRequiredCipher() { platform.assumeNotConscrypt() platform.assumeNotBouncyCastle() - val tlsSpec = ConnectionSpec.Builder(true) - .cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) - .tlsVersions(TlsVersion.TLS_1_2) - .supportsTlsExtensions(false) - .build() + val tlsSpec = + ConnectionSpec.Builder(true) + .cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + .tlsVersions(TlsVersion.TLS_1_2) + .supportsTlsExtensions(false) + .build() val socket = SSLSocketFactory.getDefault().createSocket() as SSLSocket - socket.enabledProtocols = arrayOf( - TlsVersion.TLS_1_2.javaName, - TlsVersion.TLS_1_1.javaName - ) - socket.enabledCipherSuites = arrayOf( - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName - ) + socket.enabledProtocols = + arrayOf( + TlsVersion.TLS_1_2.javaName, + TlsVersion.TLS_1_1.javaName, + ) + socket.enabledCipherSuites = + arrayOf( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, + ) assertThat(tlsSpec.isCompatible(socket)).isTrue() - socket.enabledCipherSuites = arrayOf( - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName - ) + socket.enabledCipherSuites = + arrayOf( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, + ) assertThat(tlsSpec.isCompatible(socket)).isFalse() } @@ -226,15 +241,17 @@ class ConnectionSpecTest { fun allEnabledCipherSuites() { platform.assumeNotConscrypt() platform.assumeNotBouncyCastle() - val tlsSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .allEnabledCipherSuites() - .build() + val tlsSpec = + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .allEnabledCipherSuites() + .build() assertThat(tlsSpec.cipherSuites).isNull() val sslSocket = SSLSocketFactory.getDefault().createSocket() as SSLSocket - sslSocket.enabledCipherSuites = arrayOf( - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName - ) + sslSocket.enabledCipherSuites = + arrayOf( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, + ) applyConnectionSpec(tlsSpec, sslSocket, false) if (platform.isAndroid) { // https://developer.android.com/reference/javax/net/ssl/SSLSocket @@ -246,20 +263,20 @@ class ConnectionSpecTest { CipherSuite.TLS_AES_256_GCM_SHA384.javaName, CipherSuite.TLS_CHACHA20_POLY1305_SHA256.javaName, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, ) } else { assertThat(sslSocket.enabledCipherSuites) .containsExactly( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, ) } } else { assertThat(sslSocket.enabledCipherSuites) .containsExactly( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA.javaName, ) } } @@ -267,24 +284,27 @@ class ConnectionSpecTest { @Test fun allEnabledTlsVersions() { platform.assumeNotConscrypt() - val tlsSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .allEnabledTlsVersions() - .build() + val tlsSpec = + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .allEnabledTlsVersions() + .build() assertThat(tlsSpec.tlsVersions).isNull() val sslSocket = SSLSocketFactory.getDefault().createSocket() as SSLSocket if (majorVersion > 11) { - sslSocket.enabledProtocols = arrayOf( - TlsVersion.SSL_3_0.javaName, - TlsVersion.TLS_1_1.javaName, - TlsVersion.TLS_1_2.javaName, - TlsVersion.TLS_1_3.javaName - ) + sslSocket.enabledProtocols = + arrayOf( + TlsVersion.SSL_3_0.javaName, + TlsVersion.TLS_1_1.javaName, + TlsVersion.TLS_1_2.javaName, + TlsVersion.TLS_1_3.javaName, + ) } else { - sslSocket.enabledProtocols = arrayOf( - TlsVersion.SSL_3_0.javaName, - TlsVersion.TLS_1_1.javaName, - TlsVersion.TLS_1_2.javaName - ) + sslSocket.enabledProtocols = + arrayOf( + TlsVersion.SSL_3_0.javaName, + TlsVersion.TLS_1_1.javaName, + TlsVersion.TLS_1_2.javaName, + ) } applyConnectionSpec(tlsSpec, sslSocket, false) if (isAndroid) { @@ -293,33 +313,39 @@ class ConnectionSpecTest { if (sdkVersion != null && sdkVersion >= 29) { assertThat(sslSocket.enabledProtocols) .containsExactly( - TlsVersion.TLS_1_1.javaName, TlsVersion.TLS_1_2.javaName, - TlsVersion.TLS_1_3.javaName + TlsVersion.TLS_1_1.javaName, + TlsVersion.TLS_1_2.javaName, + TlsVersion.TLS_1_3.javaName, ) } else if (sdkVersion != null && sdkVersion >= 26) { assertThat(sslSocket.enabledProtocols) .containsExactly( - TlsVersion.TLS_1_1.javaName, TlsVersion.TLS_1_2.javaName + TlsVersion.TLS_1_1.javaName, + TlsVersion.TLS_1_2.javaName, ) } else { assertThat(sslSocket.enabledProtocols) .containsExactly( - TlsVersion.SSL_3_0.javaName, TlsVersion.TLS_1_1.javaName, - TlsVersion.TLS_1_2.javaName + TlsVersion.SSL_3_0.javaName, + TlsVersion.TLS_1_1.javaName, + TlsVersion.TLS_1_2.javaName, ) } } else { if (majorVersion > 11) { assertThat(sslSocket.enabledProtocols) .containsExactly( - TlsVersion.SSL_3_0.javaName, TlsVersion.TLS_1_1.javaName, - TlsVersion.TLS_1_2.javaName, TlsVersion.TLS_1_3.javaName + TlsVersion.SSL_3_0.javaName, + TlsVersion.TLS_1_1.javaName, + TlsVersion.TLS_1_2.javaName, + TlsVersion.TLS_1_3.javaName, ) } else { assertThat(sslSocket.enabledProtocols) .containsExactly( - TlsVersion.SSL_3_0.javaName, TlsVersion.TLS_1_1.javaName, - TlsVersion.TLS_1_2.javaName + TlsVersion.SSL_3_0.javaName, + TlsVersion.TLS_1_1.javaName, + TlsVersion.TLS_1_2.javaName, ) } } @@ -329,19 +355,22 @@ class ConnectionSpecTest { fun tls_missingTlsVersion() { platform.assumeNotConscrypt() platform.assumeNotBouncyCastle() - val tlsSpec = ConnectionSpec.Builder(true) - .cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) - .tlsVersions(TlsVersion.TLS_1_2) - .supportsTlsExtensions(false) - .build() + val tlsSpec = + ConnectionSpec.Builder(true) + .cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + .tlsVersions(TlsVersion.TLS_1_2) + .supportsTlsExtensions(false) + .build() val socket = SSLSocketFactory.getDefault().createSocket() as SSLSocket - socket.enabledCipherSuites = arrayOf( - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName - ) - socket.enabledProtocols = arrayOf( - TlsVersion.TLS_1_2.javaName, - TlsVersion.TLS_1_1.javaName - ) + socket.enabledCipherSuites = + arrayOf( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.javaName, + ) + socket.enabledProtocols = + arrayOf( + TlsVersion.TLS_1_2.javaName, + TlsVersion.TLS_1_1.javaName, + ) assertThat(tlsSpec.isCompatible(socket)).isTrue() socket.enabledProtocols = arrayOf(TlsVersion.TLS_1_1.javaName) assertThat(tlsSpec.isCompatible(socket)).isFalse() @@ -349,12 +378,14 @@ class ConnectionSpecTest { @Test fun equalsAndHashCode() { - val allCipherSuites = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .allEnabledCipherSuites() - .build() - val allTlsVersions = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .allEnabledTlsVersions() - .build() + val allCipherSuites = + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .allEnabledCipherSuites() + .build() + val allTlsVersions = + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .allEnabledTlsVersions() + .build() val set: MutableSet = CopyOnWriteArraySet() assertThat(set.add(ConnectionSpec.MODERN_TLS)).isTrue() assertThat(set.add(ConnectionSpec.COMPATIBLE_TLS)).isTrue() @@ -376,25 +407,27 @@ class ConnectionSpecTest { @Test fun allEnabledToString() { - val connectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .allEnabledTlsVersions() - .allEnabledCipherSuites() - .build() + val connectionSpec = + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .allEnabledTlsVersions() + .allEnabledCipherSuites() + .build() assertThat(connectionSpec.toString()).isEqualTo( - "ConnectionSpec(cipherSuites=[all enabled], tlsVersions=[all enabled], " - + "supportsTlsExtensions=true)" + "ConnectionSpec(cipherSuites=[all enabled], tlsVersions=[all enabled], " + + "supportsTlsExtensions=true)", ) } @Test fun simpleToString() { - val connectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .tlsVersions(TlsVersion.TLS_1_2) - .cipherSuites(CipherSuite.TLS_RSA_WITH_RC4_128_MD5) - .build() + val connectionSpec = + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(TlsVersion.TLS_1_2) + .cipherSuites(CipherSuite.TLS_RSA_WITH_RC4_128_MD5) + .build() assertThat(connectionSpec.toString()).isEqualTo( - "ConnectionSpec(cipherSuites=[SSL_RSA_WITH_RC4_128_MD5], tlsVersions=[TLS_1_2], " - + "supportsTlsExtensions=true)" + "ConnectionSpec(cipherSuites=[SSL_RSA_WITH_RC4_128_MD5], tlsVersions=[TLS_1_2], " + + "supportsTlsExtensions=true)", ) } } diff --git a/okhttp/src/test/java/okhttp3/ConscryptTest.kt b/okhttp/src/test/java/okhttp3/ConscryptTest.kt index 35256cd6ca7b..cb55fa83a41b 100644 --- a/okhttp/src/test/java/okhttp3/ConscryptTest.kt +++ b/okhttp/src/test/java/okhttp3/ConscryptTest.kt @@ -32,8 +32,11 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension class ConscryptTest { - @JvmField @RegisterExtension val platform = PlatformRule() - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule() + @JvmField @RegisterExtension + val platform = PlatformRule() + + @JvmField @RegisterExtension + val clientTestRule = OkHttpClientTestRule() private val client = clientTestRule.newClient() diff --git a/okhttp/src/test/java/okhttp3/CookieTest.kt b/okhttp/src/test/java/okhttp3/CookieTest.kt index bc0cb0b72cb5..b35f43f73722 100644 --- a/okhttp/src/test/java/okhttp3/CookieTest.kt +++ b/okhttp/src/test/java/okhttp3/CookieTest.kt @@ -26,14 +26,13 @@ import java.text.ParseException import java.text.SimpleDateFormat import java.util.Arrays import java.util.Date +import kotlin.test.assertFailsWith import okhttp3.Cookie.Companion.parse import okhttp3.Cookie.Companion.parseAll import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.internal.UTC import okhttp3.internal.http.MAX_DATE import okhttp3.internal.parseCookie -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest @@ -286,9 +285,11 @@ class CookieTest { } @Test fun domainMatchesIpv6AddressWithIpv4Suffix() { - val cookie = parse( - "http://[::1:ffff:ffff]/".toHttpUrl(), "a=b; domain=::1:255.255.255.255" - ) + val cookie = + parse( + "http://[::1:ffff:ffff]/".toHttpUrl(), + "a=b; domain=::1:255.255.255.255", + ) assertThat(cookie!!.domain).isEqualTo("::1:ffff:ffff") assertThat(cookie.matches("http://[::1:ffff:ffff]/".toHttpUrl())).isTrue() } @@ -324,7 +325,7 @@ class CookieTest { @Test fun hostOnly() { assertThat(parse(url, "a=b")!!.hostOnly).isTrue() assertThat( - parse(url, "a=b; domain=example.com")!!.hostOnly + parse(url, "a=b; domain=example.com")!!.hostOnly, ).isFalse() } @@ -336,7 +337,8 @@ class CookieTest { } @Test fun defaultPathIsUsedIfPathDoesntHaveLeadingSlash() { - assertThat(parse("http://example.com/foo/bar".toHttpUrl(), "a=b; path=quux")!!.path + assertThat( + parse("http://example.com/foo/bar".toHttpUrl(), "a=b; path=quux")!!.path, ).isEqualTo("/foo") assertThat(parse("http://example.com/foo/bar".toHttpUrl(), "a=b; path=")!!.path) .isEqualTo("/foo") @@ -382,12 +384,14 @@ class CookieTest { @Test fun lastExpiresAtWins() { assertThat( parseCookie( - 0L, url, "a=b; " - + "Expires=Thu, 01 Jan 1970 00:00:02 GMT; " - + "Expires=Thu, 01 Jan 1970 00:00:04 GMT; " - + "Expires=Thu, 01 Jan 1970 00:00:01 GMT; " - + "Expires=Thu, 01 Jan 1970 00:00:03 GMT" - )!!.expiresAt + 0L, + url, + "a=b; " + + "Expires=Thu, 01 Jan 1970 00:00:02 GMT; " + + "Expires=Thu, 01 Jan 1970 00:00:04 GMT; " + + "Expires=Thu, 01 Jan 1970 00:00:01 GMT; " + + "Expires=Thu, 01 Jan 1970 00:00:03 GMT", + )!!.expiresAt, ).isEqualTo(3000L) } @@ -399,10 +403,11 @@ class CookieTest { } @Test fun parseAll() { - val headers = Headers.Builder() - .add("Set-Cookie: a=b") - .add("Set-Cookie: c=d") - .build() + val headers = + Headers.Builder() + .add("Set-Cookie: a=b") + .add("Set-Cookie: c=d") + .build() val cookies = parseAll(url, headers) assertThat(cookies.size).isEqualTo(2) assertThat(cookies[0].toString()).isEqualTo("a=b; path=/") @@ -410,11 +415,12 @@ class CookieTest { } @Test fun builder() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .domain("example.com") - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .domain("example.com") + .build() assertThat(cookie.name).isEqualTo("a") assertThat(cookie.value).isEqualTo("b") assertThat(cookie.expiresAt).isEqualTo(MAX_DATE) @@ -428,12 +434,13 @@ class CookieTest { } @Test fun newBuilder() { - val cookie = parseCookie(0L, url, "c=d; Max-Age=1")!!.newBuilder() - .name("a") - .value("b") - .domain("example.com") - .expiresAt(MAX_DATE) - .build() + val cookie = + parseCookie(0L, url, "c=d; Max-Age=1")!!.newBuilder() + .name("a") + .value("b") + .domain("example.com") + .expiresAt(MAX_DATE) + .build() assertThat(cookie.name).isEqualTo("a") assertThat(cookie.value).isEqualTo("b") assertThat(cookie.expiresAt).isEqualTo(MAX_DATE) @@ -459,32 +466,35 @@ class CookieTest { } @Test fun builderClampsMaxDate() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .hostOnlyDomain("example.com") - .expiresAt(Long.MAX_VALUE) - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .hostOnlyDomain("example.com") + .expiresAt(Long.MAX_VALUE) + .build() assertThat(cookie.toString()).isEqualTo("a=b; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/") } @Test fun builderExpiresAt() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .hostOnlyDomain("example.com") - .expiresAt(date("1970-01-01T00:00:01.000+0000").time) - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .hostOnlyDomain("example.com") + .expiresAt(date("1970-01-01T00:00:01.000+0000").time) + .build() assertThat(cookie.toString()).isEqualTo("a=b; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/") } @Test fun builderClampsMinDate() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .hostOnlyDomain("example.com") - .expiresAt(date("1970-01-01T00:00:00.000+0000").time) - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .hostOnlyDomain("example.com") + .expiresAt(date("1970-01-01T00:00:00.000+0000").time) + .build() assertThat(cookie.toString()).isEqualTo("a=b; max-age=0; path=/") } @@ -495,22 +505,24 @@ class CookieTest { } @Test fun builderDomain() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .hostOnlyDomain("squareup.com") - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .hostOnlyDomain("squareup.com") + .build() assertThat(cookie.domain).isEqualTo("squareup.com") assertThat(cookie.hostOnly).isTrue() } @Test fun builderPath() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .hostOnlyDomain("example.com") - .path("/foo") - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .hostOnlyDomain("example.com") + .path("/foo") + .build() assertThat(cookie.path).isEqualTo("/foo") } @@ -521,31 +533,34 @@ class CookieTest { } @Test fun builderSecure() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .hostOnlyDomain("example.com") - .secure() - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .hostOnlyDomain("example.com") + .secure() + .build() assertThat(cookie.secure).isTrue() } @Test fun builderHttpOnly() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .hostOnlyDomain("example.com") - .httpOnly() - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .hostOnlyDomain("example.com") + .httpOnly() + .build() assertThat(cookie.httpOnly).isTrue() } @Test fun builderIpv6() { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .domain("0:0:0:0:0:0:0:1") - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .domain("0:0:0:0:0:0:0:1") + .build() assertThat(cookie.domain).isEqualTo("::1") } @@ -567,10 +582,11 @@ class CookieTest { } @Test fun builderSameSiteTrimmed() { - var cookieBuilder = Cookie.Builder() - .name("a") - .value("b") - .domain("example.com") + var cookieBuilder = + Cookie.Builder() + .name("a") + .value("b") + .domain("example.com") assertThrows { cookieBuilder.sameSite(" a").build() @@ -588,44 +604,47 @@ class CookieTest { @ParameterizedTest(name = "{displayName}({arguments})") @ValueSource(strings = ["Lax", "Strict", "UnrecognizedButValid"]) fun builderSameSite(sameSite: String) { - val cookie = Cookie.Builder() - .name("a") - .value("b") - .domain("example.com") - .sameSite(sameSite) - .build() + val cookie = + Cookie.Builder() + .name("a") + .value("b") + .domain("example.com") + .sameSite(sameSite) + .build() assertThat(cookie.sameSite).isEqualTo(sameSite) } - /** Note that we permit building a cookie that doesn’t follow the rules. */ - @Test fun builderSameSiteNoneDoesNotRequireSecure() { - val cookieBuilder = Cookie.Builder() - .name("a") - .value("b") - .domain("example.com") - .sameSite("None") + /** Note that we permit building a cookie that doesn’t follow the rules. */ + @Test fun builderSameSiteNoneDoesNotRequireSecure() { + val cookieBuilder = + Cookie.Builder() + .name("a") + .value("b") + .domain("example.com") + .sameSite("None") val cookie = cookieBuilder.build() assertThat(cookie.sameSite).isEqualTo("None") } @Test fun equalsAndHashCode() { - val cookieStrings = Arrays.asList( - "a=b; Path=/c; Domain=example.com; Max-Age=5; Secure; HttpOnly", - "a= ; Path=/c; Domain=example.com; Max-Age=5; Secure; HttpOnly", - "a=b; Domain=example.com; Max-Age=5; Secure; HttpOnly", - "a=b; Path=/c; Max-Age=5; Secure; HttpOnly", - "a=b; Path=/c; Domain=example.com; Secure; HttpOnly", - "a=b; Path=/c; Domain=example.com; Max-Age=5; HttpOnly", - "a=b; Path=/c; Domain=example.com; Max-Age=5; Secure; ", - "a=b; Path=/c; Domain=example.com; Max-Age=5; Secure; HttpOnly; SameSite=Lax", - "a= ; Path=/c; Domain=example.com; Max-Age=5; Secure; HttpOnly; SameSite=Lax", - "a=b; Domain=example.com; Max-Age=5; Secure; HttpOnly; SameSite=Lax", - "a=b; Path=/c; Max-Age=5; Secure; HttpOnly; SameSite=Lax", - "a=b; Path=/c; Domain=example.com; Secure; HttpOnly; SameSite=Lax", - "a=b; Path=/c; Domain=example.com; Max-Age=5; HttpOnly; SameSite=Lax", - "a=b; Path=/c; Domain=example.com; Max-Age=5; Secure; ; SameSite=Lax", - ) + val cookieStrings = + Arrays.asList( + "a=b; Path=/c; Domain=example.com; Max-Age=5; Secure; HttpOnly", + "a= ; Path=/c; Domain=example.com; Max-Age=5; Secure; HttpOnly", + "a=b; Domain=example.com; Max-Age=5; Secure; HttpOnly", + "a=b; Path=/c; Max-Age=5; Secure; HttpOnly", + "a=b; Path=/c; Domain=example.com; Secure; HttpOnly", + "a=b; Path=/c; Domain=example.com; Max-Age=5; HttpOnly", + "a=b; Path=/c; Domain=example.com; Max-Age=5; Secure; ", + "a=b; Path=/c; Domain=example.com; Max-Age=5; Secure; HttpOnly; SameSite=Lax", + "a= ; Path=/c; Domain=example.com; Max-Age=5; Secure; HttpOnly; SameSite=Lax", + "a=b; Domain=example.com; Max-Age=5; Secure; HttpOnly; SameSite=Lax", + "a=b; Path=/c; Max-Age=5; Secure; HttpOnly; SameSite=Lax", + "a=b; Path=/c; Domain=example.com; Secure; HttpOnly; SameSite=Lax", + "a=b; Path=/c; Domain=example.com; Max-Age=5; HttpOnly; SameSite=Lax", + "a=b; Path=/c; Domain=example.com; Max-Age=5; Secure; ; SameSite=Lax", + ) for (stringA in cookieStrings) { val cookieA = parseCookie(0, url, stringA!!) for (stringB in cookieStrings) { @@ -642,7 +661,8 @@ class CookieTest { } } - @Throws(ParseException::class) private fun date(s: String): Date { + @Throws(ParseException::class) + private fun date(s: String): Date { val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") format.timeZone = UTC return format.parse(s) diff --git a/okhttp/src/test/java/okhttp3/CookiesTest.kt b/okhttp/src/test/java/okhttp3/CookiesTest.kt index f90eab55c486..2a67a45ad3da 100644 --- a/okhttp/src/test/java/okhttp3/CookiesTest.kt +++ b/okhttp/src/test/java/okhttp3/CookiesTest.kt @@ -57,20 +57,21 @@ class CookiesTest { @Test fun testNetscapeResponse() { val cookieManager = CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + client.newBuilder() + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() val urlWithIpAddress = urlWithIpAddress(server, "/path/foo") server.enqueue( MockResponse.Builder() .addHeader( - "Set-Cookie: a=android; " - + "expires=Fri, 31-Dec-9999 23:59:59 GMT; " - + "path=/path; " - + "domain=${urlWithIpAddress.host}; " - + "secure" + "Set-Cookie: a=android; " + + "expires=Fri, 31-Dec-9999 23:59:59 GMT; " + + "path=/path; " + + "domain=${urlWithIpAddress.host}; " + + "secure", ) - .build() + .build(), ) get(urlWithIpAddress) val cookies = cookieManager.cookieStore.cookies @@ -90,22 +91,23 @@ class CookiesTest { @Test fun testRfc2109Response() { val cookieManager = CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + client.newBuilder() + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() val urlWithIpAddress = urlWithIpAddress(server, "/path/foo") server.enqueue( MockResponse.Builder() .addHeader( - "Set-Cookie: a=android; " - + "Comment=this cookie is delicious; " - + "Domain=${urlWithIpAddress.host}; " - + "Max-Age=60; " - + "Path=/path; " - + "Secure; " - + "Version=1" + "Set-Cookie: a=android; " + + "Comment=this cookie is delicious; " + + "Domain=${urlWithIpAddress.host}; " + + "Max-Age=60; " + + "Path=/path; " + + "Secure; " + + "Version=1", ) - .build() + .build(), ) get(urlWithIpAddress) val cookies = cookieManager.cookieStore.cookies @@ -124,25 +126,26 @@ class CookiesTest { @Test fun testQuotedAttributeValues() { val cookieManager = CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + client.newBuilder() + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() val urlWithIpAddress = urlWithIpAddress(server, "/path/foo") server.enqueue( MockResponse.Builder() .addHeader( - "Set-Cookie: a=\"android\"; " - + "Comment=\"this cookie is delicious\"; " - + "CommentURL=\"http://google.com/\"; " - + "Discard; " - + "Domain=${urlWithIpAddress.host}; " - + "Max-Age=60; " - + "Path=\"/path\"; " - + "Port=\"80,443,${server.port}\"; " - + "Secure; " - + "Version=\"1\"" + "Set-Cookie: a=\"android\"; " + + "Comment=\"this cookie is delicious\"; " + + "CommentURL=\"http://google.com/\"; " + + "Discard; " + + "Domain=${urlWithIpAddress.host}; " + + "Max-Age=60; " + + "Path=\"/path\"; " + + "Port=\"80,443,${server.port}\"; " + + "Secure; " + + "Version=\"1\"", ) - .build() + .build(), ) get(urlWithIpAddress) val cookies = cookieManager.cookieStore.cookies @@ -169,9 +172,10 @@ class CookiesTest { cookieB.domain = serverUrl.host cookieB.path = "/" cookieManager.cookieStore.add(serverUrl.toUri(), cookieB) - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + client.newBuilder() + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() get(serverUrl) val request = server.takeRequest() assertThat(request.headers["Cookie"]).isEqualTo("a=android; b=banana") @@ -181,21 +185,30 @@ class CookiesTest { fun cookieHandlerLikeAndroid() { server.enqueue(MockResponse()) val serverUrl = urlWithIpAddress(server, "/") - val androidCookieHandler: CookieHandler = object : CookieHandler() { - override fun get(uri: URI, map: Map>) = mapOf( - "Cookie" to listOf( - "\$Version=\"1\"; " + - "a=\"android\";\$Path=\"/\";\$Domain=\"${serverUrl.host}\"; " + - "b=\"banana\";\$Path=\"/\";\$Domain=\"${serverUrl.host}\"" + val androidCookieHandler: CookieHandler = + object : CookieHandler() { + override fun get( + uri: URI, + map: Map>, + ) = mapOf( + "Cookie" to + listOf( + "\$Version=\"1\"; " + + "a=\"android\";\$Path=\"/\";\$Domain=\"${serverUrl.host}\"; " + + "b=\"banana\";\$Path=\"/\";\$Domain=\"${serverUrl.host}\"", + ), ) - ) - override fun put(uri: URI, map: Map>) { + override fun put( + uri: URI, + map: Map>, + ) { + } } - } - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(androidCookieHandler)) - .build() + client = + client.newBuilder() + .cookieJar(JavaNetCookieJar(androidCookieHandler)) + .build() get(serverUrl) val request = server.takeRequest() assertThat(request.headers["Cookie"]).isEqualTo("a=android; b=banana") @@ -207,13 +220,14 @@ class CookiesTest { MockResponse.Builder() .addHeader("Set-Cookie", "a=android") .addHeader("Set-Cookie", "b=banana") - .build() + .build(), ) server.enqueue(MockResponse()) val cookieManager = CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + client.newBuilder() + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() get(urlWithIpAddress(server, "/")) val request1 = server.takeRequest() assertThat(request1.headers["Cookie"]).isNull() @@ -233,7 +247,7 @@ class CookiesTest { MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .addHeader("Location: $redirectTargetUrl") - .build() + .build(), ) redirectSource.start() val redirectSourceUrl = urlWithIpAddress(redirectSource, "/") @@ -244,9 +258,10 @@ class CookiesTest { val portList = redirectSource.port.toString() cookie.portlist = portList cookieManager.cookieStore.add(redirectSourceUrl.toUri(), cookie) - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(cookieManager)) - .build() + client = + client.newBuilder() + .cookieJar(JavaNetCookieJar(cookieManager)) + .build() get(redirectSourceUrl) val request = redirectSource.takeRequest() assertThat(request.headers["Cookie"]).isEqualTo("c=cookie") @@ -259,14 +274,22 @@ class CookiesTest { @Test fun testCookiesSentIgnoresCase() { - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(object : CookieManager() { - override fun get(uri: URI, requestHeaders: Map>) = mapOf( - "COOKIE" to listOf("Bar=bar"), - "cooKIE2" to listOf("Baz=baz"), + client = + client.newBuilder() + .cookieJar( + JavaNetCookieJar( + object : CookieManager() { + override fun get( + uri: URI, + requestHeaders: Map>, + ) = mapOf( + "COOKIE" to listOf("Bar=bar"), + "cooKIE2" to listOf("Baz=baz"), + ) + }, + ), ) - })) - .build() + .build() server.enqueue(MockResponse()) get(server.url("/")) val request = server.takeRequest() @@ -324,14 +347,22 @@ class CookiesTest { @Test fun testQuoteStripping() { - client = client.newBuilder() - .cookieJar(JavaNetCookieJar(object : CookieManager() { - override fun get(uri: URI, requestHeaders: Map>) = mapOf( - "COOKIE" to listOf("Bar=\""), - "cooKIE2" to listOf("Baz=\"baz\""), + client = + client.newBuilder() + .cookieJar( + JavaNetCookieJar( + object : CookieManager() { + override fun get( + uri: URI, + requestHeaders: Map>, + ) = mapOf( + "COOKIE" to listOf("Bar=\""), + "cooKIE2" to listOf("Baz=\"baz\""), + ) + }, + ), ) - })) - .build() + .build() server.enqueue(MockResponse()) get(server.url("/")) val request = server.takeRequest() @@ -340,7 +371,10 @@ class CookiesTest { assertThat(request.headers["Quux"]).isNull() } - private fun urlWithIpAddress(server: MockWebServer, path: String): HttpUrl { + private fun urlWithIpAddress( + server: MockWebServer, + path: String, + ): HttpUrl { return server.url(path) .newBuilder() .host(InetAddress.getByName(server.hostName).hostAddress) @@ -348,11 +382,12 @@ class CookiesTest { } private operator fun get(url: HttpUrl) { - val call = client.newCall( - Request.Builder() - .url(url) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(url) + .build(), + ) val response = call.execute() response.body.close() } diff --git a/okhttp/src/test/java/okhttp3/CorrettoTest.kt b/okhttp/src/test/java/okhttp3/CorrettoTest.kt index e490011828de..623aa03cc8b2 100644 --- a/okhttp/src/test/java/okhttp3/CorrettoTest.kt +++ b/okhttp/src/test/java/okhttp3/CorrettoTest.kt @@ -26,8 +26,11 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension class CorrettoTest { - @JvmField @RegisterExtension val platform = PlatformRule() - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule() + @JvmField @RegisterExtension + val platform = PlatformRule() + + @JvmField @RegisterExtension + val clientTestRule = OkHttpClientTestRule() private val client = clientTestRule.newClient() diff --git a/okhttp/src/test/java/okhttp3/DispatcherCleanupTest.kt b/okhttp/src/test/java/okhttp3/DispatcherCleanupTest.kt index a4ea550dc92e..5f15da68abf3 100644 --- a/okhttp/src/test/java/okhttp3/DispatcherCleanupTest.kt +++ b/okhttp/src/test/java/okhttp3/DispatcherCleanupTest.kt @@ -23,12 +23,20 @@ class DispatcherCleanupTest { @Test fun testFinish(server: MockWebServer) { val okhttp = OkHttpClient() - val callback = object : Callback { - override fun onFailure(call: Call, e: IOException) {} - override fun onResponse(call: Call, response: Response) { - response.close() + val callback = + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) {} + + override fun onResponse( + call: Call, + response: Response, + ) { + response.close() + } } - } repeat(10_000) { okhttp.newCall(Request.Builder().url(server.url("/")).build()).enqueue(callback) } diff --git a/okhttp/src/test/java/okhttp3/DispatcherTest.kt b/okhttp/src/test/java/okhttp3/DispatcherTest.kt index 626edc9c3947..e59d0a8118e8 100644 --- a/okhttp/src/test/java/okhttp3/DispatcherTest.kt +++ b/okhttp/src/test/java/okhttp3/DispatcherTest.kt @@ -13,7 +13,6 @@ import java.net.UnknownHostException import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean -import assertk.fail import kotlin.test.assertFailsWith import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Tag @@ -26,15 +25,17 @@ class DispatcherTest { val clientTestRule = OkHttpClientTestRule() private val executor = RecordingExecutor(this) val callback = RecordingCallback() - val webSocketListener = object : WebSocketListener() { - } + val webSocketListener = + object : WebSocketListener() { + } val dispatcher = Dispatcher(executor) val listener = RecordingEventListener() - var client = clientTestRule.newClientBuilder() - .dns { throw UnknownHostException() } - .dispatcher(dispatcher) - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + var client = + clientTestRule.newClientBuilder() + .dns { throw UnknownHostException() } + .dispatcher(dispatcher) + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() @BeforeEach fun setUp() { @@ -197,17 +198,20 @@ class DispatcherTest { fun synchronousCallAccessors() { val ready = CountDownLatch(2) val waiting = CountDownLatch(1) - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain? -> - try { - ready.countDown() - waiting.await() - } catch (e: InterruptedException) { - throw AssertionError() - } - throw IOException() - }) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain? -> + try { + ready.countDown() + waiting.await() + } catch (e: InterruptedException) { + throw AssertionError() + } + throw IOException() + }, + ) + .build() val a1 = client.newCall(newRequest("http://a/1")) val a2 = client.newCall(newRequest("http://a/2")) val a3 = client.newCall(newRequest("http://a/3")) @@ -260,17 +264,20 @@ class DispatcherTest { assertThat(idle.get()).isFalse() val ready = CountDownLatch(1) val proceed = CountDownLatch(1) - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - ready.countDown() - try { - proceed.await(5, TimeUnit.SECONDS) - } catch (e: InterruptedException) { - throw RuntimeException(e) - } - chain.proceed(chain.request()) - }) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + ready.countDown() + try { + proceed.await(5, TimeUnit.SECONDS) + } catch (e: InterruptedException) { + throw RuntimeException(e) + } + chain.proceed(chain.request()) + }, + ) + .build() val t1 = makeSynchronousCall(client.newCall(newRequest("http://a/3"))) ready.await(5, TimeUnit.SECONDS) executor.finishJob("http://a/2") @@ -333,13 +340,14 @@ class DispatcherTest { } private fun makeSynchronousCall(call: Call): Thread { - val thread = Thread { - try { - call.execute() - throw AssertionError() - } catch (expected: IOException) { + val thread = + Thread { + try { + call.execute() + throw AssertionError() + } catch (expected: IOException) { + } } - } thread.start() return thread } @@ -348,7 +356,10 @@ class DispatcherTest { return Request.Builder().url(url).build() } - private fun newRequest(url: String, tag: String): Request { + private fun newRequest( + url: String, + tag: String, + ): Request { return Request.Builder().url(url).tag(tag).build() } } diff --git a/okhttp/src/test/java/okhttp3/DuplexTest.kt b/okhttp/src/test/java/okhttp3/DuplexTest.kt index eaabb963a2df..4e8185956650 100644 --- a/okhttp/src/test/java/okhttp3/DuplexTest.kt +++ b/okhttp/src/test/java/okhttp3/DuplexTest.kt @@ -29,6 +29,7 @@ import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.TimeUnit +import kotlin.test.assertFailsWith import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import mockwebserver3.internal.duplex.MockStreamHandler @@ -42,8 +43,6 @@ import okhttp3.testing.PlatformRule import okio.BufferedSink import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertTrue -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Tag @@ -62,9 +61,10 @@ class DuplexTest { private lateinit var server: MockWebServer private var listener = RecordingEventListener() private val handshakeCertificates = platform.localhostHandshakeCertificates() - private var client = clientTestRule.newClientBuilder() - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + private var client = + clientTestRule.newClientBuilder() + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() private val executorService = Executors.newScheduledThreadPool(1) @BeforeEach @@ -82,12 +82,13 @@ class DuplexTest { @Test @Throws(IOException::class) fun http1DoesntSupportDuplex() { - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build(), + ) assertFailsWith { call.execute() } @@ -96,27 +97,29 @@ class DuplexTest { @Test fun trueDuplexClientWritesFirst() { enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .receiveRequest("request A\n") - .sendResponse("response B\n") - .receiveRequest("request C\n") - .sendResponse("response D\n") - .receiveRequest("request E\n") - .sendResponse("response F\n") - .exhaustRequest() - .exhaustResponse() + val body = + MockStreamHandler() + .receiveRequest("request A\n") + .sendResponse("response B\n") + .receiveRequest("request C\n") + .sendResponse("response D\n") + .receiveRequest("request E\n") + .sendResponse("response F\n") + .exhaustRequest() + .exhaustResponse() server.enqueue( MockResponse.Builder() .clearHeaders() .streamHandler(body) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build(), + ) call.execute().use { response -> val requestBody = (call.request().body as AsyncRequestBody?)!!.takeSink() requestBody.writeUtf8("request A\n") @@ -141,27 +144,29 @@ class DuplexTest { @Test fun trueDuplexServerWritesFirst() { enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .sendResponse("response A\n") - .receiveRequest("request B\n") - .sendResponse("response C\n") - .receiveRequest("request D\n") - .sendResponse("response E\n") - .receiveRequest("request F\n") - .exhaustResponse() - .exhaustRequest() + val body = + MockStreamHandler() + .sendResponse("response A\n") + .receiveRequest("request B\n") + .sendResponse("response C\n") + .receiveRequest("request D\n") + .sendResponse("response E\n") + .receiveRequest("request F\n") + .exhaustResponse() + .exhaustRequest() server.enqueue( MockResponse.Builder() .clearHeaders() .streamHandler(body) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build(), + ) call.execute().use { response -> val requestBody = (call.request().body as AsyncRequestBody?)!!.takeSink() val responseBody = response.body.source() @@ -186,9 +191,10 @@ class DuplexTest { @Test fun clientReadsHeadersDataTrailers() { enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .sendResponse("ok") - .exhaustResponse() + val body = + MockStreamHandler() + .sendResponse("ok") + .exhaustResponse() server.enqueue( MockResponse.Builder() .clearHeaders() @@ -196,13 +202,14 @@ class DuplexTest { .addHeader("h2", "v2") .trailers(headersOf("trailers", "boom")) .streamHandler(body) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) call.execute().use { response -> assertThat(response.headers) .isEqualTo(headersOf("h1", "v1", "h2", "v2")) @@ -218,23 +225,25 @@ class DuplexTest { fun serverReadsHeadersData() { assumeNotWindows() enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .exhaustResponse() - .receiveRequest("hey\n") - .receiveRequest("whats going on\n") - .exhaustRequest() + val body = + MockStreamHandler() + .exhaustResponse() + .receiveRequest("hey\n") + .receiveRequest("whats going on\n") + .exhaustRequest() server.enqueue( MockResponse.Builder() .clearHeaders() .addHeader("h1", "v1") .addHeader("h2", "v2") .streamHandler(body) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .method("POST", AsyncRequestBody()) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .method("POST", AsyncRequestBody()) + .build() val call = client.newCall(request) call.execute().use { response -> val sink = (request.body as AsyncRequestBody?)!!.takeSink() @@ -248,22 +257,24 @@ class DuplexTest { @Test fun requestBodyEndsAfterResponseBody() { enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .exhaustResponse() - .receiveRequest("request A\n") - .exhaustRequest() + val body = + MockStreamHandler() + .exhaustResponse() + .receiveRequest("request A\n") + .exhaustRequest() server.enqueue( MockResponse.Builder() .clearHeaders() .streamHandler(body) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build(), + ) call.execute().use { response -> val responseBody = response.body.source() assertTrue(responseBody.exhausted()) @@ -277,31 +288,33 @@ class DuplexTest { "SecureConnectStart", "SecureConnectEnd", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "RequestBodyStart", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", "RequestBodyEnd", - "ConnectionReleased", "CallEnd" + "ConnectionReleased", "CallEnd", ) } @Test fun duplexWith100Continue() { enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .receiveRequest("request body\n") - .sendResponse("response body\n") - .exhaustRequest() + val body = + MockStreamHandler() + .receiveRequest("request body\n") + .sendResponse("response body\n") + .exhaustRequest() server.enqueue( MockResponse.Builder() .clearHeaders() .add100Continue() .streamHandler(body) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .header("Expect", "100-continue") - .post(AsyncRequestBody()) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .header("Expect", "100-continue") + .post(AsyncRequestBody()) + .build(), + ) call.execute().use { response -> val requestBody = (call.request().body as AsyncRequestBody?)!!.takeSink() requestBody.writeUtf8("request body\n") @@ -324,44 +337,51 @@ class DuplexTest { fun duplexWithRedirect() { enableProtocol(Protocol.HTTP_2) val duplexResponseSent = CountDownLatch(1) - listener = object : RecordingEventListener() { - override fun responseHeadersEnd(call: Call, response: Response) { - try { - // Wait for the server to send the duplex response before acting on the 301 response - // and resetting the stream. - duplexResponseSent.await() - } catch (e: InterruptedException) { - throw AssertionError() + listener = + object : RecordingEventListener() { + override fun responseHeadersEnd( + call: Call, + response: Response, + ) { + try { + // Wait for the server to send the duplex response before acting on the 301 response + // and resetting the stream. + duplexResponseSent.await() + } catch (e: InterruptedException) { + throw AssertionError() + } + super.responseHeadersEnd(call, response) } - super.responseHeadersEnd(call, response) } - } - client = client.newBuilder() - .eventListener(listener) - .build() - val body = MockStreamHandler() - .sendResponse("/a has moved!\n", duplexResponseSent) - .requestIOException() - .exhaustResponse() + client = + client.newBuilder() + .eventListener(listener) + .build() + val body = + MockStreamHandler() + .sendResponse("/a has moved!\n", duplexResponseSent) + .requestIOException() + .exhaustResponse() server.enqueue( MockResponse.Builder() .clearHeaders() .code(HttpURLConnection.HTTP_MOVED_PERM) .addHeader("Location: /b") .streamHandler(body) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("this is /b") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build(), + ) call.execute().use { response -> val responseBody = response.body.source() assertThat(responseBody.readUtf8Line()) @@ -382,7 +402,7 @@ class DuplexTest { "RequestHeadersStart", "RequestHeadersEnd", "RequestBodyStart", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseBodyEnd", "ConnectionReleased", "CallEnd", "RequestFailed" + "ResponseBodyEnd", "ConnectionReleased", "CallEnd", "RequestFailed", ) } @@ -394,37 +414,41 @@ class DuplexTest { fun duplexWithAuthChallenge() { enableProtocol(Protocol.HTTP_2) val credential = basic("jesse", "secret") - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(credential, null)) - .build() - val body1 = MockStreamHandler() - .sendResponse("please authenticate!\n") - .requestIOException() - .exhaustResponse() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(credential, null)) + .build() + val body1 = + MockStreamHandler() + .sendResponse("please authenticate!\n") + .requestIOException() + .exhaustResponse() server.enqueue( MockResponse.Builder() .clearHeaders() .code(HttpURLConnection.HTTP_UNAUTHORIZED) .streamHandler(body1) - .build() + .build(), ) - val body = MockStreamHandler() - .sendResponse("response body\n") - .exhaustResponse() - .receiveRequest("request body\n") - .exhaustRequest() + val body = + MockStreamHandler() + .sendResponse("response body\n") + .exhaustResponse() + .receiveRequest("request body\n") + .exhaustRequest() server.enqueue( MockResponse.Builder() .clearHeaders() .streamHandler(body) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build(), + ) val response2 = call.execute() // First duplex request is detached with violence. @@ -458,12 +482,13 @@ class DuplexTest { server.enqueue( MockResponse.Builder() .headersDelay(500, TimeUnit.MILLISECONDS) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build() val call = client.newCall(request) call.timeout().timeout(250, TimeUnit.MILLISECONDS) assertFailsWith { @@ -477,23 +502,25 @@ class DuplexTest { @Test fun fullCallTimeoutDoesNotApplyOnceConnected() { enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .sendResponse("response A\n") - .sleep(750, TimeUnit.MILLISECONDS) - .sendResponse("response B\n") - .receiveRequest("request C\n") - .exhaustResponse() - .exhaustRequest() + val body = + MockStreamHandler() + .sendResponse("response A\n") + .sleep(750, TimeUnit.MILLISECONDS) + .sendResponse("response B\n") + .receiveRequest("request C\n") + .exhaustResponse() + .exhaustRequest() server.enqueue( MockResponse.Builder() .clearHeaders() .streamHandler(body) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build() val call = client.newCall(request) call.timeout() .timeout(500, TimeUnit.MILLISECONDS) // Long enough for the first TLS handshake. @@ -514,27 +541,30 @@ class DuplexTest { @Test fun duplexWithRewriteInterceptors() { enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .receiveRequest("REQUEST A\n") - .sendResponse("response B\n") - .exhaustRequest() - .exhaustResponse() + val body = + MockStreamHandler() + .receiveRequest("REQUEST A\n") + .sendResponse("response B\n") + .exhaustRequest() + .exhaustResponse() server.enqueue( MockResponse.Builder() .clearHeaders() .streamHandler(body) - .build() + .build(), ) - client = client.newBuilder() - .addInterceptor(UppercaseRequestInterceptor()) - .addInterceptor(UppercaseResponseInterceptor()) - .build() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(AsyncRequestBody()) + client = + client.newBuilder() + .addInterceptor(UppercaseRequestInterceptor()) + .addInterceptor(UppercaseResponseInterceptor()) .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(AsyncRequestBody()) + .build(), + ) call.execute().use { response -> val requestBody = (call.request().body as AsyncRequestBody?)!!.takeSink() requestBody.writeUtf8("request A\n") @@ -559,46 +589,51 @@ class DuplexTest { @Disabled @Test fun serverCancelsRequestBodyAndSendsResponseBody() { - client = client.newBuilder() - .retryOnConnectionFailure(false) - .build() + client = + client.newBuilder() + .retryOnConnectionFailure(false) + .build() val log: BlockingQueue = LinkedBlockingQueue() enableProtocol(Protocol.HTTP_2) - val body = MockStreamHandler() - .sendResponse("success!") - .exhaustResponse() - .cancelStream() + val body = + MockStreamHandler() + .sendResponse("success!") + .exhaustResponse() + .cancelStream() server.enqueue( MockResponse.Builder() .clearHeaders() .streamHandler(body) - .build() + .build(), ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(object : RequestBody() { - override fun contentType(): MediaType? { - return null - } + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post( + object : RequestBody() { + override fun contentType(): MediaType? { + return null + } - override fun writeTo(sink: BufferedSink) { - try { - for (i in 0..9) { - sink.writeUtf8(".") - sink.flush() - Thread.sleep(100) + override fun writeTo(sink: BufferedSink) { + try { + for (i in 0..9) { + sink.writeUtf8(".") + sink.flush() + Thread.sleep(100) + } + } catch (e: IOException) { + log.add(e.toString()) + throw e + } catch (e: Exception) { + log.add(e.toString()) + } } - } catch (e: IOException) { - log.add(e.toString()) - throw e - } catch (e: Exception) { - log.add(e.toString()) - } - } - }) - .build() - ) + }, + ) + .build(), + ) call.execute().use { response -> assertThat(response.body.string()).isEqualTo("success!") } @@ -617,15 +652,17 @@ class DuplexTest { server.enqueue( MockResponse.Builder() .headersDelay(1500, TimeUnit.MILLISECONDS) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .post(DelayedRequestBody("hello".toRequestBody(null), 1500, TimeUnit.MILLISECONDS)) - .build() - client = client.newBuilder() - .readTimeout(1000, TimeUnit.MILLISECONDS) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(DelayedRequestBody("hello".toRequestBody(null), 1500, TimeUnit.MILLISECONDS)) + .build() + client = + client.newBuilder() + .readTimeout(1000, TimeUnit.MILLISECONDS) + .build() val call = client.newCall(request) assertFailsWith { call.execute() @@ -642,15 +679,17 @@ class DuplexTest { MockResponse.Builder() .bodyDelay(1500, TimeUnit.MILLISECONDS) .body("this should never be received") - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .post(DelayedRequestBody("hello".toRequestBody(null), 1500, TimeUnit.MILLISECONDS)) - .build() - client = client.newBuilder() - .readTimeout(1000, TimeUnit.MILLISECONDS) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(DelayedRequestBody("hello".toRequestBody(null), 1500, TimeUnit.MILLISECONDS)) + .build() + client = + client.newBuilder() + .readTimeout(1000, TimeUnit.MILLISECONDS) + .build() val call = client.newCall(request) val response = call.execute() assertFailsWith { @@ -670,15 +709,17 @@ class DuplexTest { server.enqueue( MockResponse.Builder() .headersDelay(500, TimeUnit.MILLISECONDS) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .post(DelayedRequestBody("hello".toRequestBody(null), 1500, TimeUnit.MILLISECONDS)) - .build() - client = client.newBuilder() - .readTimeout(1000, TimeUnit.MILLISECONDS) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(DelayedRequestBody("hello".toRequestBody(null), 1500, TimeUnit.MILLISECONDS)) + .build() + client = + client.newBuilder() + .readTimeout(1000, TimeUnit.MILLISECONDS) + .build() val call = client.newCall(request) val response = call.execute() assertThat(response.isSuccessful).isTrue() @@ -695,15 +736,17 @@ class DuplexTest { MockResponse.Builder() .bodyDelay(500, TimeUnit.MILLISECONDS) .body("success") - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .post(DelayedRequestBody("hello".toRequestBody(null), 1500, TimeUnit.MILLISECONDS)) - .build() - client = client.newBuilder() - .readTimeout(1000, TimeUnit.MILLISECONDS) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(DelayedRequestBody("hello".toRequestBody(null), 1500, TimeUnit.MILLISECONDS)) + .build() + client = + client.newBuilder() + .readTimeout(1000, TimeUnit.MILLISECONDS) + .build() val call = client.newCall(request) val response = call.execute() assertThat(response.body.string()).isEqualTo("success") @@ -714,26 +757,28 @@ class DuplexTest { */ private fun enableProtocol(protocol: Protocol) { enableTls() - client = client.newBuilder() - .protocols(listOf(protocol, Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .protocols(listOf(protocol, Protocol.HTTP_1_1)) + .build() server.protocols = client.protocols } private fun enableTls() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } private inner class DelayedRequestBody( private val delegate: RequestBody, delay: Long, - timeUnit: TimeUnit + timeUnit: TimeUnit, ) : RequestBody() { private val delayMillis = timeUnit.toMillis(delay) diff --git a/okhttp/src/test/java/okhttp3/EventListenerTest.kt b/okhttp/src/test/java/okhttp3/EventListenerTest.kt index 3a1d923c6584..fe3f199a5ba1 100644 --- a/okhttp/src/test/java/okhttp3/EventListenerTest.kt +++ b/okhttp/src/test/java/okhttp3/EventListenerTest.kt @@ -37,6 +37,7 @@ import java.time.Duration import java.util.Arrays import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit +import kotlin.test.assertFailsWith import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import mockwebserver3.SocketPolicy.DisconnectDuringRequestBody @@ -78,8 +79,6 @@ import org.hamcrest.Matcher import org.hamcrest.MatcherAssert import org.junit.Assume import org.junit.jupiter.api.AfterEach -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test @@ -98,9 +97,10 @@ class EventListenerTest { private lateinit var server: MockWebServer private val listener: RecordingEventListener = RecordingEventListener() private val handshakeCertificates = platform.localhostHandshakeCertificates() - private var client = clientTestRule.newClientBuilder() - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + private var client = + clientTestRule.newClientBuilder() + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() private var socksProxy: SocksProxy? = null private var cache: Cache? = null @@ -127,13 +127,14 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isEqualTo("abc") @@ -143,7 +144,7 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @@ -152,14 +153,15 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() + .build(), ) val ipAddress = InetAddress.getLoopbackAddress().hostAddress - val call = client.newCall( - Request.Builder() - .url(server.url("/").newBuilder().host(ipAddress!!).build()) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/").newBuilder().host(ipAddress!!).build()) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isEqualTo("abc") @@ -169,7 +171,7 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @@ -178,24 +180,32 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val completionLatch = CountDownLatch(1) - val callback: Callback = object : Callback { - override fun onFailure(call: Call, e: IOException) { - completionLatch.countDown() - } + val callback: Callback = + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + completionLatch.countDown() + } - override fun onResponse(call: Call, response: Response) { - response.close() - completionLatch.countDown() + override fun onResponse( + call: Call, + response: Response, + ) { + response.close() + completionLatch.countDown() + } } - } call.enqueue(callback) completionLatch.await() assertThat(listener.recordedEventTypes()).containsExactly( @@ -203,7 +213,7 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @@ -212,16 +222,18 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .headersDelay(2, TimeUnit.SECONDS) - .build() + .build(), ) - client = client.newBuilder() - .readTimeout(Duration.ofMillis(250)) - .build() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) + client = + client.newBuilder() + .readTimeout(Duration.ofMillis(250)) .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) assertFailsWith { call.execute() }.also { expected -> @@ -231,7 +243,7 @@ class EventListenerTest { "CallStart", "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", - "RequestHeadersEnd", "ResponseFailed", "ConnectionReleased", "CallFailed" + "RequestHeadersEnd", "ResponseFailed", "ConnectionReleased", "CallFailed", ) } @@ -242,17 +254,19 @@ class EventListenerTest { .body("0123456789") .throttleBody(2, 100, TimeUnit.MILLISECONDS) .socketPolicy(DisconnectDuringResponseBody) - .build() - ) - client = client.newBuilder() - .protocols(listOf(Protocol.HTTP_1_1)) - .readTimeout(Duration.ofMillis(250)) - .build() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + .build(), + ) + client = + client.newBuilder() + .protocols(listOf(Protocol.HTTP_1_1)) + .readTimeout(Duration.ofMillis(250)) + .build() + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertFailsWith { response.body.string() @@ -264,7 +278,7 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseFailed", "ConnectionReleased", "CallFailed" + "ResponseFailed", "ConnectionReleased", "CallFailed", ) val responseFailed = listener.removeUpToEvent() assertThat(responseFailed.ioe.message).isEqualTo("unexpected end of stream") @@ -272,11 +286,12 @@ class EventListenerTest { @Test fun canceledCallEventSequence() { - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) call.cancel() assertFailsWith { call.execute() @@ -284,7 +299,9 @@ class EventListenerTest { assertThat(expected.message).isEqualTo("Canceled") } assertThat(listener.recordedEventTypes()).containsExactly( - "Canceled", "CallStart", "CallFailed" + "Canceled", + "CallStart", + "CallFailed", ) } @@ -293,21 +310,30 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - } + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) + call.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + } - override fun onResponse(call: Call, response: Response) { - response.close() - } - }) + override fun onResponse( + call: Call, + response: Response, + ) { + response.close() + } + }, + ) call.cancel() assertThat(listener.recordedEventTypes()).contains("Canceled") } @@ -317,24 +343,26 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) call.cancel() call.cancel() assertThat(listener.recordedEventTypes()).containsExactly("Canceled") } private fun assertSuccessfulEventOrder(responseMatcher: Matcher?) { - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.string() @@ -358,7 +386,7 @@ class EventListenerTest { "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", - "CallEnd" + "CallEnd", ) } @@ -371,14 +399,15 @@ class EventListenerTest { client.newCall( Request.Builder() .url(server.url("/")) - .build() + .build(), ).execute().close() listener.removeUpToEvent() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() response.close() assertThat(listener.recordedEventTypes()).containsExactly( @@ -391,20 +420,23 @@ class EventListenerTest { "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", - "CallEnd" + "CallEnd", ) } private fun assertBytesReadWritten( listener: RecordingEventListener, - requestHeaderLength: Matcher?, requestBodyBytes: Matcher?, - responseHeaderLength: Matcher?, responseBodyBytes: Matcher? + requestHeaderLength: Matcher?, + requestBodyBytes: Matcher?, + responseHeaderLength: Matcher?, + responseBodyBytes: Matcher?, ) { if (requestHeaderLength != null) { val responseHeadersEnd = listener.removeUpToEvent() MatcherAssert.assertThat( - "request header length", responseHeadersEnd.headerLength, - requestHeaderLength + "request header length", + responseHeadersEnd.headerLength, + requestHeaderLength, ) } else { assertThat(listener.recordedEventTypes()) @@ -415,7 +447,7 @@ class EventListenerTest { MatcherAssert.assertThat( "request body bytes", responseBodyEnd.bytesWritten, - requestBodyBytes + requestBodyBytes, ) } else { assertThat(listener.recordedEventTypes()).doesNotContain("RequestBodyEnd") @@ -424,8 +456,9 @@ class EventListenerTest { val responseHeadersEnd: ResponseHeadersEnd = listener.removeUpToEvent() MatcherAssert.assertThat( - "response header length", responseHeadersEnd.headerLength, - responseHeaderLength + "response header length", + responseHeadersEnd.headerLength, + responseHeaderLength, ) } else { assertThat(listener.recordedEventTypes()) @@ -436,7 +469,7 @@ class EventListenerTest { MatcherAssert.assertThat( "response body bytes", responseBodyEnd.bytesRead, - responseBodyBytes + responseBodyBytes, ) } else { assertThat(listener.recordedEventTypes()).doesNotContain("ResponseBodyEnd") @@ -474,8 +507,11 @@ class EventListenerTest { server.enqueue(MockResponse()) assertSuccessfulEventOrder(matchesProtocol(Protocol.HTTP_2)) assertBytesReadWritten( - listener, CoreMatchers.any(Long::class.java), null, greaterThan(0L), - CoreMatchers.equalTo(0L) + listener, + CoreMatchers.any(Long::class.java), + null, + greaterThan(0L), + CoreMatchers.equalTo(0L), ) } @@ -486,12 +522,15 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() + .build(), ) assertSuccessfulEventOrder(anyResponse) assertBytesReadWritten( - listener, CoreMatchers.any(Long::class.java), null, greaterThan(0L), - CoreMatchers.equalTo(3L) + listener, + CoreMatchers.any(Long::class.java), + null, + greaterThan(0L), + CoreMatchers.equalTo(3L), ) } @@ -503,12 +542,15 @@ class EventListenerTest { MockResponse.Builder() .bodyDelay(100, TimeUnit.MILLISECONDS) .chunkedBody("Hello!", 2) - .build() + .build(), ) assertSuccessfulEventOrder(anyResponse) assertBytesReadWritten( - listener, CoreMatchers.any(Long::class.java), null, greaterThan(0L), - CoreMatchers.equalTo(6L) + listener, + CoreMatchers.any(Long::class.java), + null, + greaterThan(0L), + CoreMatchers.equalTo(6L), ) } @@ -520,23 +562,27 @@ class EventListenerTest { MockResponse.Builder() .bodyDelay(100, TimeUnit.MILLISECONDS) .chunkedBody("Hello!", 2) - .build() + .build(), ) assertSuccessfulEventOrder(matchesProtocol(Protocol.HTTP_2)) assertBytesReadWritten( - listener, CoreMatchers.any(Long::class.java), null, CoreMatchers.equalTo(0L), - greaterThan(6L) + listener, + CoreMatchers.any(Long::class.java), + null, + CoreMatchers.equalTo(0L), + greaterThan(6L), ) } @Test fun successfulDnsLookup() { server.enqueue(MockResponse()) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -555,20 +601,22 @@ class EventListenerTest { server.enqueue(MockResponse()) // Seed the pool. - val call1 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call1 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response1 = call1.execute() assertThat(response1.code).isEqualTo(200) response1.body.close() listener.clearAllEvents() - val call2 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call2 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response2 = call2.execute() assertThat(response2.code).isEqualTo(200) response2.body.close() @@ -583,20 +631,22 @@ class EventListenerTest { MockResponse.Builder() .code(301) .setHeader("Location", "http://www.fakeurl:" + server.port) - .build() + .build(), ) server.enqueue(MockResponse()) val dns = FakeDns() dns["fakeurl"] = client.dns.lookup(server.hostName) dns["www.fakeurl"] = client.dns.lookup(server.hostName) - client = client.newBuilder() - .dns(dns) - .build() - val call = client.newCall( - Request.Builder() - .url("http://fakeurl:" + server.port) - .build() - ) + client = + client.newBuilder() + .dns(dns) + .build() + val call = + client.newCall( + Request.Builder() + .url("http://fakeurl:" + server.port) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -608,14 +658,16 @@ class EventListenerTest { @Test fun failedDnsLookup() { - client = client.newBuilder() - .dns(FakeDns()) - .build() - val call = client.newCall( - Request.Builder() - .url("http://fakeurl/") - .build() - ) + client = + client.newBuilder() + .dns(FakeDns()) + .build() + val call = + client.newCall( + Request.Builder() + .url("http://fakeurl/") + .build(), + ) assertFailsWith { call.execute() } @@ -628,14 +680,16 @@ class EventListenerTest { @Test fun emptyDnsLookup() { val emptyDns = Dns { listOf() } - client = client.newBuilder() - .dns(emptyDns) - .build() - val call = client.newCall( - Request.Builder() - .url("http://fakeurl/") - .build() - ) + client = + client.newBuilder() + .dns(emptyDns) + .build() + val call = + client.newCall( + Request.Builder() + .url("http://fakeurl/") + .build(), + ) assertFailsWith { call.execute() } @@ -643,18 +697,19 @@ class EventListenerTest { val callFailed: CallFailed = listener.removeUpToEvent() assertThat(callFailed.call).isSameAs(call) assertThat(callFailed.ioe).isInstanceOf( - UnknownHostException::class.java + UnknownHostException::class.java, ) } @Test fun successfulConnect() { server.enqueue(MockResponse()) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -676,13 +731,14 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .socketPolicy(FailHandshake) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) assertFailsWith { call.execute() } @@ -705,17 +761,19 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .socketPolicy(FailHandshake) - .build() + .build(), ) server.enqueue(MockResponse()) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -728,25 +786,27 @@ class EventListenerTest { @Test fun successfulHttpProxyConnect() { server.enqueue(MockResponse()) - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .build() - val call = client.newCall( - Request.Builder() - .url("http://www.fakeurl") - .build() - ) + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .build() + val call = + client.newCall( + Request.Builder() + .url("http://www.fakeurl") + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() val address = client.dns.lookup(server.hostName)[0] val expectedAddress = InetSocketAddress(address, server.port) - val connectStart: ConnectStart = listener.removeUpToEvent( - ) + val connectStart: ConnectStart = + listener.removeUpToEvent() assertThat(connectStart.call).isSameAs(call) assertThat(connectStart.inetSocketAddress).isEqualTo(expectedAddress) assertThat(connectStart.proxy).isEqualTo( - server.toProxyAddress() + server.toProxyAddress(), ) val connectEnd = listener.removeUpToEvent() assertThat(connectEnd.call).isSameAs(call) @@ -760,20 +820,24 @@ class EventListenerTest { socksProxy = SocksProxy() socksProxy!!.play() val proxy = socksProxy!!.proxy() - client = client.newBuilder() - .proxy(proxy) - .build() - val call = client.newCall( - Request.Builder() - .url("http://" + SocksProxy.HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS + ":" + server.port) - .build() - ) + client = + client.newBuilder() + .proxy(proxy) + .build() + val call = + client.newCall( + Request.Builder() + .url("http://" + SocksProxy.HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS + ":" + server.port) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() - val expectedAddress = InetSocketAddress.createUnresolved( - SocksProxy.HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS, server.port - ) + val expectedAddress = + InetSocketAddress.createUnresolved( + SocksProxy.HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS, + server.port, + ) val connectStart = listener.removeUpToEvent() assertThat(connectStart.call).isSameAs(call) assertThat(connectStart.inetSocketAddress).isEqualTo(expectedAddress) @@ -793,23 +857,25 @@ class EventListenerTest { .code(407) .addHeader("Proxy-Authenticate: Basic realm=\"localhost\"") .addHeader("Connection: close") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .inTunnel() - .build() + .build(), ) server.enqueue(MockResponse()) - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) - .build() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) + .build() + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -824,11 +890,12 @@ class EventListenerTest { fun successfulSecureConnect() { enableTlsWithTunnel() server.enqueue(MockResponse()) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -845,13 +912,14 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .socketPolicy(FailHandshake) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) assertFailsWith { call.execute() } @@ -868,17 +936,19 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .inTunnel() - .build() + .build(), ) server.enqueue(MockResponse()) - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .build() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .build() + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -895,17 +965,19 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .socketPolicy(FailHandshake) - .build() + .build(), ) server.enqueue(MockResponse()) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -920,25 +992,28 @@ class EventListenerTest { enableTlsWithTunnel() server.enqueue(MockResponse()) server.enqueue(MockResponse()) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() // Seed the pool. - val call1 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call1 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response1 = call1.execute() assertThat(response1.code).isEqualTo(200) response1.body.close() listener.clearAllEvents() - val call2 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call2 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response2 = call2.execute() assertThat(response2.code).isEqualTo(200) response2.body.close() @@ -950,11 +1025,12 @@ class EventListenerTest { @Test fun successfulConnectionFound() { server.enqueue(MockResponse()) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) response.body.close() @@ -969,18 +1045,19 @@ class EventListenerTest { MockResponse.Builder() .code(301) .addHeader("Location", "/foo") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("ABC") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.body.string()).isEqualTo("ABC") listener.removeUpToEvent() @@ -994,27 +1071,29 @@ class EventListenerTest { server.enqueue(MockResponse()) // Seed the pool. - val call1 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call1 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response1 = call1.execute() assertThat(response1.code).isEqualTo(200) response1.body.close() val connectionAcquired1 = listener.removeUpToEvent() listener.clearAllEvents() - val call2 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call2 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response2 = call2.execute() assertThat(response2.code).isEqualTo(200) response2.body.close() val connectionAcquired2 = listener.removeUpToEvent() assertThat(connectionAcquired2.connection).isSameAs( - connectionAcquired1.connection + connectionAcquired1.connection, ) } @@ -1025,18 +1104,19 @@ class EventListenerTest { .code(301) .addHeader("Location", "/foo") .addHeader("Connection", "Close") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .body("ABC") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.body.string()).isEqualTo("ABC") listener.removeUpToEvent() @@ -1070,13 +1150,14 @@ class EventListenerTest { MockResponse.Builder() .body(Buffer().write(ByteArray(responseBodySize))) .socketPolicy(DisconnectDuringResponseBody) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() if (expectedProtocol == Protocol.HTTP_2) { // soft failure since client may not support depending on Platform @@ -1097,13 +1178,14 @@ class EventListenerTest { .body("") .bodyDelay(1, TimeUnit.SECONDS) .socketPolicy(DisconnectDuringResponseBody) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() response.body.close() assertThat(listener.recordedEventTypes()).containsExactly( @@ -1111,7 +1193,7 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @@ -1121,13 +1203,14 @@ class EventListenerTest { MockResponse.Builder() .addHeader("Connection", "close") .body("") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() response.body.close() assertThat(listener.recordedEventTypes()).containsExactly( @@ -1135,7 +1218,7 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @@ -1146,13 +1229,14 @@ class EventListenerTest { .body("abc") .bodyDelay(1, TimeUnit.SECONDS) .socketPolicy(DisconnectDuringResponseBody) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() response.body.close() assertThat(listener.recordedEventTypes()).containsExactly( @@ -1160,7 +1244,7 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @@ -1188,15 +1272,16 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .socketPolicy(DisconnectDuringRequestBody) - .build() + .build(), ) val request = NonCompletingRequestBody() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(request) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(request) + .build(), + ) assertFailsWith { call.execute() } @@ -1213,6 +1298,7 @@ class EventListenerTest { private inner class NonCompletingRequestBody : RequestBody() { private val chunk: ByteArray? = ByteArray(1024 * 1024) var ioe: IOException? = null + override fun contentType(): MediaType? { return "text/plain".toMediaType() } @@ -1240,37 +1326,39 @@ class EventListenerTest { @Test fun requestBodyMultipleFailuresReportedOnlyOnce() { - val requestBody: RequestBody = object : RequestBody() { - override fun contentType() = "text/plain".toMediaType() + val requestBody: RequestBody = + object : RequestBody() { + override fun contentType() = "text/plain".toMediaType() - override fun contentLength(): Long { - return 1024 * 1024 * 256 - } + override fun contentLength(): Long { + return 1024 * 1024 * 256 + } - override fun writeTo(sink: BufferedSink) { - var failureCount = 0 - for (i in 0..1023) { - try { - sink.write(ByteArray(1024 * 256)) - sink.flush() - } catch (e: IOException) { - failureCount++ - if (failureCount == 3) throw e + override fun writeTo(sink: BufferedSink) { + var failureCount = 0 + for (i in 0..1023) { + try { + sink.write(ByteArray(1024 * 256)) + sink.flush() + } catch (e: IOException) { + failureCount++ + if (failureCount == 3) throw e + } } } } - } server.enqueue( MockResponse.Builder() .socketPolicy(DisconnectDuringRequestBody) - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(requestBody) - .build() - ) + .build(), + ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(requestBody) + .build(), + ) assertFailsWith { call.execute() } @@ -1289,7 +1377,7 @@ class EventListenerTest { "RequestFailed", "ResponseFailed", "ConnectionReleased", - "CallFailed" + "CallFailed", ) } @@ -1298,8 +1386,9 @@ class EventListenerTest { enableTlsWithTunnel() server.protocols = Arrays.asList(Protocol.HTTP_1_1) requestBodySuccess( - "Hello".toRequestBody("text/plain".toMediaType()), CoreMatchers.equalTo(5L), - CoreMatchers.equalTo(19L) + "Hello".toRequestBody("text/plain".toMediaType()), + CoreMatchers.equalTo(5L), + CoreMatchers.equalTo(19L), ) } @@ -1309,37 +1398,41 @@ class EventListenerTest { enableTlsWithTunnel() server.protocols = Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1) requestBodySuccess( - "Hello".toRequestBody("text/plain".toMediaType()), CoreMatchers.equalTo(5L), - CoreMatchers.equalTo(19L) + "Hello".toRequestBody("text/plain".toMediaType()), + CoreMatchers.equalTo(5L), + CoreMatchers.equalTo(19L), ) } @Test fun requestBodySuccessHttp() { requestBodySuccess( - "Hello".toRequestBody("text/plain".toMediaType()), CoreMatchers.equalTo(5L), - CoreMatchers.equalTo(19L) + "Hello".toRequestBody("text/plain".toMediaType()), + CoreMatchers.equalTo(5L), + CoreMatchers.equalTo(19L), ) } @Test fun requestBodySuccessStreaming() { - val requestBody: RequestBody = object : RequestBody() { - override fun contentType() = "text/plain".toMediaType() + val requestBody: RequestBody = + object : RequestBody() { + override fun contentType() = "text/plain".toMediaType() - override fun writeTo(sink: BufferedSink) { - sink.write(ByteArray(8192)) - sink.flush() + override fun writeTo(sink: BufferedSink) { + sink.write(ByteArray(8192)) + sink.flush() + } } - } requestBodySuccess(requestBody, CoreMatchers.equalTo(8192L), CoreMatchers.equalTo(19L)) } @Test fun requestBodySuccessEmpty() { requestBodySuccess( - "".toRequestBody("text/plain".toMediaType()), CoreMatchers.equalTo(0L), - CoreMatchers.equalTo(19L) + "".toRequestBody("text/plain".toMediaType()), + CoreMatchers.equalTo(0L), + CoreMatchers.equalTo(19L), ) } @@ -1348,19 +1441,21 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() - ) - client = client.newBuilder() - .addNetworkInterceptor( - HttpLoggingInterceptor() - .setLevel(HttpLoggingInterceptor.Level.BODY) + .build(), + ) + client = + client.newBuilder() + .addNetworkInterceptor( + HttpLoggingInterceptor() + .setLevel(HttpLoggingInterceptor.Level.BODY), + ) + .build() + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), ) - .build() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) val response = call.execute() assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isEqualTo("abc") @@ -1370,31 +1465,36 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", - "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } private fun requestBodySuccess( - body: RequestBody?, requestBodyBytes: Matcher?, - responseHeaderLength: Matcher? + body: RequestBody?, + requestBodyBytes: Matcher?, + responseHeaderLength: Matcher?, ) { server.enqueue( MockResponse.Builder() .code(200) .body("World!") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(body!!) - .build() - ) + .build(), + ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post(body!!) + .build(), + ) val response = call.execute() assertThat(response.body.string()).isEqualTo("World!") assertBytesReadWritten( - listener, CoreMatchers.any(Long::class.java), requestBodyBytes, responseHeaderLength, - CoreMatchers.equalTo(6L) + listener, + CoreMatchers.any(Long::class.java), + requestBodyBytes, + responseHeaderLength, + CoreMatchers.equalTo(6L), ) } @@ -1431,54 +1531,63 @@ class EventListenerTest { // Warm up the client so the timing part of the test gets a pooled connection. server.enqueue(MockResponse()) - val warmUpCall = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val warmUpCall = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) warmUpCall.execute().use { warmUpResponse -> warmUpResponse.body.string() } listener.clearAllEvents() // Create a client with artificial delays. - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - try { - Thread.sleep(applicationInterceptorDelay) - return@Interceptor chain.proceed(chain.request()) - } catch (e: InterruptedException) { - throw InterruptedIOException() - } - }) - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain -> - try { - Thread.sleep(networkInterceptorDelay) - return@Interceptor chain.proceed(chain.request()) - } catch (e: InterruptedException) { - throw InterruptedIOException() - } - }) - .build() - - // Create a request body with artificial delays. - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(object : RequestBody() { - override fun contentType(): MediaType? { - return null - } - - override fun writeTo(sink: BufferedSink) { + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> try { - Thread.sleep(requestBodyDelay) - sink.writeUtf8("abc") + Thread.sleep(applicationInterceptorDelay) + return@Interceptor chain.proceed(chain.request()) } catch (e: InterruptedException) { throw InterruptedIOException() } - } - }) + }, + ) + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain -> + try { + Thread.sleep(networkInterceptorDelay) + return@Interceptor chain.proceed(chain.request()) + } catch (e: InterruptedException) { + throw InterruptedIOException() + } + }, + ) .build() - ) + + // Create a request body with artificial delays. + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post( + object : RequestBody() { + override fun contentType(): MediaType? { + return null + } + + override fun writeTo(sink: BufferedSink) { + try { + Thread.sleep(requestBodyDelay) + sink.writeUtf8("abc") + } catch (e: InterruptedException) { + throw InterruptedIOException() + } + } + }, + ) + .build(), + ) // Create a response with artificial delays. server.enqueue( @@ -1487,7 +1596,7 @@ class EventListenerTest { .bodyDelay(responseBodyStartDelay, TimeUnit.MILLISECONDS) .throttleBody(5, responseBodyEndDelay, TimeUnit.MILLISECONDS) .body("fghijk") - .build() + .build(), ) call.execute().use { response -> assertThat(response.body.string()).isEqualTo("fghijk") @@ -1509,12 +1618,13 @@ class EventListenerTest { } private fun enableTlsWithTunnel() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } @@ -1524,7 +1634,7 @@ class EventListenerTest { MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .addHeader("Location: /foo") - .build() + .build(), ) server.enqueue(MockResponse()) val call = client.newCall(Request.Builder().url(server.url("/")).build()) @@ -1536,7 +1646,7 @@ class EventListenerTest { "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", - "CallEnd" + "CallEnd", ) } @@ -1547,7 +1657,7 @@ class EventListenerTest { MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .addHeader("Location: " + otherServer.url("/foo")) - .build() + .build(), ) otherServer.enqueue(MockResponse()) val call = client.newCall(Request.Builder().url(server.url("/")).build()) @@ -1582,7 +1692,7 @@ class EventListenerTest { "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", - "CallEnd" + "CallEnd", ) } @@ -1590,13 +1700,16 @@ class EventListenerTest { fun applicationInterceptorProceedsMultipleTimes() { server.enqueue(MockResponse.Builder().body("a").build()) server.enqueue(MockResponse.Builder().body("b").build()) - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain? -> - chain!!.proceed(chain.request()) - .use { a -> assertThat(a.body.string()).isEqualTo("a") } - chain.proceed(chain.request()) - }) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain? -> + chain!!.proceed(chain.request()) + .use { a -> assertThat(a.body.string()).isEqualTo("a") } + chain.proceed(chain.request()) + }, + ) + .build() val call = client.newCall(Request.Builder().url(server.url("/")).build()) val response = call.execute() assertThat(response.body.string()).isEqualTo("b") @@ -1607,7 +1720,7 @@ class EventListenerTest { "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", - "CallEnd" + "CallEnd", ) assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) @@ -1615,17 +1728,20 @@ class EventListenerTest { @Test fun applicationInterceptorShortCircuit() { - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain? -> - Response.Builder() - .request(chain!!.request()) - .protocol(Protocol.HTTP_1_1) - .code(200) - .message("OK") - .body("a".toResponseBody(null)) - .build() - }) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain? -> + Response.Builder() + .request(chain!!.request()) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("OK") + .body("a".toResponseBody(null)) + .build() + }, + ) + .build() val call = client.newCall(Request.Builder().url(server.url("/")).build()) val response = call.execute() assertThat(response.body.string()).isEqualTo("a") @@ -1639,20 +1755,21 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .add100Continue() - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .header("Expect", "100-continue") - .post("abc".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Expect", "100-continue") + .post("abc".toRequestBody("text/plain".toMediaType())) + .build() val call = client.newCall(request) call.execute() assertThat(listener.recordedEventTypes()).containsExactly( "CallStart", "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "RequestBodyStart", "RequestBodyEnd", "ResponseHeadersEnd", - "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @@ -1663,13 +1780,14 @@ class EventListenerTest { MockResponse.Builder() .add100Continue() .headersDelay(responseHeadersStartDelay, TimeUnit.MILLISECONDS) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .header("Expect", "100-continue") - .post("abc".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("Expect", "100-continue") + .post("abc".toRequestBody("text/plain".toMediaType())) + .build() val call = client.newCall(request) call.execute() .use { response -> assertThat(response.body.string()).isEqualTo("") } @@ -1685,13 +1803,14 @@ class EventListenerTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() - ) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isEqualTo("abc") @@ -1701,7 +1820,7 @@ class EventListenerTest { "ProxySelectStart", "ProxySelectEnd", "DnsStart", "DnsEnd", "ConnectStart", "ConnectEnd", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", - "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @@ -1712,18 +1831,19 @@ class EventListenerTest { MockResponse.Builder() .addHeader("ETag", "v1") .body("abc") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_MODIFIED) - .build() - ) - var call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + var call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) var response = call.execute() assertThat(response.code).isEqualTo(200) response.close() @@ -1737,7 +1857,7 @@ class EventListenerTest { "CallStart", "CacheConditionalHit", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", - "ResponseBodyStart", "ResponseBodyEnd", "CacheHit", "ConnectionReleased", "CallEnd" + "ResponseBodyStart", "ResponseBodyEnd", "CacheHit", "ConnectionReleased", "CallEnd", ) } @@ -1748,20 +1868,21 @@ class EventListenerTest { MockResponse.Builder() .addHeader("ETag: v1") .body("abc") - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_OK) .addHeader("ETag: v2") .body("abd") - .build() - ) - var call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + var call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) var response = call.execute() assertThat(response.code).isEqualTo(200) response.close() @@ -1775,19 +1896,20 @@ class EventListenerTest { "CallStart", "CacheConditionalHit", "ConnectionAcquired", "RequestHeadersStart", "RequestHeadersEnd", "ResponseHeadersStart", "ResponseHeadersEnd", "CacheMiss", - "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", "CallEnd" + "ResponseBodyStart", "ResponseBodyEnd", "ConnectionReleased", "CallEnd", ) } @Test fun satisfactionFailure() { enableCache() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .cacheControl(CacheControl.FORCE_CACHE) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .cacheControl(CacheControl.FORCE_CACHE) + .build(), + ) val response = call.execute() assertThat(response.code).isEqualTo(504) response.close() @@ -1802,13 +1924,14 @@ class EventListenerTest { MockResponse.Builder() .body("abc") .addHeader("cache-control: public, max-age=300") - .build() - ) - var call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + var call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) var response = call.execute() assertThat(response.code).isEqualTo(200) assertThat(response.body.string()).isEqualTo("abc") diff --git a/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt b/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt index 7c5192ff3c2a..e2a91ef38c8e 100644 --- a/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt +++ b/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt @@ -85,7 +85,7 @@ class FakeRoutePlanner( } inner class FakePlan( - val id: Int + val id: Int, ) : RoutePlanner.Plan { var planningThrowable: Throwable? = null var canceled = false diff --git a/okhttp/src/test/java/okhttp3/FallbackTestClientSocketFactory.kt b/okhttp/src/test/java/okhttp3/FallbackTestClientSocketFactory.kt index 065295a42854..f56cdf9417e4 100644 --- a/okhttp/src/test/java/okhttp3/FallbackTestClientSocketFactory.kt +++ b/okhttp/src/test/java/okhttp3/FallbackTestClientSocketFactory.kt @@ -28,11 +28,10 @@ import okhttp3.FallbackTestClientSocketFactory.Companion.TLS_FALLBACK_SCSV class FallbackTestClientSocketFactory( delegate: SSLSocketFactory, ) : DelegatingSSLSocketFactory(delegate) { - override fun configureSocket(sslSocket: SSLSocket): SSLSocket = - TlsFallbackScsvDisabledSSLSocket(sslSocket) + override fun configureSocket(sslSocket: SSLSocket): SSLSocket = TlsFallbackScsvDisabledSSLSocket(sslSocket) private class TlsFallbackScsvDisabledSSLSocket( - socket: SSLSocket + socket: SSLSocket, ) : DelegatingSSLSocket(socket) { override fun setEnabledCipherSuites(suites: Array) { val enabledCipherSuites = mutableListOf() diff --git a/okhttp/src/test/java/okhttp3/FastFallbackTest.kt b/okhttp/src/test/java/okhttp3/FastFallbackTest.kt index da696b776d60..c67f0d4fd020 100644 --- a/okhttp/src/test/java/okhttp3/FastFallbackTest.kt +++ b/okhttp/src/test/java/okhttp3/FastFallbackTest.kt @@ -19,7 +19,6 @@ import assertk.assertThat import assertk.assertions.hasMessage import assertk.assertions.hasSize import assertk.assertions.isEqualTo -import assertk.fail import java.io.IOException import java.net.Inet4Address import java.net.Inet6Address @@ -87,21 +86,24 @@ class FastFallbackTest { serverIpv6 = MockWebServer() serverIpv6.start(localhostIpv6, serverIpv4.port) // Pick the same port as the IPv4 server. - dnsResults = listOf( - localhostIpv4, - localhostIpv6, - ) - - client = clientTestRule.newClientBuilder() - .eventListenerFactory(clientTestRule.wrap(listener)) - .connectTimeout(60, TimeUnit.SECONDS) // Deliberately exacerbate slow fallbacks. - .dns { dnsResults } - .fastFallback(true) - .build() - url = serverIpv4.url("/") - .newBuilder() - .host("localhost") - .build() + dnsResults = + listOf( + localhostIpv4, + localhostIpv6, + ) + + client = + clientTestRule.newClientBuilder() + .eventListenerFactory(clientTestRule.wrap(listener)) + .connectTimeout(60, TimeUnit.SECONDS) // Deliberately exacerbate slow fallbacks. + .dns { dnsResults } + .fastFallback(true) + .build() + url = + serverIpv4.url("/") + .newBuilder() + .host("localhost") + .build() } @AfterEach @@ -112,15 +114,16 @@ class FastFallbackTest { @Test fun callIpv6FirstEvenWhenIpv4IpIsListedFirst() { - dnsResults = listOf( - localhostIpv4, - localhostIpv6, - ) + dnsResults = + listOf( + localhostIpv4, + localhostIpv6, + ) serverIpv4.enqueue( - MockResponse(body = "unexpected call to IPv4") + MockResponse(body = "unexpected call to IPv4"), ) serverIpv6.enqueue( - MockResponse(body = "hello from IPv6") + MockResponse(body = "hello from IPv6"), ) val call = client.newCall(Request(url)) @@ -135,15 +138,16 @@ class FastFallbackTest { @Test fun callIpv6WhenBothServersAreReachable() { // Flip DNS results to prefer IPv6. - dnsResults = listOf( - localhostIpv6, - localhostIpv4, - ) + dnsResults = + listOf( + localhostIpv6, + localhostIpv4, + ) serverIpv4.enqueue( - MockResponse(body = "unexpected call to IPv4") + MockResponse(body = "unexpected call to IPv4"), ) serverIpv6.enqueue( - MockResponse(body = "hello from IPv6") + MockResponse(body = "hello from IPv6"), ) val call = client.newCall(Request(url)) @@ -159,7 +163,7 @@ class FastFallbackTest { fun reachesIpv4WhenIpv6IsDown() { serverIpv6.shutdown() serverIpv4.enqueue( - MockResponse(body = "hello from IPv4") + MockResponse(body = "hello from IPv4"), ) val call = client.newCall(Request(url)) @@ -176,7 +180,7 @@ class FastFallbackTest { fun reachesIpv6WhenIpv4IsDown() { serverIpv4.shutdown() serverIpv6.enqueue( - MockResponse(body = "hello from IPv6") + MockResponse(body = "hello from IPv6"), ) val call = client.newCall(Request(url)) @@ -207,13 +211,14 @@ class FastFallbackTest { @RetryingTest(5) @Flaky fun reachesIpv4AfterUnreachableIpv6Address() { - dnsResults = listOf( - TestUtil.UNREACHABLE_ADDRESS_IPV6.address, - localhostIpv4, - ) + dnsResults = + listOf( + TestUtil.UNREACHABLE_ADDRESS_IPV6.address, + localhostIpv4, + ) serverIpv6.shutdown() serverIpv4.enqueue( - MockResponse(body = "hello from IPv4") + MockResponse(body = "hello from IPv4"), ) val call = client.newCall(Request(url)) @@ -227,19 +232,21 @@ class FastFallbackTest { @Test fun timesOutWithFastFallbackDisabled() { - dnsResults = listOf( - TestUtil.UNREACHABLE_ADDRESS_IPV4.address, - localhostIpv6, - ) + dnsResults = + listOf( + TestUtil.UNREACHABLE_ADDRESS_IPV4.address, + localhostIpv6, + ) serverIpv4.shutdown() serverIpv6.enqueue( - MockResponse(body = "hello from IPv6") + MockResponse(body = "hello from IPv6"), ) - client = client.newBuilder() - .fastFallback(false) - .callTimeout(1_000, TimeUnit.MILLISECONDS) - .build() + client = + client.newBuilder() + .fastFallback(false) + .callTimeout(1_000, TimeUnit.MILLISECONDS) + .build() val call = client.newCall(Request(url)) assertFailsWith { call.execute() @@ -258,49 +265,54 @@ class FastFallbackTest { @Test fun preferCallConnectionOverDeferredConnection() { // Make sure we have enough connection options to permit retries. - dnsResults = listOf( - localhostIpv4, - localhostIpv6, - TestUtil.UNREACHABLE_ADDRESS_IPV4.address, - ) + dnsResults = + listOf( + localhostIpv4, + localhostIpv6, + TestUtil.UNREACHABLE_ADDRESS_IPV4.address, + ) serverIpv4.protocols = listOf(Protocol.H2_PRIOR_KNOWLEDGE) serverIpv6.protocols = listOf(Protocol.H2_PRIOR_KNOWLEDGE) // Yield the first IP address so the second IP address completes first. val firstConnectLatch = CountDownLatch(1) - val socketFactory = object : DelegatingSocketFactory(SocketFactory.getDefault()) { - var first = true - - override fun createSocket(): Socket { - if (first) { - first = false - firstConnectLatch.await() + val socketFactory = + object : DelegatingSocketFactory(SocketFactory.getDefault()) { + var first = true + + override fun createSocket(): Socket { + if (first) { + first = false + firstConnectLatch.await() + } + return super.createSocket() } - return super.createSocket() } - } - client = client.newBuilder() - .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) - .socketFactory(socketFactory) - .addNetworkInterceptor(Interceptor { chain -> - try { - chain.proceed(chain.request()) - } finally { - firstConnectLatch.countDown() - } - }) - .build() + client = + client.newBuilder() + .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) + .socketFactory(socketFactory) + .addNetworkInterceptor( + Interceptor { chain -> + try { + chain.proceed(chain.request()) + } finally { + firstConnectLatch.countDown() + } + }, + ) + .build() // Set up a same-connection retry. serverIpv4.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) serverIpv4.enqueue( - MockResponse(body = "this was the 2nd request on IPv4") + MockResponse(body = "this was the 2nd request on IPv4"), ) serverIpv6.enqueue( - MockResponse(body = "unexpected call to IPv6") + MockResponse(body = "unexpected call to IPv6"), ) // Confirm the retry succeeds on the same connection. diff --git a/okhttp/src/test/java/okhttp3/FormBodyTest.kt b/okhttp/src/test/java/okhttp3/FormBodyTest.kt index cdf9a424e90b..a4bd453b3a72 100644 --- a/okhttp/src/test/java/okhttp3/FormBodyTest.kt +++ b/okhttp/src/test/java/okhttp3/FormBodyTest.kt @@ -25,11 +25,12 @@ import org.junit.jupiter.api.Test class FormBodyTest { @Test fun urlEncoding() { - val body = FormBody.Builder() - .add("a+=& b", "c+=& d") - .add("space, the", "final frontier") - .add("%25", "%25") - .build() + val body = + FormBody.Builder() + .add("a+=& b", "c+=& d") + .add("space, the", "final frontier") + .add("%25", "%25") + .build() assertThat(body.size).isEqualTo(3) assertThat(body.encodedName(0)).isEqualTo("a%2B%3D%26+b") assertThat(body.encodedName(1)).isEqualTo("space%2C+the") @@ -44,7 +45,7 @@ class FormBodyTest { assertThat(body.value(1)).isEqualTo("final frontier") assertThat(body.value(2)).isEqualTo("%25") assertThat(body.contentType().toString()).isEqualTo( - "application/x-www-form-urlencoded" + "application/x-www-form-urlencoded", ) val expected = "a%2B%3D%26+b=c%2B%3D%26+d&space%2C+the=final+frontier&%2525=%2525" assertThat(body.contentLength()).isEqualTo(expected.length.toLong()) @@ -55,11 +56,12 @@ class FormBodyTest { @Test fun addEncoded() { - val body = FormBody.Builder() - .addEncoded("a+=& b", "c+=& d") - .addEncoded("e+=& f", "g+=& h") - .addEncoded("%25", "%25") - .build() + val body = + FormBody.Builder() + .addEncoded("a+=& b", "c+=& d") + .addEncoded("e+=& f", "g+=& h") + .addEncoded("%25", "%25") + .build() val expected = "a+%3D%26+b=c+%3D%26+d&e+%3D%26+f=g+%3D%26+h&%25=%25" val out = Buffer() body.writeTo(out) @@ -68,9 +70,10 @@ class FormBodyTest { @Test fun encodedPair() { - val body = FormBody.Builder() - .add("sim", "ple") - .build() + val body = + FormBody.Builder() + .add("sim", "ple") + .build() val expected = "sim=ple" assertThat(body.contentLength()).isEqualTo(expected.length.toLong()) val buffer = Buffer() @@ -80,11 +83,12 @@ class FormBodyTest { @Test fun encodeMultiplePairs() { - val body = FormBody.Builder() - .add("sim", "ple") - .add("hey", "there") - .add("help", "me") - .build() + val body = + FormBody.Builder() + .add("sim", "ple") + .add("hey", "there") + .add("help", "me") + .build() val expected = "sim=ple&hey=there&help=me" assertThat(body.contentLength()).isEqualTo(expected.length.toLong()) val buffer = Buffer() @@ -187,9 +191,10 @@ class FormBodyTest { @Throws(IOException::class) private fun formEncode(codePoint: Int): String { // Wrap the codepoint with regular printable characters to prevent trimming. - val body = FormBody.Builder() - .add("a", String(intArrayOf('b'.code, codePoint, 'c'.code), 0, 3)) - .build() + val body = + FormBody.Builder() + .add("a", String(intArrayOf('b'.code, codePoint, 'c'.code), 0, 3)) + .build() val buffer = Buffer() body.writeTo(buffer) buffer.skip(3) // Skip "a=b" prefix. @@ -198,9 +203,10 @@ class FormBodyTest { @Test fun manualCharset() { - val body = FormBody.Builder(StandardCharsets.ISO_8859_1) - .add("name", "Nicolás") - .build() + val body = + FormBody.Builder(StandardCharsets.ISO_8859_1) + .add("name", "Nicolás") + .build() val expected = "name=Nicol%E1s" assertThat(body.contentLength()).isEqualTo(expected.length.toLong()) val out = Buffer() diff --git a/okhttp/src/test/java/okhttp3/HandshakeTest.kt b/okhttp/src/test/java/okhttp3/HandshakeTest.kt index 3dd35f56184b..5f3afa535fcd 100644 --- a/okhttp/src/test/java/okhttp3/HandshakeTest.kt +++ b/okhttp/src/test/java/okhttp3/HandshakeTest.kt @@ -23,72 +23,81 @@ import assertk.assertions.isEqualTo import assertk.assertions.isNull import java.io.IOException import java.security.cert.Certificate +import kotlin.test.assertFailsWith import okhttp3.Handshake.Companion.handshake import okhttp3.tls.HeldCertificate -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.Test class HandshakeTest { - val serverRoot = HeldCertificate.Builder() + val serverRoot = + HeldCertificate.Builder() .certificateAuthority(1) .build() - val serverIntermediate = HeldCertificate.Builder() + val serverIntermediate = + HeldCertificate.Builder() .certificateAuthority(0) .signedBy(serverRoot) .build() - val serverCertificate = HeldCertificate.Builder() + val serverCertificate = + HeldCertificate.Builder() .signedBy(serverIntermediate) .build() @Test fun createFromParts() { - val handshake = Handshake.get( + val handshake = + Handshake.get( tlsVersion = TlsVersion.TLS_1_3, cipherSuite = CipherSuite.TLS_AES_128_GCM_SHA256, peerCertificates = listOf(serverCertificate.certificate, serverIntermediate.certificate), - localCertificates = listOf() - ) + localCertificates = listOf(), + ) assertThat(handshake.tlsVersion).isEqualTo(TlsVersion.TLS_1_3) assertThat(handshake.cipherSuite).isEqualTo(CipherSuite.TLS_AES_128_GCM_SHA256) assertThat(handshake.peerCertificates).containsExactly( - serverCertificate.certificate, serverIntermediate.certificate) + serverCertificate.certificate, + serverIntermediate.certificate, + ) assertThat(handshake.localPrincipal).isNull() assertThat(handshake.peerPrincipal) - .isEqualTo(serverCertificate.certificate.subjectX500Principal) + .isEqualTo(serverCertificate.certificate.subjectX500Principal) assertThat(handshake.localCertificates).isEmpty() } @Test fun createFromSslSession() { - val sslSession = FakeSSLSession( + val sslSession = + FakeSSLSession( "TLSv1.3", "TLS_AES_128_GCM_SHA256", arrayOf(serverCertificate.certificate, serverIntermediate.certificate), - null - ) + null, + ) val handshake = sslSession.handshake() assertThat(handshake.tlsVersion).isEqualTo(TlsVersion.TLS_1_3) assertThat(handshake.cipherSuite).isEqualTo(CipherSuite.TLS_AES_128_GCM_SHA256) assertThat(handshake.peerCertificates).containsExactly( - serverCertificate.certificate, serverIntermediate.certificate) + serverCertificate.certificate, + serverIntermediate.certificate, + ) assertThat(handshake.localPrincipal).isNull() assertThat(handshake.peerPrincipal) - .isEqualTo(serverCertificate.certificate.subjectX500Principal) + .isEqualTo(serverCertificate.certificate.subjectX500Principal) assertThat(handshake.localCertificates).isEmpty() } @Test fun sslWithNullNullNull() { - val sslSession = FakeSSLSession( + val sslSession = + FakeSSLSession( "TLSv1.3", "SSL_NULL_WITH_NULL_NULL", arrayOf(serverCertificate.certificate, serverIntermediate.certificate), - null - ) + null, + ) assertFailsWith { sslSession.handshake() @@ -99,12 +108,13 @@ class HandshakeTest { @Test fun tlsWithNullNullNull() { - val sslSession = FakeSSLSession( + val sslSession = + FakeSSLSession( "TLSv1.3", "TLS_NULL_WITH_NULL_NULL", arrayOf(serverCertificate.certificate, serverIntermediate.certificate), - null - ) + null, + ) assertFailsWith { sslSession.handshake() @@ -117,7 +127,7 @@ class HandshakeTest { private val protocol: String, private val cipherSuite: String, private val peerCertificates: Array?, - private val localCertificates: Array? + private val localCertificates: Array?, ) : DelegatingSSLSession(null) { override fun getProtocol() = protocol diff --git a/okhttp/src/test/java/okhttp3/HeadersChallengesTest.kt b/okhttp/src/test/java/okhttp3/HeadersChallengesTest.kt index b8494be25233..73aa05a5c1da 100644 --- a/okhttp/src/test/java/okhttp3/HeadersChallengesTest.kt +++ b/okhttp/src/test/java/okhttp3/HeadersChallengesTest.kt @@ -24,15 +24,16 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test class HeadersChallengesTest { - /** See https://github.com/square/okhttp/issues/2780. */ @Test fun testDigestChallengeWithStrictRfc2617Header() { - val headers = Headers.Builder() - .add( - "WWW-Authenticate", "Digest realm=\"myrealm\", nonce=\"fjalskdflwejrlaskdfjlaskdjflaks" - + "jdflkasdf\", qop=\"auth\", stale=\"FALSE\"" - ) - .build() + val headers = + Headers.Builder() + .add( + "WWW-Authenticate", + "Digest realm=\"myrealm\", nonce=\"fjalskdflwejrlaskdfjlaskdjflaks" + + "jdflkasdf\", qop=\"auth\", stale=\"FALSE\"", + ) + .build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("Digest") @@ -46,12 +47,14 @@ class HeadersChallengesTest { } @Test fun testDigestChallengeWithDifferentlyOrderedAuthParams() { - val headers = Headers.Builder() - .add( - "WWW-Authenticate", "Digest qop=\"auth\", realm=\"myrealm\", nonce=\"fjalskdflwejrlask" - + "dfjlaskdjflaksjdflkasdf\", stale=\"FALSE\"" - ) - .build() + val headers = + Headers.Builder() + .add( + "WWW-Authenticate", + "Digest qop=\"auth\", realm=\"myrealm\", nonce=\"fjalskdflwejrlask" + + "dfjlaskdjflaksjdflkasdf\", stale=\"FALSE\"", + ) + .build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("Digest") @@ -65,12 +68,14 @@ class HeadersChallengesTest { } @Test fun testDigestChallengeWithDifferentlyOrderedAuthParams2() { - val headers = Headers.Builder() - .add( - "WWW-Authenticate", "Digest qop=\"auth\", nonce=\"fjalskdflwejrlaskdfjlaskdjflaksjdflk" - + "asdf\", realm=\"myrealm\", stale=\"FALSE\"" - ) - .build() + val headers = + Headers.Builder() + .add( + "WWW-Authenticate", + "Digest qop=\"auth\", nonce=\"fjalskdflwejrlaskdfjlaskdjflaksjdflk" + + "asdf\", realm=\"myrealm\", stale=\"FALSE\"", + ) + .build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("Digest") @@ -84,12 +89,14 @@ class HeadersChallengesTest { } @Test fun testDigestChallengeWithMissingRealm() { - val headers = Headers.Builder() - .add( - "WWW-Authenticate", "Digest qop=\"auth\", underrealm=\"myrealm\", nonce=\"fjalskdflwej" - + "rlaskdfjlaskdjflaksjdflkasdf\", stale=\"FALSE\"" - ) - .build() + val headers = + Headers.Builder() + .add( + "WWW-Authenticate", + "Digest qop=\"auth\", underrealm=\"myrealm\", nonce=\"fjalskdflwej" + + "rlaskdfjlaskdjflaksjdflkasdf\", stale=\"FALSE\"", + ) + .build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("Digest") @@ -103,12 +110,14 @@ class HeadersChallengesTest { } @Test fun testDigestChallengeWithAdditionalSpaces() { - val headers = Headers.Builder() - .add( - "WWW-Authenticate", "Digest qop=\"auth\", realm=\"myrealm\", nonce=\"fjalskdflwejrl" - + "askdfjlaskdjflaksjdflkasdf\", stale=\"FALSE\"" - ) - .build() + val headers = + Headers.Builder() + .add( + "WWW-Authenticate", + "Digest qop=\"auth\", realm=\"myrealm\", nonce=\"fjalskdflwejrl" + + "askdfjlaskdjflaksjdflkasdf\", stale=\"FALSE\"", + ) + .build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("Digest") @@ -122,12 +131,14 @@ class HeadersChallengesTest { } @Test fun testDigestChallengeWithAdditionalSpacesBeforeFirstAuthParam() { - val headers = Headers.Builder() - .add( - "WWW-Authenticate", "Digest realm=\"myrealm\", nonce=\"fjalskdflwejrlaskdfjlaskdjfl" - + "aksjdflkasdf\", qop=\"auth\", stale=\"FALSE\"" - ) - .build() + val headers = + Headers.Builder() + .add( + "WWW-Authenticate", + "Digest realm=\"myrealm\", nonce=\"fjalskdflwejrlaskdfjlaskdjfl" + + "aksjdflkasdf\", qop=\"auth\", stale=\"FALSE\"", + ) + .build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("Digest") @@ -141,12 +152,14 @@ class HeadersChallengesTest { } @Test fun testDigestChallengeWithCamelCasedNames() { - val headers = Headers.Builder() - .add( - "WWW-Authenticate", "DiGeSt qop=\"auth\", rEaLm=\"myrealm\", nonce=\"fjalskdflwejrlask" - + "dfjlaskdjflaksjdflkasdf\", stale=\"FALSE\"" - ) - .build() + val headers = + Headers.Builder() + .add( + "WWW-Authenticate", + "DiGeSt qop=\"auth\", rEaLm=\"myrealm\", nonce=\"fjalskdflwejrlask" + + "dfjlaskdjflaksjdflkasdf\", stale=\"FALSE\"", + ) + .build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("DiGeSt") @@ -161,12 +174,14 @@ class HeadersChallengesTest { @Test fun testDigestChallengeWithCamelCasedNames2() { // Strict RFC 2617 camelcased. - val headers = Headers.Builder() - .add( - "WWW-Authenticate", "DIgEsT rEaLm=\"myrealm\", nonce=\"fjalskdflwejrlaskdfjlaskdjflaks" - + "jdflkasdf\", qop=\"auth\", stale=\"FALSE\"" - ) - .build() + val headers = + Headers.Builder() + .add( + "WWW-Authenticate", + "DIgEsT rEaLm=\"myrealm\", nonce=\"fjalskdflwejrlaskdfjlaskdjflaks" + + "jdflkasdf\", qop=\"auth\", stale=\"FALSE\"", + ) + .build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("DIgEsT") @@ -180,8 +195,9 @@ class HeadersChallengesTest { } @Test fun testDigestChallengeWithTokenFormOfAuthParam() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest realm=myrealm").build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest realm=myrealm").build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("Digest") @@ -192,8 +208,9 @@ class HeadersChallengesTest { @Test fun testDigestChallengeWithoutAuthParams() { // Scheme only. - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest").build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest").build() val challenges = headers.parseChallenges("WWW-Authenticate") assertThat(challenges.size).isEqualTo(1) assertThat(challenges[0].scheme).isEqualTo("Digest") @@ -202,17 +219,19 @@ class HeadersChallengesTest { } @Test fun basicChallenge() { - val headers = Headers.Builder() - .add("WWW-Authenticate: Basic realm=\"protected area\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate: Basic realm=\"protected area\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")) .isEqualTo(listOf(Challenge("Basic", mapOf("realm" to "protected area")))) } @Test fun basicChallengeWithCharset() { - val headers = Headers.Builder() - .add("WWW-Authenticate: Basic realm=\"protected area\", charset=\"UTF-8\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate: Basic realm=\"protected area\", charset=\"UTF-8\"") + .build() val expectedAuthParams = mutableMapOf() expectedAuthParams["realm"] = "protected area" expectedAuthParams["charset"] = "UTF-8" @@ -221,9 +240,10 @@ class HeadersChallengesTest { } @Test fun basicChallengeWithUnexpectedCharset() { - val headers = Headers.Builder() - .add("WWW-Authenticate: Basic realm=\"protected area\", charset=\"US-ASCII\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate: Basic realm=\"protected area\", charset=\"US-ASCII\"") + .build() val expectedAuthParams = mutableMapOf() expectedAuthParams["realm"] = "protected area" expectedAuthParams["charset"] = "US-ASCII" @@ -232,187 +252,208 @@ class HeadersChallengesTest { } @Test fun separatorsBeforeFirstChallenge() { - val headers = Headers.Builder() - .add("WWW-Authenticate", " , , Basic realm=myrealm") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", " , , Basic realm=myrealm") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")) .isEqualTo(listOf(Challenge("Basic", mapOf("realm" to "myrealm")))) } @Test fun spacesAroundKeyValueSeparator() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Basic realm = \"myrealm\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Basic realm = \"myrealm\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")) .isEqualTo(listOf(Challenge("Basic", mapOf("realm" to "myrealm")))) } @Test fun multipleChallengesInOneHeader() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Basic realm = \"myrealm\",Digest") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Basic realm = \"myrealm\",Digest") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Basic", mapOf("realm" to "myrealm")), - Challenge("Digest", mapOf()) + Challenge("Digest", mapOf()), ) } @Test fun multipleChallengesWithSameSchemeButDifferentRealmInOneHeader() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Basic realm = \"myrealm\",Basic realm=myotherrealm") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Basic realm = \"myrealm\",Basic realm=myotherrealm") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Basic", mapOf("realm" to "myrealm")), - Challenge("Basic", mapOf("realm" to "myotherrealm")) + Challenge("Basic", mapOf("realm" to "myotherrealm")), ) } @Test fun separatorsBeforeFirstAuthParam() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest, Basic ,,realm=\"myrealm\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest, Basic ,,realm=\"myrealm\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Digest", mapOf()), - Challenge("Basic", mapOf("realm" to "myrealm")) + Challenge("Basic", mapOf("realm" to "myrealm")), ) } @Test fun onlyCommaBetweenChallenges() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest,Basic realm=\"myrealm\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest,Basic realm=\"myrealm\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Digest", mapOf()), - Challenge("Basic", mapOf("realm" to "myrealm")) + Challenge("Basic", mapOf("realm" to "myrealm")), ) } @Test fun multipleSeparatorsBetweenChallenges() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest,,,, Basic ,,realm=\"myrealm\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest,,,, Basic ,,realm=\"myrealm\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Digest", mapOf()), - Challenge("Basic", mapOf("realm" to "myrealm")) + Challenge("Basic", mapOf("realm" to "myrealm")), ) } @Test fun unknownAuthParams() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest,,,, Basic ,,foo=bar,realm=\"myrealm\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest,,,, Basic ,,foo=bar,realm=\"myrealm\"") + .build() val expectedAuthParams = mutableMapOf() expectedAuthParams["realm"] = "myrealm" expectedAuthParams["foo"] = "bar" assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Digest", mapOf()), - Challenge("Basic", expectedAuthParams) + Challenge("Basic", expectedAuthParams), ) } @Test fun escapedCharactersInQuotedString() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=\"my\\\\\\\"r\\ealm\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=\"my\\\\\\\"r\\ealm\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Digest", mapOf()), - Challenge("Basic", mapOf("realm" to "my\\\"realm")) + Challenge("Basic", mapOf("realm" to "my\\\"realm")), ) } @Test fun commaInQuotedStringAndBeforeFirstChallenge() { - val headers = Headers.Builder() - .add("WWW-Authenticate", ",Digest,,,, Basic ,,,realm=\"my, realm,\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", ",Digest,,,, Basic ,,,realm=\"my, realm,\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Digest", mapOf()), - Challenge("Basic", mapOf("realm" to "my, realm,")) + Challenge("Basic", mapOf("realm" to "my, realm,")), ) } @Test fun unescapedDoubleQuoteInQuotedStringWithEvenNumberOfBackslashesInFront() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=\"my\\\\\\\\\"r\\ealm\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=\"my\\\\\\\\\"r\\ealm\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( - Challenge("Digest", mapOf()) + Challenge("Digest", mapOf()), ) } @Test fun unescapedDoubleQuoteInQuotedString() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=\"my\"realm\"") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=\"my\"realm\"") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( - Challenge("Digest", mapOf()) + Challenge("Digest", mapOf()), ) } @Disabled("TODO(jwilson): reject parameters that use invalid characters") - @Test fun doubleQuoteInToken() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=my\"realm") - .build() + @Test + fun doubleQuoteInToken() { + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest,,,, Basic ,,,realm=my\"realm") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( - Challenge("Digest", mapOf()) + Challenge("Digest", mapOf()), ) } @Test fun token68InsteadOfAuthParams() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Other abc==") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Other abc==") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")) - .isEqualTo(listOf(Challenge("Other", mapOf(null to "abc=="))) + .isEqualTo( + listOf(Challenge("Other", mapOf(null to "abc=="))), ) } @Test fun token68AndAuthParams() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Other abc==, realm=myrealm") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Other abc==, realm=myrealm") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( - Challenge("Other", mapOf(null to "abc==")) + Challenge("Other", mapOf(null to "abc==")), ) } @Test fun repeatedAuthParamKey() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Other realm=myotherrealm, realm=myrealm") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Other realm=myotherrealm, realm=myrealm") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).isEqualTo(listOf()) } @Test fun multipleAuthenticateHeaders() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Digest") - .add("WWW-Authenticate", "Basic realm=myrealm") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Digest") + .add("WWW-Authenticate", "Basic realm=myrealm") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Digest", mapOf()), - Challenge("Basic", mapOf("realm" to "myrealm")) + Challenge("Basic", mapOf("realm" to "myrealm")), ) } @Test fun multipleAuthenticateHeadersInDifferentOrder() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Basic realm=myrealm") - .add("WWW-Authenticate", "Digest") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Basic realm=myrealm") + .add("WWW-Authenticate", "Digest") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Basic", mapOf("realm" to "myrealm")), - Challenge("Digest", mapOf()) + Challenge("Digest", mapOf()), ) } @Test fun multipleBasicAuthenticateHeaders() { - val headers = Headers.Builder() - .add("WWW-Authenticate", "Basic realm=myrealm") - .add("WWW-Authenticate", "Basic realm=myotherrealm") - .build() + val headers = + Headers.Builder() + .add("WWW-Authenticate", "Basic realm=myrealm") + .add("WWW-Authenticate", "Basic realm=myotherrealm") + .build() assertThat(headers.parseChallenges("WWW-Authenticate")).containsExactly( Challenge("Basic", mapOf("realm" to "myrealm")), - Challenge("Basic", mapOf("realm" to "myotherrealm")) + Challenge("Basic", mapOf("realm" to "myotherrealm")), ) } } diff --git a/okhttp/src/test/java/okhttp3/HeadersJvmTest.kt b/okhttp/src/test/java/okhttp3/HeadersJvmTest.kt index a54d7f8e02de..25c09e128a5e 100644 --- a/okhttp/src/test/java/okhttp3/HeadersJvmTest.kt +++ b/okhttp/src/test/java/okhttp3/HeadersJvmTest.kt @@ -21,77 +21,80 @@ import assertk.assertions.isEqualTo import java.time.Instant import java.util.Date import kotlin.test.assertFailsWith -import kotlin.test.fail import okhttp3.Headers.Companion.toHeaders import okhttp3.internal.EMPTY_HEADERS import org.junit.jupiter.api.Test class HeadersJvmTest { - @Test fun byteCount() { assertThat(EMPTY_HEADERS.byteCount()).isEqualTo(0L) assertThat( Headers.Builder() .add("abc", "def") .build() - .byteCount() + .byteCount(), ).isEqualTo(10L) assertThat( Headers.Builder() .add("abc", "def") .add("ghi", "jkl") .build() - .byteCount() + .byteCount(), ).isEqualTo(20L) } @Test fun addDate() { val expected = Date(0L) - val headers = Headers.Builder() - .add("testDate", expected) - .build() + val headers = + Headers.Builder() + .add("testDate", expected) + .build() assertThat(headers["testDate"]).isEqualTo("Thu, 01 Jan 1970 00:00:00 GMT") assertThat(headers.getDate("testDate")).isEqualTo(Date(0L)) } @Test fun addInstant() { val expected = Instant.ofEpochMilli(0L) - val headers = Headers.Builder() - .add("Test-Instant", expected) - .build() + val headers = + Headers.Builder() + .add("Test-Instant", expected) + .build() assertThat(headers["Test-Instant"]).isEqualTo("Thu, 01 Jan 1970 00:00:00 GMT") assertThat(headers.getInstant("Test-Instant")).isEqualTo(expected) } @Test fun setDate() { val expected = Date(1000) - val headers = Headers.Builder() - .add("testDate", Date(0L)) - .set("testDate", expected) - .build() + val headers = + Headers.Builder() + .add("testDate", Date(0L)) + .set("testDate", expected) + .build() assertThat(headers["testDate"]).isEqualTo("Thu, 01 Jan 1970 00:00:01 GMT") assertThat(headers.getDate("testDate")).isEqualTo(expected) } @Test fun setInstant() { val expected = Instant.ofEpochMilli(1000L) - val headers = Headers.Builder() - .add("Test-Instant", Instant.ofEpochMilli(0L)) - .set("Test-Instant", expected) - .build() + val headers = + Headers.Builder() + .add("Test-Instant", Instant.ofEpochMilli(0L)) + .set("Test-Instant", expected) + .build() assertThat(headers["Test-Instant"]).isEqualTo("Thu, 01 Jan 1970 00:00:01 GMT") assertThat(headers.getInstant("Test-Instant")).isEqualTo(expected) } @Test fun addParsing() { - val headers = Headers.Builder() - .add("foo: bar") - .add(" foo: baz") // Name leading whitespace is trimmed. - .add("foo : bak") // Name trailing whitespace is trimmed. - .add("\tkey\t:\tvalue\t") // '\t' also counts as whitespace - .add("ping: pong ") // Value whitespace is trimmed. - .add("kit:kat") // Space after colon is not required. - .build() + val headers = + Headers.Builder() + .add("foo: bar") + .add(" foo: baz") // Name leading whitespace is trimmed. + .add("foo : bak") // Name trailing whitespace is trimmed. + .add("\tkey\t:\tvalue\t") // '\t' also counts as whitespace + .add("ping: pong ") // Value whitespace is trimmed. + .add("kit:kat") // Space after colon is not required. + .build() assertThat(headers.values("foo")).containsExactly("bar", "baz", "bak") assertThat(headers.values("key")).containsExactly("value") assertThat(headers.values("ping")).containsExactly("pong") @@ -130,9 +133,10 @@ class HeadersJvmTest { } @Test fun addUnsafeNonAsciiAcceptsUnicodeValue() { - val headers = Headers.Builder() - .addUnsafeNonAscii("header1", "valué1") - .build() + val headers = + Headers.Builder() + .addUnsafeNonAscii("header1", "valué1") + .build() assertThat(headers.toString()).isEqualTo("header1: valué1\n") } @@ -144,32 +148,43 @@ class HeadersJvmTest { } @Test fun toMultimapGroupsHeaders() { - val headers = Headers.headersOf( - "cache-control", "no-cache", - "cache-control", "no-store", - "user-agent", "OkHttp" - ) + val headers = + Headers.headersOf( + "cache-control", + "no-cache", + "cache-control", + "no-store", + "user-agent", + "OkHttp", + ) val headerMap = headers.toMultimap() assertThat(headerMap["cache-control"]!!.size).isEqualTo(2) assertThat(headerMap["user-agent"]!!.size).isEqualTo(1) } @Test fun toMultimapUsesCanonicalCase() { - val headers = Headers.headersOf( - "cache-control", "no-store", - "Cache-Control", "no-cache", - "User-Agent", "OkHttp" - ) + val headers = + Headers.headersOf( + "cache-control", + "no-store", + "Cache-Control", + "no-cache", + "User-Agent", + "OkHttp", + ) val headerMap = headers.toMultimap() assertThat(headerMap["cache-control"]!!.size).isEqualTo(2) assertThat(headerMap["user-agent"]!!.size).isEqualTo(1) } @Test fun toMultimapAllowsCaseInsensitiveGet() { - val headers = Headers.headersOf( - "cache-control", "no-store", - "Cache-Control", "no-cache" - ) + val headers = + Headers.headersOf( + "cache-control", + "no-store", + "Cache-Control", + "no-cache", + ) val headerMap = headers.toMultimap() assertThat(headerMap["cache-control"]!!.size).isEqualTo(2) assertThat(headerMap["Cache-Control"]!!.size).isEqualTo(2) diff --git a/okhttp/src/test/java/okhttp3/HeadersRequestTest.kt b/okhttp/src/test/java/okhttp3/HeadersRequestTest.kt index 94079c763a3e..dd7d0bc1b6c8 100644 --- a/okhttp/src/test/java/okhttp3/HeadersRequestTest.kt +++ b/okhttp/src/test/java/okhttp3/HeadersRequestTest.kt @@ -25,11 +25,15 @@ import org.junit.jupiter.api.Test class HeadersRequestTest { @Test fun readNameValueBlockDropsForbiddenHeadersHttp2() { - val headerBlock = headersOf( - ":status", "200 OK", - ":version", "HTTP/1.1", - "connection", "close" - ) + val headerBlock = + headersOf( + ":status", + "200 OK", + ":version", + "HTTP/1.1", + "connection", + "close", + ) val request = Request.Builder().url("http://square.com/").build() val response = readHttp2HeadersList(headerBlock, Protocol.HTTP_2).request(request).build() val headers = response.headers @@ -39,33 +43,45 @@ class HeadersRequestTest { } @Test fun http2HeadersListDropsForbiddenHeadersHttp2() { - val request = Request.Builder() - .url("http://square.com/") - .header("Connection", "upgrade") - .header("Upgrade", "websocket") - .header("Host", "square.com") - .header("TE", "gzip") - .build() - val expected = headerEntries( - ":method", "GET", - ":path", "/", - ":authority", "square.com", - ":scheme", "http" - ) + val request = + Request.Builder() + .url("http://square.com/") + .header("Connection", "upgrade") + .header("Upgrade", "websocket") + .header("Host", "square.com") + .header("TE", "gzip") + .build() + val expected = + headerEntries( + ":method", + "GET", + ":path", + "/", + ":authority", + "square.com", + ":scheme", + "http", + ) assertThat(http2HeadersList(request)).isEqualTo(expected) } @Test fun http2HeadersListDontDropTeIfTrailersHttp2() { - val request = Request.Builder() - .url("http://square.com/") - .header("TE", "trailers") - .build() - val expected = headerEntries( - ":method", "GET", - ":path", "/", - ":scheme", "http", - "te", "trailers" - ) + val request = + Request.Builder() + .url("http://square.com/") + .header("TE", "trailers") + .build() + val expected = + headerEntries( + ":method", + "GET", + ":path", + "/", + ":scheme", + "http", + "te", + "trailers", + ) assertThat(http2HeadersList(request)).isEqualTo(expected) } } diff --git a/okhttp/src/test/java/okhttp3/HeadersTest.kt b/okhttp/src/test/java/okhttp3/HeadersTest.kt index 4c665e1cbeb5..adb76649a277 100644 --- a/okhttp/src/test/java/okhttp3/HeadersTest.kt +++ b/okhttp/src/test/java/okhttp3/HeadersTest.kt @@ -20,7 +20,6 @@ import assertk.assertions.isEqualTo import assertk.assertions.isNotEqualTo import kotlin.test.Test import kotlin.test.assertFailsWith -import kotlin.test.fail import okhttp3.Headers.Companion.headersOf import okhttp3.Headers.Companion.toHeaders @@ -49,10 +48,11 @@ class HeadersTest { } @Test fun ofMakesDefensiveCopy() { - val namesAndValues = arrayOf( - "User-Agent", - "OkHttp" - ) + val namesAndValues = + arrayOf( + "User-Agent", + "OkHttp", + ) val headers = headersOf(*namesAndValues) namesAndValues[1] = "Chrome" assertThat(headers.value(0)).isEqualTo("OkHttp") @@ -193,48 +193,54 @@ class HeadersTest { } @Test fun headersEquals() { - val headers1 = Headers.Builder() - .add("Connection", "close") - .add("Transfer-Encoding", "chunked") - .build() - val headers2 = Headers.Builder() - .add("Connection", "close") - .add("Transfer-Encoding", "chunked") - .build() + val headers1 = + Headers.Builder() + .add("Connection", "close") + .add("Transfer-Encoding", "chunked") + .build() + val headers2 = + Headers.Builder() + .add("Connection", "close") + .add("Transfer-Encoding", "chunked") + .build() assertThat(headers2).isEqualTo(headers1) assertThat(headers2.hashCode()).isEqualTo(headers1.hashCode()) } @Test fun headersNotEquals() { - val headers1 = Headers.Builder() - .add("Connection", "close") - .add("Transfer-Encoding", "chunked") - .build() - val headers2 = Headers.Builder() - .add("Connection", "keep-alive") - .add("Transfer-Encoding", "chunked") - .build() + val headers1 = + Headers.Builder() + .add("Connection", "close") + .add("Transfer-Encoding", "chunked") + .build() + val headers2 = + Headers.Builder() + .add("Connection", "keep-alive") + .add("Transfer-Encoding", "chunked") + .build() assertThat(headers2).isNotEqualTo(headers1) assertThat(headers2.hashCode()).isNotEqualTo(headers1.hashCode().toLong()) } @Test fun headersToString() { - val headers = Headers.Builder() - .add("A", "a") - .add("B", "bb") - .build() + val headers = + Headers.Builder() + .add("A", "a") + .add("B", "bb") + .build() assertThat(headers.toString()).isEqualTo("A: a\nB: bb\n") } @Test fun headersToStringRedactsSensitiveHeaders() { - val headers = Headers.Builder() - .add("content-length", "99") - .add("authorization", "peanutbutter") - .add("proxy-authorization", "chocolate") - .add("cookie", "drink=coffee") - .add("set-cookie", "accessory=sugar") - .add("user-agent", "OkHttp") - .build() + val headers = + Headers.Builder() + .add("content-length", "99") + .add("authorization", "peanutbutter") + .add("proxy-authorization", "chocolate") + .add("cookie", "drink=coffee") + .add("set-cookie", "accessory=sugar") + .add("user-agent", "OkHttp") + .build() assertThat(headers.toString()).isEqualTo( """ |content-length: 99 @@ -243,21 +249,24 @@ class HeadersTest { |cookie: ██ |set-cookie: ██ |user-agent: OkHttp - |""".trimMargin() + | + """.trimMargin(), ) } @Test fun headersAddAll() { - val sourceHeaders = Headers.Builder() - .add("A", "aa") - .add("a", "aa") - .add("B", "bb") - .build() - val headers = Headers.Builder() - .add("A", "a") - .addAll(sourceHeaders) - .add("C", "c") - .build() + val sourceHeaders = + Headers.Builder() + .add("A", "aa") + .add("a", "aa") + .add("B", "bb") + .build() + val headers = + Headers.Builder() + .add("A", "a") + .addAll(sourceHeaders) + .add("C", "c") + .build() assertThat(headers.toString()).isEqualTo("A: a\nA: aa\na: aa\nB: bb\nC: c\n") } diff --git a/okhttp/src/test/java/okhttp3/HttpUrlJvmTest.kt b/okhttp/src/test/java/okhttp3/HttpUrlJvmTest.kt index 8c3b52222259..2bff439f823f 100644 --- a/okhttp/src/test/java/okhttp3/HttpUrlJvmTest.kt +++ b/okhttp/src/test/java/okhttp3/HttpUrlJvmTest.kt @@ -190,11 +190,12 @@ open class HttpUrlJvmTest { @Test fun toUriFragmentSpecialCharacters() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .fragment("=[]:;\"~|?#@^/$%*") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .fragment("=[]:;\"~|?#@^/$%*") + .build() assertThat(url.toString()).isEqualTo("http://host/#=[]:;\"~|?#@^/$%25*") assertThat(url.toUri().toString()) .isEqualTo("http://host/#=[]:;%22~%7C?%23@%5E/$%25*") @@ -209,22 +210,24 @@ open class HttpUrlJvmTest { @Test fun toUriWithUsernameNoPassword() { - val httpUrl = HttpUrl.Builder() - .scheme("http") - .username("user") - .host("host") - .build() + val httpUrl = + HttpUrl.Builder() + .scheme("http") + .username("user") + .host("host") + .build() assertThat(httpUrl.toString()).isEqualTo("http://user@host/") assertThat(httpUrl.toUri().toString()).isEqualTo("http://user@host/") } @Test fun toUriUsernameSpecialCharacters() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .username("=[]:;\"~|?#@^/$%*") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .username("=[]:;\"~|?#@^/$%*") + .build() assertThat(url.toString()) .isEqualTo("http://%3D%5B%5D%3A%3B%22~%7C%3F%23%40%5E%2F$%25*@host/") assertThat(url.toUri().toString()) @@ -233,12 +236,13 @@ open class HttpUrlJvmTest { @Test fun toUriPasswordSpecialCharacters() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .username("user") - .password("=[]:;\"~|?#@^/$%*") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .username("user") + .password("=[]:;\"~|?#@^/$%*") + .build() assertThat(url.toString()) .isEqualTo("http://user:%3D%5B%5D%3A%3B%22~%7C%3F%23%40%5E%2F$%25*@host/") assertThat(url.toUri().toString()) @@ -247,11 +251,12 @@ open class HttpUrlJvmTest { @Test fun toUriPathSpecialCharacters() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .addPathSegment("=[]:;\"~|?#@^/$%*") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .addPathSegment("=[]:;\"~|?#@^/$%*") + .build() assertThat(url.toString()) .isEqualTo("http://host/=[]:;%22~%7C%3F%23@%5E%2F$%25*") assertThat(url.toUri().toString()) @@ -260,11 +265,12 @@ open class HttpUrlJvmTest { @Test fun toUriQueryParameterNameSpecialCharacters() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .addQueryParameter("=[]:;\"~|?#@^/$%*", "a") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .addQueryParameter("=[]:;\"~|?#@^/$%*", "a") + .build() assertThat(url.toString()) .isEqualTo("http://host/?%3D%5B%5D%3A%3B%22%7E%7C%3F%23%40%5E%2F%24%25*=a") assertThat(url.toUri().toString()) @@ -274,11 +280,12 @@ open class HttpUrlJvmTest { @Test fun toUriQueryParameterValueSpecialCharacters() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .addQueryParameter("a", "=[]:;\"~|?#@^/$%*") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .addQueryParameter("a", "=[]:;\"~|?#@^/$%*") + .build() assertThat(url.toString()) .isEqualTo("http://host/?a=%3D%5B%5D%3A%3B%22%7E%7C%3F%23%40%5E%2F%24%25*") assertThat(url.toUri().toString()) @@ -288,11 +295,12 @@ open class HttpUrlJvmTest { @Test fun toUriQueryValueSpecialCharacters() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .query("=[]:;\"~|?#@^/$%*") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .query("=[]:;\"~|?#@^/$%*") + .build() assertThat(url.toString()).isEqualTo("http://host/?=[]:;%22~|?%23@^/$%25*") assertThat(url.toUri().toString()) .isEqualTo("http://host/?=[]:;%22~%7C?%23@%5E/$%25*") @@ -339,4 +347,3 @@ open class HttpUrlJvmTest { assertThat(url.toUri().toString()).isEqualTo("http://host/#%80") } } - diff --git a/okhttp/src/test/java/okhttp3/HttpUrlTest.kt b/okhttp/src/test/java/okhttp3/HttpUrlTest.kt index 8bc0ed5f1302..91cc094ab57a 100644 --- a/okhttp/src/test/java/okhttp3/HttpUrlTest.kt +++ b/okhttp/src/test/java/okhttp3/HttpUrlTest.kt @@ -36,7 +36,10 @@ open class HttpUrlTest { return url.toHttpUrl() } - protected open fun assertInvalid(string: String, exceptionMessage: String?) { + protected open fun assertInvalid( + string: String, + exceptionMessage: String?, + ) { try { val result = string.toHttpUrl() if (exceptionMessage != null) { @@ -44,7 +47,7 @@ open class HttpUrlTest { } else { fail("Expected failure but got $result") } - } catch(iae: IllegalArgumentException) { + } catch (iae: IllegalArgumentException) { iae.printStackTrace() if (exceptionMessage != null) { assertThat(iae).hasMessage(exceptionMessage) @@ -436,7 +439,7 @@ open class HttpUrlTest { '\''.code, ';'.code, '='.code, - '@'.code + '@'.code, ) .override( Encoding.SKIP, @@ -444,7 +447,7 @@ open class HttpUrlTest { '/'.code, '\\'.code, '?'.code, - '#'.code + '#'.code, ) .test(UrlComponentEncodingTester.Component.USER) } @@ -465,14 +468,14 @@ open class HttpUrlTest { ':'.code, ';'.code, '='.code, - '@'.code + '@'.code, ) .override( Encoding.SKIP, '/'.code, '\\'.code, '?'.code, - '#'.code + '#'.code, ) .test(UrlComponentEncodingTester.Component.PASSWORD) } @@ -546,7 +549,7 @@ open class HttpUrlTest { '\n'.code, '\u000c'.code, '\r'.code, - ' '.code + ' '.code, ) .override( Encoding.FORBIDDEN, @@ -558,11 +561,11 @@ open class HttpUrlTest { '@'.code, '['.code, '\\'.code, - ']'.code + ']'.code, ) .override( // java.net.URL got stricter - if (PlatformVersion.majorVersion >= 21) Encoding.SKIP else Encoding.IDENTITY, + if (PlatformVersion.majorVersion >= 21) Encoding.SKIP else Encoding.IDENTITY, '\"'.code, '<'.code, '>'.code, @@ -570,7 +573,7 @@ open class HttpUrlTest { '`'.code, '{'.code, '|'.code, - '}'.code + '}'.code, ) .test(UrlComponentEncodingTester.Component.HOST) } @@ -631,7 +634,7 @@ open class HttpUrlTest { fun hostIpv6AddressTooManyDigitsInGroup() { assertInvalid( "http://[00000:0000:0000:0000:0000:0000:0000:0001]", - "Invalid URL host: \"[00000:0000:0000:0000:0000:0000:0000:0001]\"" + "Invalid URL host: \"[00000:0000:0000:0000:0000:0000:0000:0001]\"", ) assertInvalid("http://[::00001]", "Invalid URL host: \"[::00001]\"") } @@ -640,36 +643,36 @@ open class HttpUrlTest { fun hostIpv6AddressMisplacedColons() { assertInvalid( "http://[:0000:0000:0000:0000:0000:0000:0000:0001]", - "Invalid URL host: \"[:0000:0000:0000:0000:0000:0000:0000:0001]\"" + "Invalid URL host: \"[:0000:0000:0000:0000:0000:0000:0000:0001]\"", ) assertInvalid( "http://[:::0000:0000:0000:0000:0000:0000:0000:0001]", - "Invalid URL host: \"[:::0000:0000:0000:0000:0000:0000:0000:0001]\"" + "Invalid URL host: \"[:::0000:0000:0000:0000:0000:0000:0000:0001]\"", ) assertInvalid("http://[:1]", "Invalid URL host: \"[:1]\"") assertInvalid("http://[:::1]", "Invalid URL host: \"[:::1]\"") assertInvalid( "http://[0000:0000:0000:0000:0000:0000:0001:]", - "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0001:]\"" + "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0001:]\"", ) assertInvalid( "http://[0000:0000:0000:0000:0000:0000:0000:0001:]", - "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0000:0001:]\"" + "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0000:0001:]\"", ) assertInvalid( "http://[0000:0000:0000:0000:0000:0000:0000:0001::]", - "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0000:0001::]\"" + "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0000:0001::]\"", ) assertInvalid( "http://[0000:0000:0000:0000:0000:0000:0000:0001:::]", - "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0000:0001:::]\"" + "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0000:0001:::]\"", ) assertInvalid("http://[1:]", "Invalid URL host: \"[1:]\"") assertInvalid("http://[1:::]", "Invalid URL host: \"[1:::]\"") assertInvalid("http://[1:::1]", "Invalid URL host: \"[1:::1]\"") assertInvalid( "http://[0000:0000:0000:0000::0000:0000:0000:0001]", - "Invalid URL host: \"[0000:0000:0000:0000::0000:0000:0000:0001]\"" + "Invalid URL host: \"[0000:0000:0000:0000::0000:0000:0000:0001]\"", ) } @@ -677,7 +680,7 @@ open class HttpUrlTest { fun hostIpv6AddressTooManyGroups() { assertInvalid( "http://[0000:0000:0000:0000:0000:0000:0000:0000:0001]", - "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0000:0000:0001]\"" + "Invalid URL host: \"[0000:0000:0000:0000:0000:0000:0000:0000:0001]\"", ) } @@ -685,11 +688,11 @@ open class HttpUrlTest { fun hostIpv6AddressTooMuchCompression() { assertInvalid( "http://[0000::0000:0000:0000:0000::0001]", - "Invalid URL host: \"[0000::0000:0000:0000:0000::0001]\"" + "Invalid URL host: \"[0000::0000:0000:0000:0000::0001]\"", ) assertInvalid( "http://[::0000:0000:0000:0000::0001]", - "Invalid URL host: \"[::0000:0000:0000:0000::0001]\"" + "Invalid URL host: \"[::0000:0000:0000:0000::0001]\"", ) } @@ -704,7 +707,7 @@ open class HttpUrlTest { // Guava's been buggy on this case. https://github.com/google/guava/issues/3116 assertInvalid( "http://[2001:db8:0:0:1:0:0:00001]", - "Invalid URL host: \"[2001:db8:0:0:1:0:0:00001]\"" + "Invalid URL host: \"[2001:db8:0:0:1:0:0:00001]\"", ) } @@ -720,15 +723,15 @@ open class HttpUrlTest { // Chrome interprets a leading '0' as octal; Firefox rejects them. (We reject them.) assertInvalid( "http://[0:0:0:0:0:1:0.0.0.000000]/", - "Invalid URL host: \"[0:0:0:0:0:1:0.0.0.000000]\"" + "Invalid URL host: \"[0:0:0:0:0:1:0.0.0.000000]\"", ) assertInvalid( "http://[0:0:0:0:0:1:0.010.0.010]/", - "Invalid URL host: \"[0:0:0:0:0:1:0.010.0.010]\"" + "Invalid URL host: \"[0:0:0:0:0:1:0.010.0.010]\"", ) assertInvalid( "http://[0:0:0:0:0:1:0.0.0.000001]/", - "Invalid URL host: \"[0:0:0:0:0:1:0.0.0.000001]\"" + "Invalid URL host: \"[0:0:0:0:0:1:0.0.0.000001]\"", ) } @@ -737,7 +740,7 @@ open class HttpUrlTest { // Chrome interprets a leading '0x' as hexadecimal; Firefox rejects them. (We reject them.) assertInvalid( "http://[0:0:0:0:0:1:0.0x10.0.0x10]/", - "Invalid URL host: \"[0:0:0:0:0:1:0.0x10.0.0x10]\"" + "Invalid URL host: \"[0:0:0:0:0:1:0.0x10.0.0x10]\"", ) } @@ -745,55 +748,55 @@ open class HttpUrlTest { fun hostIpv6WithMalformedIpv4Suffix() { assertInvalid( "http://[0:0:0:0:0:1:0.0:0.0]/", - "Invalid URL host: \"[0:0:0:0:0:1:0.0:0.0]\"" + "Invalid URL host: \"[0:0:0:0:0:1:0.0:0.0]\"", ) assertInvalid( "http://[0:0:0:0:0:1:0.0-0.0]/", - "Invalid URL host: \"[0:0:0:0:0:1:0.0-0.0]\"" + "Invalid URL host: \"[0:0:0:0:0:1:0.0-0.0]\"", ) assertInvalid( "http://[0:0:0:0:0:1:.255.255.255]/", - "Invalid URL host: \"[0:0:0:0:0:1:.255.255.255]\"" + "Invalid URL host: \"[0:0:0:0:0:1:.255.255.255]\"", ) assertInvalid( "http://[0:0:0:0:0:1:255..255.255]/", - "Invalid URL host: \"[0:0:0:0:0:1:255..255.255]\"" + "Invalid URL host: \"[0:0:0:0:0:1:255..255.255]\"", ) assertInvalid( "http://[0:0:0:0:0:1:255.255..255]/", - "Invalid URL host: \"[0:0:0:0:0:1:255.255..255]\"" + "Invalid URL host: \"[0:0:0:0:0:1:255.255..255]\"", ) assertInvalid( "http://[0:0:0:0:0:0:1:255.255]/", - "Invalid URL host: \"[0:0:0:0:0:0:1:255.255]\"" + "Invalid URL host: \"[0:0:0:0:0:0:1:255.255]\"", ) assertInvalid( "http://[0:0:0:0:0:1:256.255.255.255]/", - "Invalid URL host: \"[0:0:0:0:0:1:256.255.255.255]\"" + "Invalid URL host: \"[0:0:0:0:0:1:256.255.255.255]\"", ) assertInvalid( "http://[0:0:0:0:0:1:ff.255.255.255]/", - "Invalid URL host: \"[0:0:0:0:0:1:ff.255.255.255]\"" + "Invalid URL host: \"[0:0:0:0:0:1:ff.255.255.255]\"", ) assertInvalid( "http://[0:0:0:0:0:0:1:255.255.255.255]/", - "Invalid URL host: \"[0:0:0:0:0:0:1:255.255.255.255]\"" + "Invalid URL host: \"[0:0:0:0:0:0:1:255.255.255.255]\"", ) assertInvalid( "http://[0:0:0:0:1:255.255.255.255]/", - "Invalid URL host: \"[0:0:0:0:1:255.255.255.255]\"" + "Invalid URL host: \"[0:0:0:0:1:255.255.255.255]\"", ) assertInvalid( "http://[0:0:0:0:1:0.0.0.0:1]/", - "Invalid URL host: \"[0:0:0:0:1:0.0.0.0:1]\"" + "Invalid URL host: \"[0:0:0:0:1:0.0.0.0:1]\"", ) assertInvalid( "http://[0:0.0.0.0:1:0:0:0:0:1]/", - "Invalid URL host: \"[0:0.0.0.0:1:0:0:0:0:1]\"" + "Invalid URL host: \"[0:0.0.0.0:1:0:0:0:0:1]\"", ) assertInvalid( "http://[0.0.0.0:0:0:0:0:0:1]/", - "Invalid URL host: \"[0.0.0.0:0:0:0:0:0:1]\"" + "Invalid URL host: \"[0.0.0.0:0:0:0:0:0:1]\"", ) } @@ -802,11 +805,11 @@ open class HttpUrlTest { // To Chrome & Safari these are well-formed; Firefox disagrees. (We're consistent with Firefox). assertInvalid( "http://[0:0:0:0:0:1:255.255.255.]/", - "Invalid URL host: \"[0:0:0:0:0:1:255.255.255.]\"" + "Invalid URL host: \"[0:0:0:0:0:1:255.255.255.]\"", ) assertInvalid( "http://[0:0:0:0:0:1:255.255.255]/", - "Invalid URL host: \"[0:0:0:0:0:1:255.255.255]\"" + "Invalid URL host: \"[0:0:0:0:0:1:255.255.255]\"", ) } @@ -864,13 +867,13 @@ open class HttpUrlTest { '^'.code, '{'.code, '}'.code, - '|'.code + '|'.code, ) .override( Encoding.SKIP, '\\'.code, '?'.code, - '#'.code + '#'.code, ) .test(UrlComponentEncodingTester.Component.PATH) } @@ -906,7 +909,7 @@ open class HttpUrlTest { '<'.code, '>'.code, '?'.code, - '`'.code + '`'.code, ) .nonAscii(Encoding.IDENTITY) .test(UrlComponentEncodingTester.Component.FRAGMENT) @@ -1050,13 +1053,15 @@ open class HttpUrlTest { @Test fun incompleteUrlComposition() { - val noHost = assertFailsWith { - HttpUrl.Builder().scheme("http").build() - } + val noHost = + assertFailsWith { + HttpUrl.Builder().scheme("http").build() + } assertThat(noHost.message).isEqualTo("host == null") - val noScheme = assertFailsWith { - HttpUrl.Builder().host("host").build() - } + val noScheme = + assertFailsWith { + HttpUrl.Builder().host("host").build() + } assertThat(noScheme.message).isEqualTo("scheme == null") } @@ -1073,7 +1078,7 @@ open class HttpUrlTest { assertThat(HttpUrl.Builder().host("host.com").encodedPath("/path").toString()) .isEqualTo("//host.com/path") assertThat( - HttpUrl.Builder().host("host.com").encodedPath("/path").port(8080).toString() + HttpUrl.Builder().host("host.com").encodedPath("/path").port(8080).toString(), ) .isEqualTo("//host.com:8080/path") } @@ -1084,36 +1089,37 @@ open class HttpUrlTest { parse("http://example.com") .newBuilder() .scheme("https") - .build().port + .build().port, ).isEqualTo(443) assertThat( parse("https://example.com") .newBuilder() .scheme("http") - .build().port + .build().port, ).isEqualTo(80) assertThat( parse("https://example.com:1234") .newBuilder() .scheme("http") - .build().port + .build().port, ).isEqualTo(1234) } @Test fun composeEncodesWhitespace() { - val url = HttpUrl.Builder() - .scheme("http") - .username("a\r\n\u000c\t b") - .password("c\r\n\u000c\t d") - .host("host") - .addPathSegment("e\r\n\u000c\t f") - .query("g\r\n\u000c\t h") - .fragment("i\r\n\u000c\t j") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .username("a\r\n\u000c\t b") + .password("c\r\n\u000c\t d") + .host("host") + .addPathSegment("e\r\n\u000c\t f") + .query("g\r\n\u000c\t h") + .fragment("i\r\n\u000c\t j") + .build() assertThat(url.toString()).isEqualTo( - "http://a%0D%0A%0C%09%20b:c%0D%0A%0C%09%20d@host" - + "/e%0D%0A%0C%09%20f?g%0D%0A%0C%09%20h#i%0D%0A%0C%09 j" + "http://a%0D%0A%0C%09%20b:c%0D%0A%0C%09%20d@host" + + "/e%0D%0A%0C%09%20f?g%0D%0A%0C%09%20h#i%0D%0A%0C%09 j", ) assertThat(url.username).isEqualTo("a\r\n\u000c\t b") assertThat(url.password).isEqualTo("c\r\n\u000c\t d") @@ -1124,20 +1130,21 @@ open class HttpUrlTest { @Test fun composeFromUnencodedComponents() { - val url = HttpUrl.Builder() - .scheme("http") - .username("a:\u0001@/\\?#%b") - .password("c:\u0001@/\\?#%d") - .host("ef") - .port(8080) - .addPathSegment("g:\u0001@/\\?#%h") - .query("i:\u0001@/\\?#%j") - .fragment("k:\u0001@/\\?#%l") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .username("a:\u0001@/\\?#%b") + .password("c:\u0001@/\\?#%d") + .host("ef") + .port(8080) + .addPathSegment("g:\u0001@/\\?#%h") + .query("i:\u0001@/\\?#%j") + .fragment("k:\u0001@/\\?#%l") + .build() assertThat(url.toString()) .isEqualTo( - "http://a%3A%01%40%2F%5C%3F%23%25b:c%3A%01%40%2F%5C%3F%23%25d@ef:8080/" - + "g:%01@%2F%5C%3F%23%25h?i:%01@/\\?%23%25j#k:%01@/\\?#%25l" + "http://a%3A%01%40%2F%5C%3F%23%25b:c%3A%01%40%2F%5C%3F%23%25d@ef:8080/" + + "g:%01@%2F%5C%3F%23%25h?i:%01@/\\?%23%25j#k:%01@/\\?#%25l", ) assertThat(url.scheme).isEqualTo("http") assertThat(url.username).isEqualTo("a:\u0001@/\\?#%b") @@ -1154,20 +1161,21 @@ open class HttpUrlTest { @Test fun composeFromEncodedComponents() { - val url = HttpUrl.Builder() - .scheme("http") - .encodedUsername("a:\u0001@/\\?#%25b") - .encodedPassword("c:\u0001@/\\?#%25d") - .host("ef") - .port(8080) - .addEncodedPathSegment("g:\u0001@/\\?#%25h") - .encodedQuery("i:\u0001@/\\?#%25j") - .encodedFragment("k:\u0001@/\\?#%25l") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .encodedUsername("a:\u0001@/\\?#%25b") + .encodedPassword("c:\u0001@/\\?#%25d") + .host("ef") + .port(8080) + .addEncodedPathSegment("g:\u0001@/\\?#%25h") + .encodedQuery("i:\u0001@/\\?#%25j") + .encodedFragment("k:\u0001@/\\?#%25l") + .build() assertThat(url.toString()) .isEqualTo( - "http://a%3A%01%40%2F%5C%3F%23%25b:c%3A%01%40%2F%5C%3F%23%25d@ef:8080/" - + "g:%01@%2F%5C%3F%23%25h?i:%01@/\\?%23%25j#k:%01@/\\?#%25l" + "http://a%3A%01%40%2F%5C%3F%23%25b:c%3A%01%40%2F%5C%3F%23%25d@ef:8080/" + + "g:%01@%2F%5C%3F%23%25h?i:%01@/\\?%23%25j#k:%01@/\\?#%25l", ) assertThat(url.scheme).isEqualTo("http") assertThat(url.username).isEqualTo("a:\u0001@/\\?#%b") @@ -1184,11 +1192,12 @@ open class HttpUrlTest { @Test fun composeWithEncodedPath() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .encodedPath("/a%2Fb/c") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .encodedPath("/a%2Fb/c") + .build() assertThat(url.toString()).isEqualTo("http://host/a%2Fb/c") assertThat(url.encodedPath).isEqualTo("/a%2Fb/c") assertThat(url.pathSegments).containsExactly("a/b", "c") @@ -1196,13 +1205,14 @@ open class HttpUrlTest { @Test fun composeMixingPathSegments() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .encodedPath("/a%2fb/c") - .addPathSegment("d%25e") - .addEncodedPathSegment("f%25g") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .encodedPath("/a%2fb/c") + .addPathSegment("d%25e") + .addEncodedPathSegment("f%25g") + .build() assertThat(url.toString()).isEqualTo("http://host/a%2fb/c/d%2525e/f%25g") assertThat(url.encodedPath).isEqualTo("/a%2fb/c/d%2525e/f%25g") assertThat(url.encodedPathSegments) @@ -1213,28 +1223,38 @@ open class HttpUrlTest { @Test fun composeWithAddSegment() { val base = parse("http://host/a/b/c") - assertThat(base.newBuilder() - .addPathSegment("") - .build().encodedPath) + assertThat( + base.newBuilder() + .addPathSegment("") + .build().encodedPath, + ) .isEqualTo("/a/b/c/") - assertThat(base.newBuilder() - .addPathSegment("") - .addPathSegment("d") - .build().encodedPath) + assertThat( + base.newBuilder() + .addPathSegment("") + .addPathSegment("d") + .build().encodedPath, + ) .isEqualTo("/a/b/c/d") - assertThat(base.newBuilder() - .addPathSegment("..") - .build().encodedPath) + assertThat( + base.newBuilder() + .addPathSegment("..") + .build().encodedPath, + ) .isEqualTo("/a/b/") - assertThat(base.newBuilder() - .addPathSegment("") - .addPathSegment("..") - .build().encodedPath) + assertThat( + base.newBuilder() + .addPathSegment("") + .addPathSegment("..") + .build().encodedPath, + ) .isEqualTo("/a/b/") - assertThat(base.newBuilder() - .addPathSegment("") - .addPathSegment("") - .build().encodedPath) + assertThat( + base.newBuilder() + .addPathSegment("") + .addPathSegment("") + .build().encodedPath, + ) .isEqualTo("/a/b/c/") } @@ -1320,7 +1340,7 @@ open class HttpUrlTest { fun addEncodedPathSegments() { val base = parse("http://host/a/b/c") assertThat( - base.newBuilder().addEncodedPathSegments("d/e/%20/\n").build().encodedPath as Any + base.newBuilder().addEncodedPathSegments("d/e/%20/\n").build().encodedPath as Any, ).isEqualTo("/a/b/c/d/e/%20/") } @@ -1485,20 +1505,22 @@ open class HttpUrlTest { @Test fun removePathSegment() { val base = parse("http://host/a/b/c") - val url = base.newBuilder() - .removePathSegment(0) - .build() + val url = + base.newBuilder() + .removePathSegment(0) + .build() assertThat(url.encodedPath).isEqualTo("/b/c") } @Test fun removePathSegmentDoesntRemovePath() { val base = parse("http://host/a/b/c") - val url = base.newBuilder() - .removePathSegment(0) - .removePathSegment(0) - .removePathSegment(0) - .build() + val url = + base.newBuilder() + .removePathSegment(0) + .removePathSegment(0) + .removePathSegment(0) + .build() assertThat(url.pathSegments).containsExactly("") assertThat(url.encodedPath).isEqualTo("/") } @@ -1512,11 +1534,12 @@ open class HttpUrlTest { @Test fun queryCharactersEncodedWhenComposed() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .addQueryParameter("a", "!$(),/:;?@[]\\^`{|}~") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .addQueryParameter("a", "!$(),/:;?@[]\\^`{|}~") + .build() assertThat(url.toString()) .isEqualTo("http://host/?a=%21%24%28%29%2C%2F%3A%3B%3F%40%5B%5D%5C%5E%60%7B%7C%7D%7E") assertThat(url.queryParameter("a")).isEqualTo("!$(),/:;?@[]\\^`{|}~") @@ -1528,11 +1551,12 @@ open class HttpUrlTest { */ @Test fun queryCharactersNotReencodedWhenComposedWithAddEncoded() { - val url = HttpUrl.Builder() - .scheme("http") - .host("host") - .addEncodedQueryParameter("a", "!$(),/:;?@[]\\^`{|}~") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .host("host") + .addEncodedQueryParameter("a", "!$(),/:;?@[]\\^`{|}~") + .build() assertThat(url.toString()).isEqualTo("http://host/?a=!$(),/:;?@[]\\^`{|}~") assertThat(url.queryParameter("a")).isEqualTo("!$(),/:;?@[]\\^`{|}~") } @@ -1568,59 +1592,65 @@ open class HttpUrlTest { @Test fun composeQueryWithEncodedComponents() { val base = parse("http://host/") - val url = base.newBuilder() - .addEncodedQueryParameter("a+=& b", "c+=& d") - .build() + val url = + base.newBuilder() + .addEncodedQueryParameter("a+=& b", "c+=& d") + .build() assertThat(url.toString()).isEqualTo("http://host/?a+%3D%26%20b=c+%3D%26%20d") assertThat(url.queryParameter("a =& b")).isEqualTo("c =& d") } @Test fun composeQueryRemoveQueryParameter() { - val url = parse("http://host/").newBuilder() - .addQueryParameter("a+=& b", "c+=& d") - .removeAllQueryParameters("a+=& b") - .build() + val url = + parse("http://host/").newBuilder() + .addQueryParameter("a+=& b", "c+=& d") + .removeAllQueryParameters("a+=& b") + .build() assertThat(url.toString()).isEqualTo("http://host/") assertThat(url.queryParameter("a+=& b")).isNull() } @Test fun composeQueryRemoveEncodedQueryParameter() { - val url = parse("http://host/").newBuilder() - .addEncodedQueryParameter("a+=& b", "c+=& d") - .removeAllEncodedQueryParameters("a+=& b") - .build() + val url = + parse("http://host/").newBuilder() + .addEncodedQueryParameter("a+=& b", "c+=& d") + .removeAllEncodedQueryParameters("a+=& b") + .build() assertThat(url.toString()).isEqualTo("http://host/") assertThat(url.queryParameter("a =& b")).isNull() } @Test fun composeQuerySetQueryParameter() { - val url = parse("http://host/").newBuilder() - .addQueryParameter("a+=& b", "c+=& d") - .setQueryParameter("a+=& b", "ef") - .build() + val url = + parse("http://host/").newBuilder() + .addQueryParameter("a+=& b", "c+=& d") + .setQueryParameter("a+=& b", "ef") + .build() assertThat(url.toString()).isEqualTo("http://host/?a%2B%3D%26%20b=ef") assertThat(url.queryParameter("a+=& b")).isEqualTo("ef") } @Test fun composeQuerySetEncodedQueryParameter() { - val url = parse("http://host/").newBuilder() - .addEncodedQueryParameter("a+=& b", "c+=& d") - .setEncodedQueryParameter("a+=& b", "ef") - .build() + val url = + parse("http://host/").newBuilder() + .addEncodedQueryParameter("a+=& b", "c+=& d") + .setEncodedQueryParameter("a+=& b", "ef") + .build() assertThat(url.toString()).isEqualTo("http://host/?a+%3D%26%20b=ef") assertThat(url.queryParameter("a =& b")).isEqualTo("ef") } @Test fun composeQueryMultipleEncodedValuesForParameter() { - val url = parse("http://host/").newBuilder() - .addQueryParameter("a+=& b", "c+=& d") - .addQueryParameter("a+=& b", "e+=& f") - .build() + val url = + parse("http://host/").newBuilder() + .addQueryParameter("a+=& b", "c+=& d") + .addQueryParameter("a+=& b", "e+=& f") + .build() assertThat(url.toString()) .isEqualTo("http://host/?a%2B%3D%26%20b=c%2B%3D%26%20d&a%2B%3D%26%20b=e%2B%3D%26%20f") assertThat(url.querySize).isEqualTo(2) @@ -1631,17 +1661,19 @@ open class HttpUrlTest { @Test fun absentQueryIsZeroNameValuePairs() { - val url = parse("http://host/").newBuilder() - .query(null) - .build() + val url = + parse("http://host/").newBuilder() + .query(null) + .build() assertThat(url.querySize).isEqualTo(0) } @Test fun emptyQueryIsSingleNameValuePairWithEmptyKey() { - val url = parse("http://host/").newBuilder() - .query("") - .build() + val url = + parse("http://host/").newBuilder() + .query("") + .build() assertThat(url.querySize).isEqualTo(1) assertThat(url.queryParameterName(0)).isEqualTo("") assertThat(url.queryParameterValue(0)).isNull() @@ -1649,9 +1681,10 @@ open class HttpUrlTest { @Test fun ampersandQueryIsTwoNameValuePairsWithEmptyKeys() { - val url = parse("http://host/").newBuilder() - .query("&") - .build() + val url = + parse("http://host/").newBuilder() + .query("&") + .build() assertThat(url.querySize).isEqualTo(2) assertThat(url.queryParameterName(0)).isEqualTo("") assertThat(url.queryParameterValue(0)).isNull() @@ -1661,10 +1694,11 @@ open class HttpUrlTest { @Test fun removeAllDoesNotRemoveQueryIfNoParametersWereRemoved() { - val url = parse("http://host/").newBuilder() - .query("") - .removeAllQueryParameters("a") - .build() + val url = + parse("http://host/").newBuilder() + .query("") + .removeAllQueryParameters("a") + .build() assertThat(url.toString()).isEqualTo("http://host/?") } @@ -1724,15 +1758,16 @@ open class HttpUrlTest { @Test fun roundTripBuilder() { - val url = HttpUrl.Builder() - .scheme("http") - .username("%") - .password("%") - .host("host") - .addPathSegment("%") - .query("%") - .fragment("%") - .build() + val url = + HttpUrl.Builder() + .scheme("http") + .username("%") + .password("%") + .host("host") + .addPathSegment("%") + .query("%") + .fragment("%") + .build() assertThat(url.toString()).isEqualTo("http://%25:%25@host/%25?%25#%25") assertThat(url.newBuilder().build().toString()) .isEqualTo("http://%25:%25@host/%25?%25#%25") @@ -1761,10 +1796,11 @@ open class HttpUrlTest { @Test fun clearFragment() { - val url = parse("http://host/#fragment") - .newBuilder() - .fragment(null) - .build() + val url = + parse("http://host/#fragment") + .newBuilder() + .fragment(null) + .build() assertThat(url.toString()).isEqualTo("http://host/") assertThat(url.fragment).isNull() assertThat(url.encodedFragment).isNull() @@ -1772,10 +1808,11 @@ open class HttpUrlTest { @Test fun clearEncodedFragment() { - val url = parse("http://host/#fragment") - .newBuilder() - .encodedFragment(null) - .build() + val url = + parse("http://host/#fragment") + .newBuilder() + .encodedFragment(null) + .build() assertThat(url.toString()).isEqualTo("http://host/") assertThat(url.fragment).isNull() assertThat(url.encodedFragment).isNull() diff --git a/okhttp/src/test/java/okhttp3/InsecureForHostTest.kt b/okhttp/src/test/java/okhttp3/InsecureForHostTest.kt index c7a86d70a877..894fd43a2043 100644 --- a/okhttp/src/test/java/okhttp3/InsecureForHostTest.kt +++ b/okhttp/src/test/java/okhttp3/InsecureForHostTest.kt @@ -32,8 +32,11 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension class InsecureForHostTest { - @RegisterExtension @JvmField val platform = PlatformRule() - @RegisterExtension @JvmField val clientTestRule = OkHttpClientTestRule() + @RegisterExtension @JvmField + val platform = PlatformRule() + + @RegisterExtension @JvmField + val clientTestRule = OkHttpClientTestRule() private lateinit var server: MockWebServer @@ -50,12 +53,14 @@ class InsecureForHostTest { server.useHttps(serverCertificates.sslSocketFactory()) server.enqueue(MockResponse()) - val clientCertificates = HandshakeCertificates.Builder() + val clientCertificates = + HandshakeCertificates.Builder() .addPlatformTrustedCertificates() .addInsecureHost(server.hostName) .build() - val client = clientTestRule.newClientBuilder() + val client = + clientTestRule.newClientBuilder() .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) .build() @@ -71,21 +76,25 @@ class InsecureForHostTest { } @Test fun `bad certificates host in insecureHosts fails with SSLException`() { - val heldCertificate = HeldCertificate.Builder() + val heldCertificate = + HeldCertificate.Builder() .addSubjectAlternativeName("example.com") .build() - val serverCertificates = HandshakeCertificates.Builder() + val serverCertificates = + HandshakeCertificates.Builder() .heldCertificate(heldCertificate) .build() server.useHttps(serverCertificates.sslSocketFactory()) server.enqueue(MockResponse()) - val clientCertificates = HandshakeCertificates.Builder() + val clientCertificates = + HandshakeCertificates.Builder() .addPlatformTrustedCertificates() .addInsecureHost(server.hostName) .build() - val client = clientTestRule.newClientBuilder() + val client = + clientTestRule.newClientBuilder() .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) .build() @@ -100,12 +109,14 @@ class InsecureForHostTest { server.useHttps(serverCertificates.sslSocketFactory()) server.enqueue(MockResponse()) - val clientCertificates = HandshakeCertificates.Builder() + val clientCertificates = + HandshakeCertificates.Builder() .addPlatformTrustedCertificates() .addInsecureHost("${server.hostName}2") .build() - val client = clientTestRule.newClientBuilder() + val client = + clientTestRule.newClientBuilder() .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) .build() diff --git a/okhttp/src/test/java/okhttp3/InterceptorTest.kt b/okhttp/src/test/java/okhttp3/InterceptorTest.kt index 4c3b15b5108a..5e9334ca9017 100644 --- a/okhttp/src/test/java/okhttp3/InterceptorTest.kt +++ b/okhttp/src/test/java/okhttp3/InterceptorTest.kt @@ -33,6 +33,7 @@ import java.util.concurrent.SynchronousQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicReference +import kotlin.test.assertFailsWith import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import mockwebserver3.SocketPolicy.DisconnectAtEnd @@ -48,8 +49,6 @@ import okio.GzipSink import okio.Sink import okio.Source import okio.buffer -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test @@ -71,19 +70,22 @@ class InterceptorTest { @Test fun applicationInterceptorsCanShortCircuitResponses() { server.shutdown() // Accept no connections. - val request = Request.Builder() - .url("https://localhost:1/") - .build() - val interceptorResponse = Response.Builder() - .request(request) - .protocol(Protocol.HTTP_1_1) - .code(200) - .message("Intercepted!") - .body("abc".toResponseBody("text/plain; charset=utf-8".toMediaType())) - .build() - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain? -> interceptorResponse }) - .build() + val request = + Request.Builder() + .url("https://localhost:1/") + .build() + val interceptorResponse = + Response.Builder() + .request(request) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("Intercepted!") + .body("abc".toResponseBody("text/plain; charset=utf-8".toMediaType())) + .build() + client = + client.newBuilder() + .addInterceptor(Interceptor { chain: Interceptor.Chain? -> interceptorResponse }) + .build() val response = client.newCall(request).execute() assertThat(response).isSameAs(interceptorResponse) } @@ -93,28 +95,31 @@ class InterceptorTest { server.enqueue( MockResponse.Builder() .code(500) - .build() + .build(), ) - val interceptor = Interceptor { chain: Interceptor.Chain -> - Response.Builder() - .request(chain.request()) - .protocol(Protocol.HTTP_1_1) - .code(200) - .message("Intercepted!") - .body("abc".toResponseBody("text/plain; charset=utf-8".toMediaType())) + val interceptor = + Interceptor { chain: Interceptor.Chain -> + Response.Builder() + .request(chain.request()) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("Intercepted!") + .body("abc".toResponseBody("text/plain; charset=utf-8".toMediaType())) + .build() + } + client = + client.newBuilder() + .addNetworkInterceptor(interceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) .build() - } - client = client.newBuilder() - .addNetworkInterceptor(interceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() assertFailsWith { client.newCall(request).execute() }.also { expected -> assertThat(expected.message).isEqualTo( - "network interceptor $interceptor must call proceed() exactly once" + "network interceptor $interceptor must call proceed() exactly once", ) } } @@ -123,21 +128,24 @@ class InterceptorTest { fun networkInterceptorsCannotCallProceedMultipleTimes() { server.enqueue(MockResponse()) server.enqueue(MockResponse()) - val interceptor = Interceptor { chain: Interceptor.Chain -> - chain.proceed(chain.request()) - chain.proceed(chain.request()) - } - client = client.newBuilder() - .addNetworkInterceptor(interceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + val interceptor = + Interceptor { chain: Interceptor.Chain -> + chain.proceed(chain.request()) + chain.proceed(chain.request()) + } + client = + client.newBuilder() + .addNetworkInterceptor(interceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() assertFailsWith { client.newCall(request).execute() }.also { expected -> assertThat(expected.message).isEqualTo( - "network interceptor $interceptor must call proceed() exactly once" + "network interceptor $interceptor must call proceed() exactly once", ) } } @@ -147,29 +155,32 @@ class InterceptorTest { server.enqueue( MockResponse.Builder() .code(500) - .build() + .build(), ) - val interceptor = Interceptor { chain: Interceptor.Chain -> - val address = chain.connection()!!.route().address - val sameHost = address.url.host - val differentPort = address.url.port + 1 - chain.proceed( - chain.request().newBuilder() - .url("http://$sameHost:$differentPort/") - .build() - ) - } - client = client.newBuilder() - .addNetworkInterceptor(interceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + val interceptor = + Interceptor { chain: Interceptor.Chain -> + val address = chain.connection()!!.route().address + val sameHost = address.url.host + val differentPort = address.url.port + 1 + chain.proceed( + chain.request().newBuilder() + .url("http://$sameHost:$differentPort/") + .build(), + ) + } + client = + client.newBuilder() + .addNetworkInterceptor(interceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() assertFailsWith { client.newCall(request).execute() }.also { expected -> assertThat(expected.message).isEqualTo( - "network interceptor $interceptor must retain the same host and port" + "network interceptor $interceptor must retain the same host and port", ) } } @@ -177,17 +188,20 @@ class InterceptorTest { @Test fun networkInterceptorsHaveConnectionAccess() { server.enqueue(MockResponse()) - val interceptor = Interceptor { chain: Interceptor.Chain -> - val connection = chain.connection() - assertThat(connection).isNotNull() - chain.proceed(chain.request()) - } - client = client.newBuilder() - .addNetworkInterceptor(interceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + val interceptor = + Interceptor { chain: Interceptor.Chain -> + val connection = chain.connection() + assertThat(connection).isNotNull() + chain.proceed(chain.request()) + } + client = + client.newBuilder() + .addNetworkInterceptor(interceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() client.newCall(request).execute() } @@ -197,28 +211,31 @@ class InterceptorTest { MockResponse.Builder() .body(gzip("abcabcabc")) .addHeader("Content-Encoding: gzip") - .build() + .build(), ) - val interceptor = Interceptor { chain: Interceptor.Chain -> - // The network request has everything: User-Agent, Host, Accept-Encoding. - val networkRequest = chain.request() - assertThat(networkRequest.header("User-Agent")).isNotNull() - assertThat(networkRequest.header("Host")).isEqualTo( - server.hostName + ":" + server.port - ) - assertThat(networkRequest.header("Accept-Encoding")).isNotNull() - - // The network response also has everything, including the raw gzipped content. - val networkResponse = chain.proceed(networkRequest) - assertThat(networkResponse.header("Content-Encoding")).isEqualTo("gzip") - networkResponse - } - client = client.newBuilder() - .addNetworkInterceptor(interceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + val interceptor = + Interceptor { chain: Interceptor.Chain -> + // The network request has everything: User-Agent, Host, Accept-Encoding. + val networkRequest = chain.request() + assertThat(networkRequest.header("User-Agent")).isNotNull() + assertThat(networkRequest.header("Host")).isEqualTo( + server.hostName + ":" + server.port, + ) + assertThat(networkRequest.header("Accept-Encoding")).isNotNull() + + // The network response also has everything, including the raw gzipped content. + val networkResponse = chain.proceed(networkRequest) + assertThat(networkResponse.header("Content-Encoding")).isEqualTo("gzip") + networkResponse + } + client = + client.newBuilder() + .addNetworkInterceptor(interceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() // No extra headers in the application's request. assertThat(request.header("User-Agent")).isNull() @@ -234,25 +251,28 @@ class InterceptorTest { @Test fun networkInterceptorsCanChangeRequestMethodFromGetToPost() { server.enqueue(MockResponse()) - val interceptor = Interceptor { chain: Interceptor.Chain -> - val originalRequest = chain.request() - val mediaType = "text/plain".toMediaType() - val body = "abc".toRequestBody(mediaType) - chain.proceed( - originalRequest.newBuilder() - .method("POST", body) - .header("Content-Type", mediaType.toString()) - .header("Content-Length", body.contentLength().toString()) - .build() - ) - } - client = client.newBuilder() - .addNetworkInterceptor(interceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .get() - .build() + val interceptor = + Interceptor { chain: Interceptor.Chain -> + val originalRequest = chain.request() + val mediaType = "text/plain".toMediaType() + val body = "abc".toRequestBody(mediaType) + chain.proceed( + originalRequest.newBuilder() + .method("POST", body) + .header("Content-Type", mediaType.toString()) + .header("Content-Length", body.contentLength().toString()) + .build(), + ) + } + client = + client.newBuilder() + .addNetworkInterceptor(interceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .get() + .build() client.newCall(request).execute() val recordedRequest = server.takeRequest() assertThat(recordedRequest.method).isEqualTo("POST") @@ -277,14 +297,15 @@ class InterceptorTest { originalRequest.newBuilder() .method("POST", uppercase(originalRequest.body)) .addHeader("OkHttp-Intercepted", "yep") - .build() + .build(), ) } - val request = Request.Builder() - .url(server.url("/")) - .addHeader("Original-Header", "foo") - .method("PUT", "abc".toRequestBody("text/plain".toMediaType())) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .addHeader("Original-Header", "foo") + .method("PUT", "abc".toRequestBody("text/plain".toMediaType())) + .build() client.newCall(request).execute() val recordedRequest = server.takeRequest() assertThat(recordedRequest.body.readUtf8()).isEqualTo("ABC") @@ -308,7 +329,7 @@ class InterceptorTest { MockResponse.Builder() .addHeader("Original-Header: foo") .body("abc") - .build() + .build(), ) addInterceptor(network) { chain: Interceptor.Chain -> val originalResponse = chain.proceed(chain.request()) @@ -317,9 +338,10 @@ class InterceptorTest { .addHeader("OkHttp-Intercepted", "yep") .build() } - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("ABC") assertThat(response.header("OkHttp-Intercepted")).isEqualTo("yep") @@ -340,29 +362,32 @@ class InterceptorTest { server.enqueue(MockResponse()) addInterceptor(network) { chain: Interceptor.Chain -> val originalRequest = chain.request() - val originalResponse = chain.proceed( - originalRequest.newBuilder() - .addHeader("Request-Interceptor", "Android") // 1. Added first. - .build() - ) + val originalResponse = + chain.proceed( + originalRequest.newBuilder() + .addHeader("Request-Interceptor", "Android") // 1. Added first. + .build(), + ) originalResponse.newBuilder() .addHeader("Response-Interceptor", "Donut") // 4. Added last. .build() } addInterceptor(network) { chain: Interceptor.Chain -> val originalRequest = chain.request() - val originalResponse = chain.proceed( - originalRequest.newBuilder() - .addHeader("Request-Interceptor", "Bob") // 2. Added second. - .build() - ) + val originalResponse = + chain.proceed( + originalRequest.newBuilder() + .addHeader("Request-Interceptor", "Bob") // 2. Added second. + .build(), + ) originalResponse.newBuilder() .addHeader("Response-Interceptor", "Cupcake") // 3. Added third. .build() } - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val response = client.newCall(request).execute() assertThat(response.headers("Response-Interceptor")) .containsExactly("Cupcake", "Donut") @@ -389,9 +414,10 @@ class InterceptorTest { .addHeader("OkHttp-Intercepted", "yep") .build() } - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() client.newCall(request).enqueue(callback) callback.await(request.url) .assertCode(200) @@ -402,16 +428,20 @@ class InterceptorTest { fun applicationInterceptorsCanMakeMultipleRequestsToServer() { server.enqueue(MockResponse.Builder().body("a").build()) server.enqueue(MockResponse.Builder().body("b").build()) - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - val response1 = chain.proceed(chain.request()) - response1.body.close() - chain.proceed(chain.request()) - }) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + val response1 = chain.proceed(chain.request()) + response1.body.close() + chain.proceed(chain.request()) + }, + ) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val response = client.newCall(request).execute() assertThat("b").isEqualTo(response.body.string()) } @@ -421,21 +451,26 @@ class InterceptorTest { fun interceptorMakesAnUnrelatedRequest() { server.enqueue(MockResponse.Builder().body("a").build()) // Fetched by interceptor. server.enqueue(MockResponse.Builder().body("b").build()) // Fetched directly. - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - if (chain.request().url.encodedPath == "/b") { - val requestA = Request.Builder() - .url(server.url("/a")) - .build() - val responseA = client.newCall(requestA).execute() - assertThat(responseA.body.string()).isEqualTo("a") - } - chain.proceed(chain.request()) - }) - .build() - val requestB = Request.Builder() - .url(server.url("/b")) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + if (chain.request().url.encodedPath == "/b") { + val requestA = + Request.Builder() + .url(server.url("/a")) + .build() + val responseA = client.newCall(requestA).execute() + assertThat(responseA.body.string()).isEqualTo("a") + } + chain.proceed(chain.request()) + }, + ) + .build() + val requestB = + Request.Builder() + .url(server.url("/b")) + .build() val responseB = client.newCall(requestB).execute() assertThat(responseB.body.string()).isEqualTo("b") } @@ -445,26 +480,31 @@ class InterceptorTest { fun interceptorMakesAnUnrelatedAsyncRequest() { server.enqueue(MockResponse.Builder().body("a").build()) // Fetched by interceptor. server.enqueue(MockResponse.Builder().body("b").build()) // Fetched directly. - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - if (chain.request().url.encodedPath == "/b") { - val requestA = Request.Builder() - .url(server.url("/a")) - .build() - try { - val callbackA = RecordingCallback() - client.newCall(requestA).enqueue(callbackA) - callbackA.await(requestA.url).assertBody("a") - } catch (e: Exception) { - throw RuntimeException(e) - } - } - chain.proceed(chain.request()) - }) - .build() - val requestB = Request.Builder() - .url(server.url("/b")) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + if (chain.request().url.encodedPath == "/b") { + val requestA = + Request.Builder() + .url(server.url("/a")) + .build() + try { + val callbackA = RecordingCallback() + client.newCall(requestA).enqueue(callbackA) + callbackA.await(requestA.url).assertBody("a") + } catch (e: Exception) { + throw RuntimeException(e) + } + } + chain.proceed(chain.request()) + }, + ) + .build() + val requestB = + Request.Builder() + .url(server.url("/b")) + .build() val callbackB = RecordingCallback() client.newCall(requestB).enqueue(callbackB) callbackB.await(requestB.url).assertBody("b") @@ -486,9 +526,10 @@ class InterceptorTest { */ private fun interceptorThrowsRuntimeExceptionSynchronous(network: Boolean) { addInterceptor(network) { chain: Interceptor.Chain? -> throw RuntimeException("boom!") } - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() assertFailsWith { client.newCall(request).execute() }.also { expected -> @@ -499,25 +540,29 @@ class InterceptorTest { @Test fun networkInterceptorModifiedRequestIsReturned() { server.enqueue(MockResponse()) - val modifyHeaderInterceptor = Interceptor { chain: Interceptor.Chain -> - val modifiedRequest = chain.request() - .newBuilder() - .header("User-Agent", "intercepted request") + val modifyHeaderInterceptor = + Interceptor { chain: Interceptor.Chain -> + val modifiedRequest = + chain.request() + .newBuilder() + .header("User-Agent", "intercepted request") + .build() + chain.proceed(modifiedRequest) + } + client = + client.newBuilder() + .addNetworkInterceptor(modifyHeaderInterceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .header("User-Agent", "user request") .build() - chain.proceed(modifiedRequest) - } - client = client.newBuilder() - .addNetworkInterceptor(modifyHeaderInterceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .header("User-Agent", "user request") - .build() val response = client.newCall(request).execute() assertThat(response.request.header("User-Agent")).isNotNull() assertThat(response.request.header("User-Agent")).isEqualTo("user request") assertThat(response.networkResponse!!.request.header("User-Agent")).isEqualTo( - "intercepted request" + "intercepted request", ) } @@ -539,12 +584,14 @@ class InterceptorTest { val boom = RuntimeException("boom!") addInterceptor(network) { chain: Interceptor.Chain? -> throw boom } val executor = ExceptionCatchingExecutor() - client = client.newBuilder() - .dispatcher(Dispatcher(executor)) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + client = + client.newBuilder() + .dispatcher(Dispatcher(executor)) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) call.enqueue(callback) val recordedResponse = callback.await(server.url("/")) @@ -563,43 +610,50 @@ class InterceptorTest { MockResponse.Builder() .socketPolicy(DisconnectAtEnd) .addHeader("Connection", "Close") - .build() + .build(), ) - val interceptor = Interceptor { chain: Interceptor.Chain -> - val response = chain.proceed(chain.request()) - assertThat(chain.connection()).isNotNull() - response - } - client = client.newBuilder() - .addNetworkInterceptor(interceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + val interceptor = + Interceptor { chain: Interceptor.Chain -> + val response = chain.proceed(chain.request()) + assertThat(chain.connection()).isNotNull() + response + } + client = + client.newBuilder() + .addNetworkInterceptor(interceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val response = client.newCall(request).execute() response.body.close() } @Test fun connectTimeout() { - val interceptor1 = Interceptor { chainA: Interceptor.Chain -> - assertThat(chainA.connectTimeoutMillis()).isEqualTo(5000) - val chainB = chainA.withConnectTimeout(100, TimeUnit.MILLISECONDS) - assertThat(chainB.connectTimeoutMillis()).isEqualTo(100) - chainB.proceed(chainA.request()) - } - val interceptor2 = Interceptor { chain: Interceptor.Chain -> - assertThat(chain.connectTimeoutMillis()).isEqualTo(100) - chain.proceed(chain.request()) - } - client = client.newBuilder() - .connectTimeout(Duration.ofSeconds(5)) - .addInterceptor(interceptor1) - .addInterceptor(interceptor2) - .build() - val request1 = Request.Builder() - .url("http://" + TestUtil.UNREACHABLE_ADDRESS_IPV4) - .build() + val interceptor1 = + Interceptor { chainA: Interceptor.Chain -> + assertThat(chainA.connectTimeoutMillis()).isEqualTo(5000) + val chainB = chainA.withConnectTimeout(100, TimeUnit.MILLISECONDS) + assertThat(chainB.connectTimeoutMillis()).isEqualTo(100) + chainB.proceed(chainA.request()) + } + val interceptor2 = + Interceptor { chain: Interceptor.Chain -> + assertThat(chain.connectTimeoutMillis()).isEqualTo(100) + chain.proceed(chain.request()) + } + client = + client.newBuilder() + .connectTimeout(Duration.ofSeconds(5)) + .addInterceptor(interceptor1) + .addInterceptor(interceptor2) + .build() + val request1 = + Request.Builder() + .url("http://" + TestUtil.UNREACHABLE_ADDRESS_IPV4) + .build() val call = client.newCall(request1) val startNanos = System.nanoTime() assertFailsWith { @@ -608,36 +662,40 @@ class InterceptorTest { val elapsedNanos = System.nanoTime() - startNanos org.junit.jupiter.api.Assertions.assertTrue( elapsedNanos < TimeUnit.SECONDS.toNanos(5), - "Timeout should have taken ~100ms but was " + elapsedNanos / 1e6 + " ms" + "Timeout should have taken ~100ms but was " + elapsedNanos / 1e6 + " ms", ) } @Test fun chainWithReadTimeout() { - val interceptor1 = Interceptor { chainA: Interceptor.Chain -> - assertThat(chainA.readTimeoutMillis()).isEqualTo(5000) - val chainB = chainA.withReadTimeout(100, TimeUnit.MILLISECONDS) - assertThat(chainB.readTimeoutMillis()).isEqualTo(100) - chainB.proceed(chainA.request()) - } - val interceptor2 = Interceptor { chain: Interceptor.Chain -> - assertThat(chain.readTimeoutMillis()).isEqualTo(100) - chain.proceed(chain.request()) - } - client = client.newBuilder() - .readTimeout(Duration.ofSeconds(5)) - .addInterceptor(interceptor1) - .addInterceptor(interceptor2) - .build() + val interceptor1 = + Interceptor { chainA: Interceptor.Chain -> + assertThat(chainA.readTimeoutMillis()).isEqualTo(5000) + val chainB = chainA.withReadTimeout(100, TimeUnit.MILLISECONDS) + assertThat(chainB.readTimeoutMillis()).isEqualTo(100) + chainB.proceed(chainA.request()) + } + val interceptor2 = + Interceptor { chain: Interceptor.Chain -> + assertThat(chain.readTimeoutMillis()).isEqualTo(100) + chain.proceed(chain.request()) + } + client = + client.newBuilder() + .readTimeout(Duration.ofSeconds(5)) + .addInterceptor(interceptor1) + .addInterceptor(interceptor2) + .build() server.enqueue( MockResponse.Builder() .body("abc") .throttleBody(1, 1, TimeUnit.SECONDS) - .build() + .build(), ) - val request1 = Request.Builder() - .url(server.url("/")) - .build() + val request1 = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request1) val response = call.execute() val body = response.body @@ -651,7 +709,7 @@ class InterceptorTest { addInterceptor(true) { chain: Interceptor.Chain -> chain.withReadTimeout( 100, - TimeUnit.MILLISECONDS + TimeUnit.MILLISECONDS, ).proceed(chain.request()) } val request1 = Request.Builder().url(server.url("/")).build() @@ -669,7 +727,7 @@ class InterceptorTest { addInterceptor(true) { chain: Interceptor.Chain -> chain.withWriteTimeout( 100, - TimeUnit.MILLISECONDS + TimeUnit.MILLISECONDS, ).proceed(chain.request()) } val request1 = Request.Builder().url(server.url("/")).build() @@ -687,7 +745,7 @@ class InterceptorTest { addInterceptor(true) { chain: Interceptor.Chain -> chain.withConnectTimeout( 100, - TimeUnit.MILLISECONDS + TimeUnit.MILLISECONDS, ).proceed(chain.request()) } val request1 = Request.Builder().url(server.url("/")).build() @@ -702,32 +760,36 @@ class InterceptorTest { @Test fun chainWithWriteTimeout() { - val interceptor1 = Interceptor { chainA: Interceptor.Chain -> - assertThat(chainA.writeTimeoutMillis()).isEqualTo(5000) - val chainB = chainA.withWriteTimeout(100, TimeUnit.MILLISECONDS) - assertThat(chainB.writeTimeoutMillis()).isEqualTo(100) - chainB.proceed(chainA.request()) - } - val interceptor2 = Interceptor { chain: Interceptor.Chain -> - assertThat(chain.writeTimeoutMillis()).isEqualTo(100) - chain.proceed(chain.request()) - } - client = client.newBuilder() - .writeTimeout(Duration.ofSeconds(5)) - .addInterceptor(interceptor1) - .addInterceptor(interceptor2) - .build() + val interceptor1 = + Interceptor { chainA: Interceptor.Chain -> + assertThat(chainA.writeTimeoutMillis()).isEqualTo(5000) + val chainB = chainA.withWriteTimeout(100, TimeUnit.MILLISECONDS) + assertThat(chainB.writeTimeoutMillis()).isEqualTo(100) + chainB.proceed(chainA.request()) + } + val interceptor2 = + Interceptor { chain: Interceptor.Chain -> + assertThat(chain.writeTimeoutMillis()).isEqualTo(100) + chain.proceed(chain.request()) + } + client = + client.newBuilder() + .writeTimeout(Duration.ofSeconds(5)) + .addInterceptor(interceptor1) + .addInterceptor(interceptor2) + .build() server.enqueue( MockResponse.Builder() .body("abc") .throttleBody(1, 1, TimeUnit.SECONDS) - .build() + .build(), ) val data = ByteArray(2 * 1024 * 1024) // 2 MiB. - val request1 = Request.Builder() - .url(server.url("/")) - .post(data.toRequestBody("text/plain".toMediaType())) - .build() + val request1 = + Request.Builder() + .url(server.url("/")) + .post(data.toRequestBody("text/plain".toMediaType())) + .build() val call = client.newCall(request1) assertFailsWith { call.execute() // we want this call to throw a SocketTimeoutException @@ -737,20 +799,23 @@ class InterceptorTest { @Test fun chainCanCancelCall() { val callRef = AtomicReference() - val interceptor = Interceptor { chain: Interceptor.Chain -> - val call = chain.call() - callRef.set(call) - assertThat(call.isCanceled()).isFalse() - call.cancel() - assertThat(call.isCanceled()).isTrue() - chain.proceed(chain.request()) - } - client = client.newBuilder() - .addInterceptor(interceptor) - .build() - val request = Request.Builder() - .url(server.url("/")) - .build() + val interceptor = + Interceptor { chain: Interceptor.Chain -> + val call = chain.call() + callRef.set(call) + assertThat(call.isCanceled()).isFalse() + call.cancel() + assertThat(call.isCanceled()).isTrue() + chain.proceed(chain.request()) + } + client = + client.newBuilder() + .addInterceptor(interceptor) + .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) assertFailsWith { call.execute() @@ -779,7 +844,10 @@ class InterceptorTest { private fun uppercase(original: BufferedSink): Sink { return object : ForwardingSink(original) { - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { original.writeUtf8(source.readUtf8(byteCount).uppercase()) } } @@ -793,7 +861,10 @@ class InterceptorTest { return result } - private fun addInterceptor(network: Boolean, interceptor: Interceptor) { + private fun addInterceptor( + network: Boolean, + interceptor: Interceptor, + ) { val builder = client.newBuilder() if (network) { builder.addNetworkInterceptor(interceptor) @@ -807,6 +878,7 @@ class InterceptorTest { private class ExceptionCatchingExecutor : ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, SynchronousQueue()) { private val exceptions: BlockingQueue = LinkedBlockingQueue() + override fun execute(runnable: Runnable) { super.execute { try { @@ -817,7 +889,7 @@ class InterceptorTest { } } - fun takeException(): Exception { + fun takeException(): Exception { return exceptions.take() } } @@ -825,7 +897,7 @@ class InterceptorTest { companion object { fun uppercase(original: ResponseBody): ResponseBody { return object : ResponseBody() { - override fun contentType()= original.contentType() + override fun contentType() = original.contentType() override fun contentLength() = original.contentLength() @@ -835,7 +907,10 @@ class InterceptorTest { private fun uppercase(original: Source): Source { return object : ForwardingSource(original) { - override fun read(sink: Buffer, byteCount: Long): Long { + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { val mixedCase = Buffer() val count = original.read(mixedCase, byteCount) sink.writeUtf8(mixedCase.readUtf8().uppercase()) diff --git a/okhttp/src/test/java/okhttp3/JSSETest.kt b/okhttp/src/test/java/okhttp3/JSSETest.kt index 13f45fb58a55..96f3683df0f2 100644 --- a/okhttp/src/test/java/okhttp3/JSSETest.kt +++ b/okhttp/src/test/java/okhttp3/JSSETest.kt @@ -37,8 +37,11 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension class JSSETest { - @JvmField @RegisterExtension var platform = PlatformRule() - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule() + @JvmField @RegisterExtension + var platform = PlatformRule() + + @JvmField @RegisterExtension + val clientTestRule = OkHttpClientTestRule() private val handshakeCertificates = platform.localhostHandshakeCertificates() @@ -81,7 +84,7 @@ class JSSETest { } assertThat(response.connection.socket().javaClass.name).isEqualTo( - "sun.security.ssl.SSLSocketImpl" + "sun.security.ssl.SSLSocketImpl", ) } } @@ -93,21 +96,29 @@ class JSSETest { val s = factory.createSocket() as SSLSocket when { - PlatformVersion.majorVersion > 11 -> assertThat(s.enabledProtocols.toList()).containsExactly( - "TLSv1.3", "TLSv1.2" - ) + PlatformVersion.majorVersion > 11 -> + assertThat(s.enabledProtocols.toList()).containsExactly( + "TLSv1.3", + "TLSv1.2", + ) // Not much we can guarantee on JDK 11. - PlatformVersion.majorVersion == 11 -> assertThat(s.enabledProtocols.toList()).contains( - "TLSv1.2" - ) + PlatformVersion.majorVersion == 11 -> + assertThat(s.enabledProtocols.toList()).contains( + "TLSv1.2", + ) // JDK 8 291 removed older versions // See https://java.com/en/jre-jdk-cryptoroadmap.html - PlatformVersion.majorVersion == 8 -> assertThat(s.enabledProtocols.toList()).contains( - "TLSv1.2" - ) - else -> assertThat(s.enabledProtocols.toList()).containsExactly( - "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" - ) + PlatformVersion.majorVersion == 8 -> + assertThat(s.enabledProtocols.toList()).contains( + "TLSv1.2", + ) + else -> + assertThat(s.enabledProtocols.toList()).containsExactly( + "TLSv1.3", + "TLSv1.2", + "TLSv1.1", + "TLSv1", + ) } } @@ -118,15 +129,23 @@ class JSSETest { assumeNetwork() - client = client.newBuilder() - .eventListenerFactory(clientTestRule.wrap(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - val sslSocket = connection.socket() as SSLSocket - - sessionIds.add(sslSocket.session.id.toByteString().hex()) - } - })) - .build() + client = + client.newBuilder() + .eventListenerFactory( + clientTestRule.wrap( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + val sslSocket = connection.socket() as SSLSocket + + sessionIds.add(sslSocket.session.id.toByteString().hex()) + } + }, + ), + ) + .build() val request = Request.Builder().url("https://facebook.com/robots.txt").build() @@ -149,11 +168,12 @@ class JSSETest { } private fun enableTls() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } } diff --git a/okhttp/src/test/java/okhttp3/KotlinDeprecationErrorTest.kt b/okhttp/src/test/java/okhttp3/KotlinDeprecationErrorTest.kt index 9962b329f96e..c7063fe5f511 100644 --- a/okhttp/src/test/java/okhttp3/KotlinDeprecationErrorTest.kt +++ b/okhttp/src/test/java/okhttp3/KotlinDeprecationErrorTest.kt @@ -54,10 +54,10 @@ import org.junit.jupiter.api.Test * ensures the symbols remain available and with the expected parameter and return types. */ @Suppress( - "DEPRECATION_ERROR", - "UNUSED_VALUE", - "UNUSED_VARIABLE", - "VARIABLE_WITH_REDUNDANT_INITIALIZER" + "DEPRECATION_ERROR", + "UNUSED_VALUE", + "UNUSED_VARIABLE", + "VARIABLE_WITH_REDUNDANT_INITIALIZER", ) class KotlinDeprecationErrorTest { private val factory = TestValueFactory() @@ -151,7 +151,7 @@ class KotlinDeprecationErrorTest { @Test @Disabled fun handshake() { val handshake: Handshake = - Handshake.get((localhost().sslSocketFactory().createSocket() as SSLSocket).session) + Handshake.get((localhost().sslSocketFactory().createSocket() as SSLSocket).session) val tlsVersion: TlsVersion = handshake.tlsVersion() val cipherSuite: CipherSuite = handshake.cipherSuite() val peerCertificates: List = handshake.peerCertificates() diff --git a/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt b/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt index 0e93e2ef2d9e..2f42bfc9bcbb 100644 --- a/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt +++ b/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt @@ -89,14 +89,14 @@ import org.junit.jupiter.api.Test * modern 4.0.x kotlin source-compatibility. */ @Suppress( - "ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", - "UNUSED_ANONYMOUS_PARAMETER", - "UNUSED_VALUE", - "UNUSED_VARIABLE", - "VARIABLE_WITH_REDUNDANT_INITIALIZER", - "RedundantLambdaArrow", - "RedundantExplicitType", - "IMPLICIT_NOTHING_AS_TYPE_PARAMETER" + "ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", + "UNUSED_ANONYMOUS_PARAMETER", + "UNUSED_VALUE", + "UNUSED_VARIABLE", + "VARIABLE_WITH_REDUNDANT_INITIALIZER", + "RedundantLambdaArrow", + "RedundantExplicitType", + "IMPLICIT_NOTHING_AS_TYPE_PARAMETER", ) @Disabled class KotlinSourceModernTest { @@ -190,10 +190,18 @@ class KotlinSourceModernTest { @Test fun callback() { - val callback = object : Callback { - override fun onFailure(call: Call, e: IOException) = TODO() - override fun onResponse(call: Call, response: Response) = TODO() - } + val callback = + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) = TODO() + + override fun onResponse( + call: Call, + response: Response, + ) = TODO() + } } @Test @@ -234,12 +242,16 @@ class KotlinSourceModernTest { @Test fun connection() { - val connection = object : Connection { - override fun route(): Route = TODO() - override fun socket(): Socket = TODO() - override fun handshake(): Handshake? = TODO() - override fun protocol(): Protocol = TODO() - } + val connection = + object : Connection { + override fun route(): Route = TODO() + + override fun socket(): Socket = TODO() + + override fun handshake(): Handshake? = TODO() + + override fun protocol(): Protocol = TODO() + } } @Test @@ -260,8 +272,10 @@ class KotlinSourceModernTest { val tlsVersions: List? = connectionSpec.tlsVersions val cipherSuites: List? = connectionSpec.cipherSuites val supportsTlsExtensions: Boolean = connectionSpec.supportsTlsExtensions - val compatible: Boolean = connectionSpec.isCompatible( - localhost().sslSocketFactory().createSocket() as SSLSocket) + val compatible: Boolean = + connectionSpec.isCompatible( + localhost().sslSocketFactory().createSocket() as SSLSocket, + ) } @Test @@ -310,10 +324,15 @@ class KotlinSourceModernTest { @Test fun cookieJar() { - val cookieJar = object : CookieJar { - override fun saveFromResponse(url: HttpUrl, cookies: List) = TODO() - override fun loadForRequest(url: HttpUrl): List = TODO() - } + val cookieJar = + object : CookieJar { + override fun saveFromResponse( + url: HttpUrl, + cookies: List, + ) = TODO() + + override fun loadForRequest(url: HttpUrl): List = TODO() + } } @Test @@ -340,11 +359,14 @@ class KotlinSourceModernTest { @Test fun dispatcherFromMockWebServer() { - val dispatcher = object : okhttp3.mockwebserver.Dispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse = TODO() - override fun peek(): MockResponse = TODO() - override fun shutdown() = TODO() - } + val dispatcher = + object : okhttp3.mockwebserver.Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse = TODO() + + override fun peek(): MockResponse = TODO() + + override fun shutdown() = TODO() + } } @Test @@ -356,54 +378,106 @@ class KotlinSourceModernTest { @Test fun eventListener() { - val eventListener = object : EventListener() { - override fun callStart(call: Call) = TODO() - override fun dnsStart(call: Call, domainName: String) = TODO() - override fun dnsEnd( - call: Call, - domainName: String, - inetAddressList: List - ) = TODO() - - override fun connectStart( - call: Call, - inetSocketAddress: InetSocketAddress, - proxy: Proxy - ) = TODO() - - override fun secureConnectStart(call: Call) = TODO() - override fun secureConnectEnd(call: Call, handshake: Handshake?) = TODO() - override fun connectEnd( - call: Call, - inetSocketAddress: InetSocketAddress, - proxy: Proxy, - protocol: Protocol? - ) = TODO() - - override fun connectFailed( - call: Call, - inetSocketAddress: InetSocketAddress, - proxy: Proxy, - protocol: Protocol?, - ioe: IOException - ) = TODO() - - override fun connectionAcquired(call: Call, connection: Connection) = TODO() - override fun connectionReleased(call: Call, connection: Connection) = TODO() - override fun requestHeadersStart(call: Call) = TODO() - override fun requestHeadersEnd(call: Call, request: Request) = TODO() - override fun requestBodyStart(call: Call) = TODO() - override fun requestBodyEnd(call: Call, byteCount: Long) = TODO() - override fun requestFailed(call: Call, ioe: IOException) = TODO() - override fun responseHeadersStart(call: Call) = TODO() - override fun responseHeadersEnd(call: Call, response: Response) = TODO() - override fun responseBodyStart(call: Call) = TODO() - override fun responseBodyEnd(call: Call, byteCount: Long) = TODO() - override fun responseFailed(call: Call, ioe: IOException) = TODO() - override fun callEnd(call: Call) = TODO() - override fun callFailed(call: Call, ioe: IOException) = TODO() - override fun canceled(call: Call) = TODO() - } + val eventListener = + object : EventListener() { + override fun callStart(call: Call) = TODO() + + override fun dnsStart( + call: Call, + domainName: String, + ) = TODO() + + override fun dnsEnd( + call: Call, + domainName: String, + inetAddressList: List, + ) = TODO() + + override fun connectStart( + call: Call, + inetSocketAddress: InetSocketAddress, + proxy: Proxy, + ) = TODO() + + override fun secureConnectStart(call: Call) = TODO() + + override fun secureConnectEnd( + call: Call, + handshake: Handshake?, + ) = TODO() + + override fun connectEnd( + call: Call, + inetSocketAddress: InetSocketAddress, + proxy: Proxy, + protocol: Protocol?, + ) = TODO() + + override fun connectFailed( + call: Call, + inetSocketAddress: InetSocketAddress, + proxy: Proxy, + protocol: Protocol?, + ioe: IOException, + ) = TODO() + + override fun connectionAcquired( + call: Call, + connection: Connection, + ) = TODO() + + override fun connectionReleased( + call: Call, + connection: Connection, + ) = TODO() + + override fun requestHeadersStart(call: Call) = TODO() + + override fun requestHeadersEnd( + call: Call, + request: Request, + ) = TODO() + + override fun requestBodyStart(call: Call) = TODO() + + override fun requestBodyEnd( + call: Call, + byteCount: Long, + ) = TODO() + + override fun requestFailed( + call: Call, + ioe: IOException, + ) = TODO() + + override fun responseHeadersStart(call: Call) = TODO() + + override fun responseHeadersEnd( + call: Call, + response: Response, + ) = TODO() + + override fun responseBodyStart(call: Call) = TODO() + + override fun responseBodyEnd( + call: Call, + byteCount: Long, + ) = TODO() + + override fun responseFailed( + call: Call, + ioe: IOException, + ) = TODO() + + override fun callEnd(call: Call) = TODO() + + override fun callFailed( + call: Call, + ioe: IOException, + ) = TODO() + + override fun canceled(call: Call) = TODO() + } val none: EventListener = EventListener.NONE } @@ -438,14 +512,15 @@ class KotlinSourceModernTest { @Test fun handshake() { var handshake: Handshake = - (localhost().sslSocketFactory().createSocket() as SSLSocket).session.handshake() + (localhost().sslSocketFactory().createSocket() as SSLSocket).session.handshake() val listOfCertificates: List = listOf() - handshake = Handshake.get( + handshake = + Handshake.get( TlsVersion.TLS_1_3, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, listOfCertificates, - listOfCertificates - ) + listOfCertificates, + ) val tlsVersion: TlsVersion = handshake.tlsVersion val cipherSuite: CipherSuite = handshake.cipherSuite val peerCertificates: List = handshake.peerCertificates @@ -666,9 +741,10 @@ class KotlinSourceModernTest { fun loggingEventListenerFactory() { var factory: LoggingEventListener.Factory = LoggingEventListener.Factory() factory = LoggingEventListener.Factory(HttpLoggingInterceptor.Logger.DEFAULT) - factory = object : LoggingEventListener.Factory() { - override fun create(call: Call): EventListener = TODO() - } + factory = + object : LoggingEventListener.Factory() { + override fun create(call: Call): EventListener = TODO() + } val eventListener: EventListener = factory.create(newCall()) } @@ -721,8 +797,11 @@ class KotlinSourceModernTest { mockResponse = mockResponse.withSettings(Settings()) var settings: Settings = mockResponse.settings settings = mockResponse.settings - mockResponse = mockResponse.withWebSocketUpgrade(object : WebSocketListener() { - }) + mockResponse = + mockResponse.withWebSocketUpgrade( + object : WebSocketListener() { + }, + ) var webSocketListener: WebSocketListener? = mockResponse.webSocketListener webSocketListener = mockResponse.webSocketListener } @@ -836,10 +915,12 @@ class KotlinSourceModernTest { val writeTimeoutMillis: Int = client.writeTimeoutMillis val pingIntervalMillis: Int = client.pingIntervalMillis val call: Call = client.newCall(Request.Builder().build()) - val webSocket: WebSocket = client.newWebSocket( + val webSocket: WebSocket = + client.newWebSocket( Request.Builder().build(), object : WebSocketListener() { - }) + }, + ) val newBuilder: OkHttpClient.Builder = client.newBuilder() } @@ -913,8 +994,10 @@ class KotlinSourceModernTest { @Test fun queueDispatcher() { val queueDispatcher = QueueDispatcher() - var mockResponse: MockResponse = queueDispatcher.dispatch( - RecordedRequest("", headersOf(), listOf(), 0L, Buffer(), 0, Socket())) + var mockResponse: MockResponse = + queueDispatcher.dispatch( + RecordedRequest("", headersOf(), listOf(), 0L, Buffer(), 0, Socket()), + ) mockResponse = queueDispatcher.peek() queueDispatcher.enqueueResponse(MockResponse()) queueDispatcher.shutdown() @@ -924,8 +1007,16 @@ class KotlinSourceModernTest { @Test fun recordedRequest() { - var recordedRequest: RecordedRequest = RecordedRequest( - "", headersOf(), listOf(), 0L, Buffer(), 0, Socket()) + var recordedRequest: RecordedRequest = + RecordedRequest( + "", + headersOf(), + listOf(), + 0L, + Buffer(), + 0, + Socket(), + ) recordedRequest = RecordedRequest("", headersOf(), listOf(), 0L, Buffer(), 0, Socket()) var requestUrl: HttpUrl? = recordedRequest.requestUrl var requestLine: String = recordedRequest.requestLine @@ -1001,13 +1092,18 @@ class KotlinSourceModernTest { @Test fun requestBody() { - var requestBody: RequestBody = object : RequestBody() { - override fun contentType(): MediaType? = TODO() - override fun contentLength(): Long = TODO() - override fun isDuplex(): Boolean = TODO() - override fun isOneShot(): Boolean = TODO() - override fun writeTo(sink: BufferedSink) = TODO() - } + var requestBody: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType? = TODO() + + override fun contentLength(): Long = TODO() + + override fun isDuplex(): Boolean = TODO() + + override fun isOneShot(): Boolean = TODO() + + override fun writeTo(sink: BufferedSink) = TODO() + } requestBody = "".toRequestBody(null) requestBody = "".toRequestBody("".toMediaTypeOrNull()) requestBody = ByteString.EMPTY.toRequestBody(null) @@ -1053,12 +1149,15 @@ class KotlinSourceModernTest { builder = builder.protocol(Protocol.HTTP_2) builder = builder.code(0) builder = builder.message("") - builder = builder.handshake(Handshake.get( - TlsVersion.TLS_1_3, - CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - listOf(), - listOf()) - ) + builder = + builder.handshake( + Handshake.get( + TlsVersion.TLS_1_3, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + listOf(), + listOf(), + ), + ) builder = builder.handshake(null) builder = builder.header("", "") builder = builder.addHeader("", "") @@ -1078,12 +1177,16 @@ class KotlinSourceModernTest { @Test fun responseBody() { - var responseBody: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? = TODO() - override fun contentLength(): Long = TODO() - override fun source(): BufferedSource = TODO() - override fun close() = TODO() - } + var responseBody: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? = TODO() + + override fun contentLength(): Long = TODO() + + override fun source(): BufferedSource = TODO() + + override fun close() = TODO() + } val byteStream = responseBody.byteStream() val source = responseBody.source() val bytes = responseBody.bytes() @@ -1123,37 +1226,80 @@ class KotlinSourceModernTest { @Test fun webSocket() { - val webSocket = object : WebSocket { - override fun request(): Request = TODO() - override fun queueSize(): Long = TODO() - override fun send(text: String): Boolean = TODO() - override fun send(bytes: ByteString): Boolean = TODO() - override fun close(code: Int, reason: String?): Boolean = TODO() - override fun cancel() = TODO() - } + val webSocket = + object : WebSocket { + override fun request(): Request = TODO() + + override fun queueSize(): Long = TODO() + + override fun send(text: String): Boolean = TODO() + + override fun send(bytes: ByteString): Boolean = TODO() + + override fun close( + code: Int, + reason: String?, + ): Boolean = TODO() + + override fun cancel() = TODO() + } } @Test fun webSocketListener() { - val webSocketListener = object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) = TODO() - override fun onMessage(webSocket: WebSocket, text: String) = TODO() - override fun onMessage(webSocket: WebSocket, bytes: ByteString) = TODO() - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) = TODO() - override fun onClosed(webSocket: WebSocket, code: Int, reason: String) = TODO() - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) = TODO() - } + val webSocketListener = + object : WebSocketListener() { + override fun onOpen( + webSocket: WebSocket, + response: Response, + ) = TODO() + + override fun onMessage( + webSocket: WebSocket, + text: String, + ) = TODO() + + override fun onMessage( + webSocket: WebSocket, + bytes: ByteString, + ) = TODO() + + override fun onClosing( + webSocket: WebSocket, + code: Int, + reason: String, + ) = TODO() + + override fun onClosed( + webSocket: WebSocket, + code: Int, + reason: String, + ) = TODO() + + override fun onFailure( + webSocket: WebSocket, + t: Throwable, + response: Response?, + ) = TODO() + } } private fun newCall(): Call { return object : Call { override fun request(): Request = TODO() + override fun execute(): Response = TODO() + override fun enqueue(responseCallback: Callback) = TODO() + override fun cancel() = TODO() + override fun isExecuted(): Boolean = TODO() + override fun isCanceled(): Boolean = TODO() + override fun timeout(): Timeout = TODO() + override fun clone(): Call = TODO() } } @@ -1162,12 +1308,12 @@ class KotlinSourceModernTest { return object : CookieHandler() { override fun put( uri: URI?, - responseHeaders: MutableMap>? + responseHeaders: MutableMap>?, ) = TODO() override fun get( uri: URI?, - requestHeaders: MutableMap>? + requestHeaders: MutableMap>?, ): MutableMap> = TODO() } } @@ -1175,15 +1321,33 @@ class KotlinSourceModernTest { private fun newInterceptorChain(): Interceptor.Chain { return object : Interceptor.Chain { override fun request(): Request = TODO() + override fun proceed(request: Request): Response = TODO() + override fun connection(): Connection? = TODO() + override fun call(): Call = TODO() + override fun connectTimeoutMillis(): Int = TODO() - override fun withConnectTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() + + override fun withConnectTimeout( + timeout: Int, + unit: TimeUnit, + ): Interceptor.Chain = TODO() + override fun readTimeoutMillis(): Int = TODO() - override fun withReadTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() + + override fun withReadTimeout( + timeout: Int, + unit: TimeUnit, + ): Interceptor.Chain = TODO() + override fun writeTimeoutMillis(): Int = TODO() - override fun withWriteTimeout(timeout: Int, unit: TimeUnit): Interceptor.Chain = TODO() + + override fun withWriteTimeout( + timeout: Int, + unit: TimeUnit, + ): Interceptor.Chain = TODO() } } } diff --git a/okhttp/src/test/java/okhttp3/LoomTest.kt b/okhttp/src/test/java/okhttp3/LoomTest.kt index 58091c25b8b9..66c75c07c668 100644 --- a/okhttp/src/test/java/okhttp3/LoomTest.kt +++ b/okhttp/src/test/java/okhttp3/LoomTest.kt @@ -31,6 +31,7 @@ class LoomTest { @JvmField @RegisterExtension val platform = PlatformRule() + @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule() @@ -40,16 +41,15 @@ class LoomTest { private lateinit var client: OkHttpClient @BeforeEach - fun setUp( - server: MockWebServer, - ) { + fun setUp(server: MockWebServer) { platform.assumeLoom() this.server = server - client = clientTestRule.newClientBuilder() - .dispatcher(Dispatcher(newVirtualThreadPerTaskExecutor())) - .build() + client = + clientTestRule.newClientBuilder() + .dispatcher(Dispatcher(newVirtualThreadPerTaskExecutor())) + .build() } private fun newVirtualThreadPerTaskExecutor(): ExecutorService { diff --git a/okhttp/src/test/java/okhttp3/MediaTypeGetTest.kt b/okhttp/src/test/java/okhttp3/MediaTypeGetTest.kt index 0aa5b580c103..a21b9685af82 100644 --- a/okhttp/src/test/java/okhttp3/MediaTypeGetTest.kt +++ b/okhttp/src/test/java/okhttp3/MediaTypeGetTest.kt @@ -22,10 +22,14 @@ import okhttp3.MediaType.Companion.toMediaType open class MediaTypeGetTest : MediaTypeTest() { override fun parse(string: String): MediaType = string.toMediaType() - override fun assertInvalid(string: String, exceptionMessage: String?) { - val e = assertFailsWith { - parse(string) - } + override fun assertInvalid( + string: String, + exceptionMessage: String?, + ) { + val e = + assertFailsWith { + parse(string) + } assertEquals(exceptionMessage, e.message) } } diff --git a/okhttp/src/test/java/okhttp3/MediaTypeJvmTest.kt b/okhttp/src/test/java/okhttp3/MediaTypeJvmTest.kt index ee2b5b93c540..67cf2ce5e83e 100644 --- a/okhttp/src/test/java/okhttp3/MediaTypeJvmTest.kt +++ b/okhttp/src/test/java/okhttp3/MediaTypeJvmTest.kt @@ -22,7 +22,7 @@ import okhttp3.MediaType.Companion.toMediaType import okhttp3.internal.platform.Platform.Companion.isAndroid import org.junit.jupiter.api.Test -class MediaTypeJvmTest: MediaTypeGetTest() { +class MediaTypeJvmTest : MediaTypeGetTest() { override fun MediaType.charsetName(): String? = this.charset()?.name() @Test fun testCharsetNameIsDoubleQuotedAndSingleQuotedAndroid() { @@ -38,17 +38,21 @@ class MediaTypeJvmTest: MediaTypeGetTest() { @Test fun testDefaultCharset() { val noCharset = parse("text/plain") assertEquals( - "UTF-8", noCharset.charset(Charsets.UTF_8)!!.name() + "UTF-8", + noCharset.charset(Charsets.UTF_8)!!.name(), ) assertEquals( - "US-ASCII", noCharset.charset(Charsets.US_ASCII)!!.name() + "US-ASCII", + noCharset.charset(Charsets.US_ASCII)!!.name(), ) val charset = parse("text/plain; charset=iso-8859-1") assertEquals( - "ISO-8859-1", charset.charset(Charsets.UTF_8)!!.name() + "ISO-8859-1", + charset.charset(Charsets.UTF_8)!!.name(), ) assertEquals( - "ISO-8859-1", charset.charset(Charsets.US_ASCII)!!.name() + "ISO-8859-1", + charset.charset(Charsets.US_ASCII)!!.name(), ) } @@ -68,7 +72,10 @@ class MediaTypeJvmTest: MediaTypeGetTest() { } } - private fun withLocale(locale: Locale, block: () -> T): T { + private fun withLocale( + locale: Locale, + block: () -> T, + ): T { val previous = Locale.getDefault() try { Locale.setDefault(locale) diff --git a/okhttp/src/test/java/okhttp3/MediaTypeTest.kt b/okhttp/src/test/java/okhttp3/MediaTypeTest.kt index 77e20e04b9e7..65ce7d3a0393 100644 --- a/okhttp/src/test/java/okhttp3/MediaTypeTest.kt +++ b/okhttp/src/test/java/okhttp3/MediaTypeTest.kt @@ -32,7 +32,10 @@ open class MediaTypeTest { protected open fun parse(string: String): MediaType = string.toMediaTypeOrNull()!! - protected open fun assertInvalid(string: String, exceptionMessage: String?) { + protected open fun assertInvalid( + string: String, + exceptionMessage: String?, + ) { assertNull(string.toMediaTypeOrNull(), exceptionMessage) } @@ -45,7 +48,7 @@ open class MediaTypeTest { assertEquals(mediaType, parse("text/plain;boundary=foo;charset=utf-8")) assertEquals( mediaType.hashCode(), - parse("text/plain;boundary=foo;charset=utf-8").hashCode() + parse("text/plain;boundary=foo;charset=utf-8").hashCode(), ) } @@ -79,47 +82,47 @@ open class MediaTypeTest { assertInvalid("text/ plain", "No subtype found for: \"text/ plain\"") assertInvalid( "text/pl@in", - "Parameter is not formatted correctly: \"@in\" for: \"text/pl@in\"" + "Parameter is not formatted correctly: \"@in\" for: \"text/pl@in\"", ) assertInvalid( "text/plain; a", - "Parameter is not formatted correctly: \"a\" for: \"text/plain; a\"" + "Parameter is not formatted correctly: \"a\" for: \"text/plain; a\"", ) assertInvalid( "text/plain; a=", - "Parameter is not formatted correctly: \"a=\" for: \"text/plain; a=\"" + "Parameter is not formatted correctly: \"a=\" for: \"text/plain; a=\"", ) assertInvalid( "text/plain; a=@", - "Parameter is not formatted correctly: \"a=@\" for: \"text/plain; a=@\"" + "Parameter is not formatted correctly: \"a=@\" for: \"text/plain; a=@\"", ) assertInvalid( "text/plain; a=\"@", - "Parameter is not formatted correctly: \"a=\"@\" for: \"text/plain; a=\"@\"" + "Parameter is not formatted correctly: \"a=\"@\" for: \"text/plain; a=\"@\"", ) assertInvalid( "text/plain; a=1; b", - "Parameter is not formatted correctly: \"b\" for: \"text/plain; a=1; b\"" + "Parameter is not formatted correctly: \"b\" for: \"text/plain; a=1; b\"", ) assertInvalid( "text/plain; a=1; b=", - "Parameter is not formatted correctly: \"b=\" for: \"text/plain; a=1; b=\"" + "Parameter is not formatted correctly: \"b=\" for: \"text/plain; a=1; b=\"", ) assertInvalid( "text/plain; a=\u2025", - "Parameter is not formatted correctly: \"a=‥\" for: \"text/plain; a=‥\"" + "Parameter is not formatted correctly: \"a=‥\" for: \"text/plain; a=‥\"", ) assertInvalid( "text/pl ain", - "Parameter is not formatted correctly: \" ain\" for: \"text/pl ain\"" + "Parameter is not formatted correctly: \" ain\" for: \"text/pl ain\"", ) assertInvalid( "text/plain ", - "Parameter is not formatted correctly: \" \" for: \"text/plain \"" + "Parameter is not formatted correctly: \" \" for: \"text/plain \"", ) assertInvalid( "text/plain ; a=1", - "Parameter is not formatted correctly: \" ; a=1\" for: \"text/plain ; a=1\"" + "Parameter is not formatted correctly: \" ; a=1\" for: \"text/plain ; a=1\"", ) } @@ -204,6 +207,7 @@ open class MediaTypeTest { val mediaType = parse("multipart/mixed; number=2; number=3") assertEquals("2", mediaType.parameter("number")) } + private fun assertMediaType(string: String) { assertEquals(string, parse(string).toString()) } diff --git a/okhttp/src/test/java/okhttp3/MultipartBodyTest.kt b/okhttp/src/test/java/okhttp3/MultipartBodyTest.kt index eafa23a5d959..59430a255599 100644 --- a/okhttp/src/test/java/okhttp3/MultipartBodyTest.kt +++ b/okhttp/src/test/java/okhttp3/MultipartBodyTest.kt @@ -42,16 +42,18 @@ class MultipartBodyTest { @Test fun singlePart() { - val expected = """ + val expected = + """ |--123 | |Hello, World! |--123-- | """.trimMargin().replace("\n", "\r\n") - val body = MultipartBody.Builder("123") - .addPart("Hello, World!".toRequestBody(null)) - .build() + val body = + MultipartBody.Builder("123") + .addPart("Hello, World!".toRequestBody(null)) + .build() assertThat(body.boundary).isEqualTo("123") assertThat(body.type).isEqualTo(MultipartBody.MIXED) assertThat(body.contentType().toString()) @@ -66,7 +68,8 @@ class MultipartBodyTest { @Test fun threeParts() { - val expected = """ + val expected = + """ |--123 | |Quick @@ -79,11 +82,12 @@ class MultipartBodyTest { |--123-- | """.trimMargin().replace("\n", "\r\n") - val body = MultipartBody.Builder("123") - .addPart("Quick".toRequestBody(null)) - .addPart("Brown".toRequestBody(null)) - .addPart("Fox".toRequestBody(null)) - .build() + val body = + MultipartBody.Builder("123") + .addPart("Quick".toRequestBody(null)) + .addPart("Brown".toRequestBody(null)) + .addPart("Fox".toRequestBody(null)) + .build() assertThat(body.boundary).isEqualTo("123") assertThat(body.type).isEqualTo(MultipartBody.MIXED) assertThat(body.contentType().toString()) @@ -98,7 +102,8 @@ class MultipartBodyTest { @Test fun fieldAndTwoFiles() { - val expected = """ + val expected = + """ |--AaB03x |Content-Disposition: form-data; name="submit-name" | @@ -123,31 +128,35 @@ class MultipartBodyTest { |--AaB03x-- | """.trimMargin().replace("\n", "\r\n") - val body = MultipartBody.Builder("AaB03x") - .setType(MultipartBody.FORM) - .addFormDataPart("submit-name", "Larry") - .addFormDataPart( - "files", null, - MultipartBody.Builder("BbC04y") - .addPart( - headersOf("Content-Disposition", "file; filename=\"file1.txt\""), - "... contents of file1.txt ...".toRequestBody("text/plain".toMediaType()) - ) - .addPart( - headersOf( - "Content-Disposition", "file; filename=\"file2.gif\"", - "Content-Transfer-Encoding", "binary" - ), - "... contents of file2.gif ...".toByteArray(StandardCharsets.UTF_8) - .toRequestBody("image/gif".toMediaType()) - ) - .build() - ) - .build() + val body = + MultipartBody.Builder("AaB03x") + .setType(MultipartBody.FORM) + .addFormDataPart("submit-name", "Larry") + .addFormDataPart( + "files", + null, + MultipartBody.Builder("BbC04y") + .addPart( + headersOf("Content-Disposition", "file; filename=\"file1.txt\""), + "... contents of file1.txt ...".toRequestBody("text/plain".toMediaType()), + ) + .addPart( + headersOf( + "Content-Disposition", + "file; filename=\"file2.gif\"", + "Content-Transfer-Encoding", + "binary", + ), + "... contents of file2.gif ...".toByteArray(StandardCharsets.UTF_8) + .toRequestBody("image/gif".toMediaType()), + ) + .build(), + ) + .build() assertThat(body.boundary).isEqualTo("AaB03x") assertThat(body.type).isEqualTo(MultipartBody.FORM) assertThat(body.contentType().toString()).isEqualTo( - "multipart/form-data; boundary=AaB03x" + "multipart/form-data; boundary=AaB03x", ) assertThat(body.parts.size).isEqualTo(2) assertThat(body.contentLength()).isEqualTo(488L) @@ -159,7 +168,8 @@ class MultipartBodyTest { @Test fun stringEscapingIsWeird() { - val expected = """ + val expected = + """ |--AaB03x |Content-Disposition: form-data; name="field with spaces"; filename="filename with spaces.txt" |Content-Type: text/plain; charset=utf-8 @@ -180,16 +190,18 @@ class MultipartBodyTest { |--AaB03x-- | """.trimMargin().replace("\n", "\r\n") - val body = MultipartBody.Builder("AaB03x") - .setType(MultipartBody.FORM) - .addFormDataPart( - "field with spaces", "filename with spaces.txt", - "okay".toRequestBody("text/plain; charset=utf-8".toMediaType()) - ) - .addFormDataPart("field with \"", "\"") - .addFormDataPart("field with %22", "%22") - .addFormDataPart("field with \u007e", "Alpha") - .build() + val body = + MultipartBody.Builder("AaB03x") + .setType(MultipartBody.FORM) + .addFormDataPart( + "field with spaces", + "filename with spaces.txt", + "okay".toRequestBody("text/plain; charset=utf-8".toMediaType()), + ) + .addFormDataPart("field with \"", "\"") + .addFormDataPart("field with %22", "%22") + .addFormDataPart("field with \u007e", "Alpha") + .build() val buffer = Buffer() body.writeTo(buffer) assertThat(buffer.readUtf8()).isEqualTo(expected) @@ -208,7 +220,8 @@ class MultipartBodyTest { } } - val expected = """ + val expected = + """ |--123 | |Quick @@ -221,11 +234,12 @@ class MultipartBodyTest { |--123-- | """.trimMargin().replace("\n", "\r\n") - val body = MultipartBody.Builder("123") - .addPart("Quick".toRequestBody(null)) - .addPart(StreamingBody("Brown")) - .addPart("Fox".toRequestBody(null)) - .build() + val body = + MultipartBody.Builder("123") + .addPart("Quick".toRequestBody(null)) + .addPart(StreamingBody("Brown")) + .addPart("Fox".toRequestBody(null)) + .build() assertThat(body.boundary).isEqualTo("123") assertThat(body.type).isEqualTo(MultipartBody.MIXED) assertThat(body.contentType().toString()) @@ -243,7 +257,7 @@ class MultipartBodyTest { assertFailsWith { multipart.addPart( headersOf("Content-Type", "text/plain"), - "Hello, World!".toRequestBody(null) + "Hello, World!".toRequestBody(null), ) } } @@ -254,7 +268,7 @@ class MultipartBodyTest { assertFailsWith { multipart.addPart( headersOf("Content-Length", "13"), - "Hello, World!".toRequestBody(null) + "Hello, World!".toRequestBody(null), ) } } @@ -262,9 +276,10 @@ class MultipartBodyTest { @Test @Throws(IOException::class) fun partAccessors() { - val body = MultipartBody.Builder() - .addPart(headersOf("Foo", "Bar"), "Baz".toRequestBody(null)) - .build() + val body = + MultipartBody.Builder() + .addPart(headersOf("Foo", "Bar"), "Baz".toRequestBody(null)) + .build() assertThat(body.parts.size).isEqualTo(1) val part1Buffer = Buffer() val part1 = body.part(0) @@ -275,7 +290,8 @@ class MultipartBodyTest { @Test fun nonAsciiFilename() { - val expected = """ + val expected = + """ |--AaB03x |Content-Disposition: form-data; name="attachment"; filename="resumé.pdf" |Content-Type: application/pdf; charset=utf-8 @@ -284,13 +300,15 @@ class MultipartBodyTest { |--AaB03x-- | """.trimMargin().replace("\n", "\r\n") - val body = MultipartBody.Builder("AaB03x") - .setType(MultipartBody.FORM) - .addFormDataPart( - "attachment", "resumé.pdf", - "Jesse’s Resumé".toRequestBody("application/pdf".toMediaTypeOrNull()) - ) - .build() + val body = + MultipartBody.Builder("AaB03x") + .setType(MultipartBody.FORM) + .addFormDataPart( + "attachment", + "resumé.pdf", + "Jesse’s Resumé".toRequestBody("application/pdf".toMediaTypeOrNull()), + ) + .build() val buffer = Buffer() body.writeTo(buffer) assertThat(buffer.readUtf8()).isEqualTo(expected) @@ -298,16 +316,18 @@ class MultipartBodyTest { @Test fun writeTwice() { - val expected = """ + val expected = + """ |--123 | |Hello, World! |--123-- | """.trimMargin().replace("\n", "\r\n") - val body = MultipartBody.Builder("123") - .addPart("Hello, World!".toRequestBody(null)) - .build() + val body = + MultipartBody.Builder("123") + .addPart("Hello, World!".toRequestBody(null)) + .build() assertThat(body.isOneShot()).isEqualTo(false) @@ -324,16 +344,18 @@ class MultipartBodyTest { @Test fun writeTwiceWithOneShot() { - val expected = """ + val expected = + """ |--123 | |Hello, World! |--123-- | """.trimMargin().replace("\n", "\r\n") - val body = MultipartBody.Builder("123") - .addPart("Hello, World!".toOneShotRequestBody()) - .build() + val body = + MultipartBody.Builder("123") + .addPart("Hello, World!".toOneShotRequestBody()) + .build() assertThat(body.isOneShot()).isEqualTo(true) diff --git a/okhttp/src/test/java/okhttp3/MultipartReaderTest.kt b/okhttp/src/test/java/okhttp3/MultipartReaderTest.kt index b7fe06c703cf..cd0b7dcb3e88 100644 --- a/okhttp/src/test/java/okhttp3/MultipartReaderTest.kt +++ b/okhttp/src/test/java/okhttp3/MultipartReaderTest.kt @@ -22,58 +22,63 @@ import assertk.assertions.isNotNull import assertk.assertions.isNull import java.io.EOFException import java.net.ProtocolException +import kotlin.test.assertFailsWith import okhttp3.Headers.Companion.headersOf import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.ResponseBody.Companion.toResponseBody import okio.Buffer -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test @Tag("Slowish") class MultipartReaderTest { @Test fun `parse multipart`() { - val multipart = """ - |--simple boundary - |Content-Type: text/plain; charset=utf-8 - |Content-ID: abc - | - |abcd - |efgh - |--simple boundary - |Content-Type: text/plain; charset=utf-8 - |Content-ID: ijk - | - |ijkl - |mnop - | - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + |Content-Type: text/plain; charset=utf-8 + |Content-ID: abc + | + |abcd + |efgh + |--simple boundary + |Content-Type: text/plain; charset=utf-8 + |Content-ID: ijk + | + |ijkl + |mnop + | + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) assertThat(parts.boundary).isEqualTo("simple boundary") val partAbc = parts.nextPart()!! assertThat(partAbc.headers).isEqualTo( headersOf( - "Content-Type", "text/plain; charset=utf-8", - "Content-ID", "abc" - ) + "Content-Type", + "text/plain; charset=utf-8", + "Content-ID", + "abc", + ), ) assertThat(partAbc.body.readUtf8()).isEqualTo("abcd\r\nefgh") val partIjk = parts.nextPart()!! assertThat(partIjk.headers).isEqualTo( headersOf( - "Content-Type", "text/plain; charset=utf-8", - "Content-ID", "ijk" - ) + "Content-Type", + "text/plain; charset=utf-8", + "Content-ID", + "ijk", + ), ) assertThat(partIjk.body.readUtf8()).isEqualTo("ijkl\r\nmnop\r\n") @@ -81,17 +86,19 @@ class MultipartReaderTest { } @Test fun `parse from response body`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val responseBody = multipart.toResponseBody( - "application/multipart; boundary=\"simple boundary\"".toMediaType() - ) + val responseBody = + multipart.toResponseBody( + "application/multipart; boundary=\"simple boundary\"".toMediaType(), + ) val parts = MultipartReader(responseBody) assertThat(parts.boundary).isEqualTo("simple boundary") @@ -103,18 +110,21 @@ class MultipartReaderTest { } @Test fun `truncated multipart`() { - val multipart = """ - |--simple boundary - | - |abcd - |efgh - |""".trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |efgh + | + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val part = parts.nextPart()!! assertFailsWith { @@ -127,16 +137,19 @@ class MultipartReaderTest { } @Test fun `malformed headers`() { - val multipart = """ - |--simple boundary - |abcd - |""".trimMargin() + val multipart = + """ + |--simple boundary + |abcd + | + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) assertFailsWith { parts.nextPart() @@ -144,22 +157,24 @@ class MultipartReaderTest { } @Test fun `lf instead of crlf boundary is not honored`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundary - | - |efgh - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundary + | + |efgh + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") .replace(Regex("(?m)abcd\r\n"), "abcd\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val part = parts.nextPart()!! assertThat(part.body.readUtf8()).isEqualTo("abcd\n--simple boundary\r\n\r\nefgh") @@ -168,21 +183,23 @@ class MultipartReaderTest { } @Test fun `partial boundary is not honored`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundar - | - |efgh - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundar + | + |efgh + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val part = parts.nextPart()!! assertThat(part.body.readUtf8()).isEqualTo("abcd\r\n--simple boundar\r\n\r\nefgh") @@ -191,23 +208,25 @@ class MultipartReaderTest { } @Test fun `do not need to read entire part`() { - val multipart = """ - |--simple boundary - | - |abcd - |efgh - |ijkl - |--simple boundary - | - |mnop - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |efgh + |ijkl + |--simple boundary + | + |mnop + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) parts.nextPart()!! val partMno = parts.nextPart()!! @@ -217,23 +236,25 @@ class MultipartReaderTest { } @Test fun `cannot read part after calling nextPart`() { - val multipart = """ - |--simple boundary - | - |abcd - |efgh - |ijkl - |--simple boundary - | - |mnop - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |efgh + |ijkl + |--simple boundary + | + |mnop + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val partAbc = parts.nextPart()!! val partMno = parts.nextPart()!! @@ -249,18 +270,20 @@ class MultipartReaderTest { } @Test fun `cannot read part after calling close`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val part = parts.nextPart()!! parts.close() @@ -273,10 +296,11 @@ class MultipartReaderTest { } @Test fun `cannot call nextPart after calling close`() { - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer() - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer(), + ) parts.close() @@ -288,15 +312,17 @@ class MultipartReaderTest { } @Test fun `zero parts`() { - val multipart = """ - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) assertFailsWith { parts.nextPart() @@ -306,20 +332,22 @@ class MultipartReaderTest { } @Test fun `skip preamble`() { - val multipart = """ - |this is the preamble! it is invisible to application code - | - |--simple boundary - | - |abcd - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |this is the preamble! it is invisible to application code + | + |--simple boundary + | + |abcd + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val part = parts.nextPart()!! assertThat(part.headers).isEqualTo(headersOf()) @@ -329,19 +357,22 @@ class MultipartReaderTest { } @Test fun `skip epilogue`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundary-- - |this is the epilogue! it is also invisible to application code - |""".trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundary-- + |this is the epilogue! it is also invisible to application code + | + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val part = parts.nextPart()!! assertThat(part.headers).isEqualTo(headersOf()) @@ -351,19 +382,21 @@ class MultipartReaderTest { } @Test fun `skip whitespace after boundary`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundary-- + """.trimMargin() .replace(Regex("(?m)simple boundary$"), "simple boundary \t \t") .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val part = parts.nextPart()!! assertThat(part.headers).isEqualTo(headersOf()) @@ -373,19 +406,21 @@ class MultipartReaderTest { } @Test fun `skip whitespace after close delimiter`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundary-- + """.trimMargin() .replace(Regex("(?m)simple boundary--$"), "simple boundary-- \t \t") .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) val part = parts.nextPart()!! assertThat(part.headers).isEqualTo(headersOf()) @@ -395,16 +430,18 @@ class MultipartReaderTest { } @Test fun `other characters after boundary`() { - val multipart = """ - |--simple boundary hi - """.trimMargin() + val multipart = + """ + |--simple boundary hi + """.trimMargin() .replace(Regex("(?m)simple boundary$"), "simple boundary ") .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) assertFailsWith { parts.nextPart() @@ -414,18 +451,20 @@ class MultipartReaderTest { } @Test fun `whitespace before close delimiter`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundary -- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundary -- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) parts.nextPart() assertFailsWith { @@ -437,23 +476,25 @@ class MultipartReaderTest { /** The documentation advises that '-' is the simplest boundary possible. */ @Test fun `dash boundary`() { - val multipart = """ - |--- - |Content-ID: abc - | - |abcd - |--- - |Content-ID: efg - | - |efgh - |----- - """.trimMargin() + val multipart = + """ + |--- + |Content-ID: abc + | + |abcd + |--- + |Content-ID: efg + | + |efgh + |----- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "-", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "-", + source = Buffer().writeUtf8(multipart), + ) val partAbc = parts.nextPart()!! assertThat(partAbc.headers).isEqualTo(headersOf("Content-ID", "abc")) @@ -467,21 +508,23 @@ class MultipartReaderTest { } @Test fun `no more parts is idempotent`() { - val multipart = """ - |--simple boundary - | - |abcd - |--simple boundary-- - | - |efgh - |--simple boundary-- - """.trimMargin() + val multipart = + """ + |--simple boundary + | + |abcd + |--simple boundary-- + | + |efgh + |--simple boundary-- + """.trimMargin() .replace("\n", "\r\n") - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer().writeUtf8(multipart) - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer().writeUtf8(multipart), + ) assertThat(parts.nextPart()).isNotNull() assertThat(parts.nextPart()).isNull() @@ -489,10 +532,11 @@ class MultipartReaderTest { } @Test fun `empty source`() { - val parts = MultipartReader( - boundary = "simple boundary", - source = Buffer() - ) + val parts = + MultipartReader( + boundary = "simple boundary", + source = Buffer(), + ) assertFailsWith { parts.nextPart() @@ -501,7 +545,8 @@ class MultipartReaderTest { /** Confirm that [MultipartBody] and [MultipartReader] can work together. */ @Test fun `multipart round trip`() { - val body = MultipartBody.Builder("boundary") + val body = + MultipartBody.Builder("boundary") .setType(MultipartBody.PARALLEL) .addPart("Quick".toRequestBody("text/plain".toMediaType())) .addFormDataPart("color", "Brown") @@ -516,24 +561,27 @@ class MultipartReaderTest { val quickPart = reader.nextPart()!! assertThat(quickPart.headers).isEqualTo( headersOf( - "Content-Type", "text/plain; charset=utf-8", - ) + "Content-Type", + "text/plain; charset=utf-8", + ), ) assertThat(quickPart.body.readUtf8()).isEqualTo("Quick") val brownPart = reader.nextPart()!! assertThat(brownPart.headers).isEqualTo( headersOf( - "Content-Disposition", "form-data; name=\"color\"", - ) + "Content-Disposition", + "form-data; name=\"color\"", + ), ) assertThat(brownPart.body.readUtf8()).isEqualTo("Brown") val foxPart = reader.nextPart()!! assertThat(foxPart.headers).isEqualTo( headersOf( - "Content-Disposition", "form-data; name=\"animal\"; filename=\"fox.txt\"", - ) + "Content-Disposition", + "form-data; name=\"animal\"; filename=\"fox.txt\"", + ), ) assertThat(foxPart.body.readUtf8()).isEqualTo("Fox") diff --git a/okhttp/src/test/java/okhttp3/OkHttpClientTest.kt b/okhttp/src/test/java/okhttp3/OkHttpClientTest.kt index 9492784aa451..8bc455b09692 100644 --- a/okhttp/src/test/java/okhttp3/OkHttpClientTest.kt +++ b/okhttp/src/test/java/okhttp3/OkHttpClientTest.kt @@ -34,6 +34,7 @@ import java.time.Duration import java.util.AbstractList import javax.net.ssl.SSLSession import javax.net.ssl.SSLSocketFactory +import kotlin.test.assertFailsWith import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import okhttp3.internal.platform.Platform.Companion.get @@ -43,8 +44,6 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNotSame import org.junit.jupiter.api.Assertions.assertSame -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @@ -119,9 +118,10 @@ class OkHttpClientTest { } @Test fun clonedInterceptorsListsAreIndependent() { - val interceptor = Interceptor { chain: Interceptor.Chain -> - chain.proceed(chain.request()) - } + val interceptor = + Interceptor { chain: Interceptor.Chain -> + chain.proceed(chain.request()) + } val original = clientTestRule.newClient() original.newBuilder() .addInterceptor(interceptor) @@ -192,8 +192,8 @@ class OkHttpClientTest { .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE, Protocol.HTTP_1_1)) }.also { expected -> assertThat(expected.message).isEqualTo( - "protocols containing h2_prior_knowledge cannot use other protocols: " - + "[h2_prior_knowledge, http/1.1]" + "protocols containing h2_prior_knowledge cannot use other protocols: " + + "[h2_prior_knowledge, http/1.1]", ) } } @@ -204,16 +204,17 @@ class OkHttpClientTest { .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE, Protocol.H2_PRIOR_KNOWLEDGE)) }.also { expected -> assertThat(expected.message).isEqualTo( - "protocols containing h2_prior_knowledge cannot use other protocols: " - + "[h2_prior_knowledge, h2_prior_knowledge]" + "protocols containing h2_prior_knowledge cannot use other protocols: " + + "[h2_prior_knowledge, h2_prior_knowledge]", ) } } @Test fun testH2PriorKnowledgeOkHttpClientConstructionSuccess() { - val okHttpClient = OkHttpClient.Builder() - .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) - .build() + val okHttpClient = + OkHttpClient.Builder() + .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) + .build() assertThat(okHttpClient.protocols.size).isEqualTo(1) assertThat(okHttpClient.protocols[0]).isEqualTo(Protocol.H2_PRIOR_KNOWLEDGE) } @@ -235,43 +236,48 @@ class OkHttpClientTest { } @Test fun noSslSocketFactoryConfigured() { - val client = OkHttpClient.Builder() - .connectionSpecs(listOf(ConnectionSpec.CLEARTEXT)) - .build() + val client = + OkHttpClient.Builder() + .connectionSpecs(listOf(ConnectionSpec.CLEARTEXT)) + .build() assertFailsWith { client.sslSocketFactory } } @Test fun nullHostileProtocolList() { - val nullHostileProtocols = object : AbstractList() { - override val size: Int = 1 - - override fun get(index: Int) = Protocol.HTTP_1_1 - - override fun contains(element: Protocol?): Boolean { - if (element == null) throw NullPointerException() - return super.contains(element) - } - - override fun indexOf(element: Protocol?): Int { - if (element == null) throw NullPointerException() - return super.indexOf(element) - } - } as List - val client = OkHttpClient.Builder() - .protocols(nullHostileProtocols) - .build() + val nullHostileProtocols = + object : AbstractList() { + override val size: Int = 1 + + override fun get(index: Int) = Protocol.HTTP_1_1 + + override fun contains(element: Protocol?): Boolean { + if (element == null) throw NullPointerException() + return super.contains(element) + } + + override fun indexOf(element: Protocol?): Int { + if (element == null) throw NullPointerException() + return super.indexOf(element) + } + } as List + val client = + OkHttpClient.Builder() + .protocols(nullHostileProtocols) + .build() assertEquals( - listOf(Protocol.HTTP_1_1), client.protocols + listOf(Protocol.HTTP_1_1), + client.protocols, ) } @Test fun nullProtocolInList() { - val protocols = mutableListOf( - Protocol.HTTP_1_1, - null - ) + val protocols = + mutableListOf( + Protocol.HTTP_1_1, + null, + ) assertFailsWith { OkHttpClient.Builder() .protocols(protocols as List) @@ -281,13 +287,15 @@ class OkHttpClientTest { } @Test fun spdy3IsRemovedFromProtocols() { - val protocols = mutableListOf( - Protocol.HTTP_1_1, - Protocol.SPDY_3 - ) - val client = OkHttpClient.Builder() - .protocols(protocols) - .build() + val protocols = + mutableListOf( + Protocol.HTTP_1_1, + Protocol.SPDY_3, + ) + val client = + OkHttpClient.Builder() + .protocols(protocols) + .build() assertThat(client.protocols).containsExactly(Protocol.HTTP_1_1) } @@ -296,28 +304,36 @@ class OkHttpClientTest { assertThat(client.proxy).isNull() assertThat(client.proxySelector) .isNotInstanceOf(NullProxySelector::class.java) - client = OkHttpClient.Builder() - .proxy(Proxy.NO_PROXY) - .build() + client = + OkHttpClient.Builder() + .proxy(Proxy.NO_PROXY) + .build() assertThat(client.proxy).isSameAs(Proxy.NO_PROXY) assertThat(client.proxySelector) .isInstanceOf(NullProxySelector::class.java) - client = OkHttpClient.Builder() - .proxySelector(FakeProxySelector()) - .build() + client = + OkHttpClient.Builder() + .proxySelector(FakeProxySelector()) + .build() assertThat(client.proxy).isNull() assertThat(client.proxySelector) .isInstanceOf(FakeProxySelector::class.java) } @Test fun sharesRouteDatabase() { - val client = OkHttpClient.Builder() - .build() - val proxySelector: ProxySelector = object : ProxySelector() { - override fun select(uri: URI): List = listOf() - - override fun connectFailed(uri: URI, socketAddress: SocketAddress, e: IOException) {} - } + val client = + OkHttpClient.Builder() + .build() + val proxySelector: ProxySelector = + object : ProxySelector() { + override fun select(uri: URI): List = listOf() + + override fun connectFailed( + uri: URI, + socketAddress: SocketAddress, + e: IOException, + ) {} + } val trustManager = get().platformTrustManager() val sslContext = get().newSSLContext() @@ -328,7 +344,7 @@ class OkHttpClientTest { client.routeDatabase, OkHttpClient.Builder() .build() - .routeDatabase + .routeDatabase, ) // same client with no change affecting route db @@ -336,75 +352,79 @@ class OkHttpClientTest { client.routeDatabase, client.newBuilder() .build() - .routeDatabase + .routeDatabase, ) assertSame( client.routeDatabase, client.newBuilder() .callTimeout(Duration.ofSeconds(5)) .build() - .routeDatabase + .routeDatabase, ) // logically different scope of client for route db - assertNotSame(client.routeDatabase, + assertNotSame( + client.routeDatabase, client.newBuilder() .dns { listOf() } .build() - .routeDatabase + .routeDatabase, ) - assertNotSame(client.routeDatabase, client.newBuilder() - .proxyAuthenticator { _: Route?, _: Response? -> null } - .build() - .routeDatabase + assertNotSame( + client.routeDatabase, + client.newBuilder() + .proxyAuthenticator { _: Route?, _: Response? -> null } + .build() + .routeDatabase, ) assertNotSame( client.routeDatabase, client.newBuilder() .protocols(listOf(Protocol.HTTP_1_1)) .build() - .routeDatabase + .routeDatabase, ) assertNotSame( client.routeDatabase, client.newBuilder() .connectionSpecs(listOf(ConnectionSpec.COMPATIBLE_TLS)) .build() - .routeDatabase + .routeDatabase, ) assertNotSame( client.routeDatabase, client.newBuilder() .proxySelector(proxySelector) .build() - .routeDatabase + .routeDatabase, ) assertNotSame( client.routeDatabase, client.newBuilder() .proxy(Proxy.NO_PROXY) .build() - .routeDatabase + .routeDatabase, ) assertNotSame( client.routeDatabase, client.newBuilder() .sslSocketFactory(sslContext.socketFactory, trustManager) .build() - .routeDatabase + .routeDatabase, ) - assertNotSame(client.routeDatabase, + assertNotSame( + client.routeDatabase, client.newBuilder() .hostnameVerifier { _: String?, _: SSLSession? -> false } .build() - .routeDatabase + .routeDatabase, ) assertNotSame( client.routeDatabase, client.newBuilder() .certificatePinner(CertificatePinner.Builder().build()) .build() - .routeDatabase + .routeDatabase, ) } diff --git a/okhttp/src/test/java/okhttp3/OpenJSSETest.kt b/okhttp/src/test/java/okhttp3/OpenJSSETest.kt index c9fb35406410..ea000f9bb342 100644 --- a/okhttp/src/test/java/okhttp3/OpenJSSETest.kt +++ b/okhttp/src/test/java/okhttp3/OpenJSSETest.kt @@ -37,8 +37,11 @@ import org.openjsse.sun.security.ssl.SSLSocketFactoryImpl import org.openjsse.sun.security.ssl.SSLSocketImpl class OpenJSSETest { - @JvmField @RegisterExtension var platform = PlatformRule() - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule() + @JvmField @RegisterExtension + var platform = PlatformRule() + + @JvmField @RegisterExtension + val clientTestRule = OkHttpClientTestRule() var client = clientTestRule.newClient() @@ -100,18 +103,22 @@ class OpenJSSETest { private fun enableTls() { // Generate a self-signed cert for the server to serve and the client to trust. // can't use TlsUtil.localhost with a non OpenJSSE trust manager - val heldCertificate = HeldCertificate.Builder() + val heldCertificate = + HeldCertificate.Builder() .commonName("localhost") .addSubjectAlternativeName("localhost") .build() - val handshakeCertificates = HandshakeCertificates.Builder() + val handshakeCertificates = + HandshakeCertificates.Builder() .heldCertificate(heldCertificate) .addTrustedCertificate(heldCertificate.certificate) .build() - client = client.newBuilder() + client = + client.newBuilder() .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager) + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } diff --git a/okhttp/src/test/java/okhttp3/PublicInternalApiTest.kt b/okhttp/src/test/java/okhttp3/PublicInternalApiTest.kt index 29acba8738c5..01e8be9b8c9f 100644 --- a/okhttp/src/test/java/okhttp3/PublicInternalApiTest.kt +++ b/okhttp/src/test/java/okhttp3/PublicInternalApiTest.kt @@ -39,11 +39,12 @@ class PublicInternalApiTest { @Test fun hasBody() { val request = Request.Builder().url("http://example.com").build() - val response = Response.Builder().code(200) - .message("OK") - .request(request) - .protocol(Protocol.HTTP_2) - .build() + val response = + Response.Builder().code(200) + .message("OK") + .request(request) + .protocol(Protocol.HTTP_2) + .build() assertTrue(hasBody(response)) } } diff --git a/okhttp/src/test/java/okhttp3/RecordedResponse.kt b/okhttp/src/test/java/okhttp3/RecordedResponse.kt index f2a6ad69c8ff..340ca88158c8 100644 --- a/okhttp/src/test/java/okhttp3/RecordedResponse.kt +++ b/okhttp/src/test/java/okhttp3/RecordedResponse.kt @@ -36,54 +36,68 @@ class RecordedResponse( val response: Response?, val webSocket: WebSocket?, val body: String?, - val failure: IOException? + val failure: IOException?, ) { - fun assertRequestUrl(url: HttpUrl) = apply { - assertThat(request.url).isEqualTo(url) - } + fun assertRequestUrl(url: HttpUrl) = + apply { + assertThat(request.url).isEqualTo(url) + } - fun assertRequestMethod(method: String) = apply { - assertThat(request.method).isEqualTo(method) - } + fun assertRequestMethod(method: String) = + apply { + assertThat(request.method).isEqualTo(method) + } - fun assertRequestHeader(name: String, vararg values: String) = apply { + fun assertRequestHeader( + name: String, + vararg values: String, + ) = apply { assertThat(request.headers(name)).containsExactly(*values) } - fun assertCode(expectedCode: Int) = apply { - assertThat(response!!.code).isEqualTo(expectedCode) - } + fun assertCode(expectedCode: Int) = + apply { + assertThat(response!!.code).isEqualTo(expectedCode) + } - fun assertSuccessful() = apply { - assertThat(failure).isNull() - assertThat(response!!.isSuccessful).isTrue() - } + fun assertSuccessful() = + apply { + assertThat(failure).isNull() + assertThat(response!!.isSuccessful).isTrue() + } - fun assertNotSuccessful() = apply { - assertThat(response!!.isSuccessful).isFalse() - } + fun assertNotSuccessful() = + apply { + assertThat(response!!.isSuccessful).isFalse() + } - fun assertHeader(name: String, vararg values: String?) = apply { + fun assertHeader( + name: String, + vararg values: String?, + ) = apply { assertThat(response!!.headers(name)).containsExactly(*values) } - fun assertHeaders(headers: Headers) = apply { - assertThat(response!!.headers).isEqualTo(headers) - } + fun assertHeaders(headers: Headers) = + apply { + assertThat(response!!.headers).isEqualTo(headers) + } - fun assertBody(expectedBody: String) = apply { - assertThat(body).isEqualTo(expectedBody) - } + fun assertBody(expectedBody: String) = + apply { + assertThat(body).isEqualTo(expectedBody) + } - fun assertHandshake() = apply { - val handshake = response!!.handshake!! - assertThat(handshake.tlsVersion).isNotNull() - assertThat(handshake.cipherSuite).isNotNull() - assertThat(handshake.peerPrincipal).isNotNull() - assertThat(handshake.peerCertificates.size).isEqualTo(1) - assertThat(handshake.localPrincipal).isNull() - assertThat(handshake.localCertificates.size).isEqualTo(0) - } + fun assertHandshake() = + apply { + val handshake = response!!.handshake!! + assertThat(handshake.tlsVersion).isNotNull() + assertThat(handshake.cipherSuite).isNotNull() + assertThat(handshake.peerPrincipal).isNotNull() + assertThat(handshake.peerCertificates.size).isEqualTo(1) + assertThat(handshake.localPrincipal).isNull() + assertThat(handshake.localCertificates.size).isEqualTo(0) + } /** * Asserts that the current response was redirected and returns the prior response. @@ -102,14 +116,16 @@ class RecordedResponse( } /** Asserts that the current response didn't use the network. */ - fun assertNoNetworkResponse() = apply { - assertThat(response!!.networkResponse).isNull() - } + fun assertNoNetworkResponse() = + apply { + assertThat(response!!.networkResponse).isNull() + } /** Asserts that the current response didn't use the cache. */ - fun assertNoCacheResponse() = apply { - assertThat(response!!.cacheResponse).isNull() - } + fun assertNoCacheResponse() = + apply { + assertThat(response!!.cacheResponse).isNull() + } /** * Asserts that the current response used the cache and returns the cache response. @@ -119,41 +135,56 @@ class RecordedResponse( return RecordedResponse(cacheResponse.request, cacheResponse, null, null, null) } - fun assertFailure(vararg allowedExceptionTypes: Class<*>) = apply { - var found = false - for (expectedClass in allowedExceptionTypes) { - if (expectedClass.isInstance(failure)) { - found = true - break + fun assertFailure(vararg allowedExceptionTypes: Class<*>) = + apply { + var found = false + for (expectedClass in allowedExceptionTypes) { + if (expectedClass.isInstance(failure)) { + found = true + break + } } + assertThat( + found, + "Expected exception type among ${allowedExceptionTypes.contentToString()}, got $failure", + ).isTrue() } - assertThat( - found, - "Expected exception type among ${allowedExceptionTypes.contentToString()}, got $failure" - ).isTrue() - } - fun assertFailure(vararg messages: String) = apply { - assertThat(failure, "No failure found").isNotNull() - assertThat(messages).contains(failure!!.message) - } + fun assertFailure(vararg messages: String) = + apply { + assertThat(failure, "No failure found").isNotNull() + assertThat(messages).contains(failure!!.message) + } - fun assertFailureMatches(vararg patterns: String) = apply { - val message = failure!!.message!! - assertThat(patterns.firstOrNull { pattern -> - message.matches(pattern.toRegex()) - }).isNotNull() - } + fun assertFailureMatches(vararg patterns: String) = + apply { + val message = failure!!.message!! + assertThat( + patterns.firstOrNull { pattern -> + message.matches(pattern.toRegex()) + }, + ).isNotNull() + } - fun assertSentRequestAtMillis(minimum: Long, maximum: Long) = apply { + fun assertSentRequestAtMillis( + minimum: Long, + maximum: Long, + ) = apply { assertDateInRange(minimum, response!!.sentRequestAtMillis, maximum) } - fun assertReceivedResponseAtMillis(minimum: Long, maximum: Long) = apply { + fun assertReceivedResponseAtMillis( + minimum: Long, + maximum: Long, + ) = apply { assertDateInRange(minimum, response!!.receivedResponseAtMillis, maximum) } - private fun assertDateInRange(minimum: Long, actual: Long, maximum: Long) { + private fun assertDateInRange( + minimum: Long, + actual: Long, + maximum: Long, + ) { assertThat(actual, "${format(minimum)} <= ${format(actual)} <= ${format(maximum)}") .isBetween(minimum, maximum) } diff --git a/okhttp/src/test/java/okhttp3/RecordingCallback.kt b/okhttp/src/test/java/okhttp3/RecordingCallback.kt index e60e46205391..630bce0c6f68 100644 --- a/okhttp/src/test/java/okhttp3/RecordingCallback.kt +++ b/okhttp/src/test/java/okhttp3/RecordingCallback.kt @@ -25,13 +25,19 @@ class RecordingCallback : Callback { private val responses = mutableListOf() @Synchronized - override fun onFailure(call: Call, e: IOException) { + override fun onFailure( + call: Call, + e: IOException, + ) { responses.add(RecordedResponse(call.request(), null, null, null, e)) (this as Object).notifyAll() } @Synchronized - override fun onResponse(call: Call, response: Response) { + override fun onResponse( + call: Call, + response: Response, + ) { val body = response.body.string() responses.add(RecordedResponse(call.request(), response, null, body, null)) (this as Object).notifyAll() diff --git a/okhttp/src/test/java/okhttp3/RecordingExecutor.kt b/okhttp/src/test/java/okhttp3/RecordingExecutor.kt index 21fd912dd363..7ecf86bb7253 100644 --- a/okhttp/src/test/java/okhttp3/RecordingExecutor.kt +++ b/okhttp/src/test/java/okhttp3/RecordingExecutor.kt @@ -24,7 +24,7 @@ import okhttp3.internal.connection.RealCall import okhttp3.internal.finishedAccessor internal class RecordingExecutor( - private val dispatcherTest: DispatcherTest + private val dispatcherTest: DispatcherTest, ) : AbstractExecutorService() { private var shutdown: Boolean = false private val calls = mutableListOf() @@ -68,7 +68,10 @@ internal class RecordingExecutor( throw UnsupportedOperationException() } - override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean { + override fun awaitTermination( + timeout: Long, + unit: TimeUnit, + ): Boolean { throw UnsupportedOperationException() } } diff --git a/okhttp/src/test/java/okhttp3/RequestBodyTest.kt b/okhttp/src/test/java/okhttp3/RequestBodyTest.kt index 3fca7d2e2508..11afe31e0280 100644 --- a/okhttp/src/test/java/okhttp3/RequestBodyTest.kt +++ b/okhttp/src/test/java/okhttp3/RequestBodyTest.kt @@ -37,7 +37,9 @@ class RequestBodyTest { private lateinit var filePath: okio.Path @BeforeEach - fun setup(@TempDir tempDir: Path) { + fun setup( + @TempDir tempDir: Path, + ) { filePath = tempDir.toOkioPath() / "file.txt" } @@ -117,7 +119,10 @@ class RequestBodyTest { } } - private inline fun assertOnFileDescriptor(content: String? = null, fn: (FileDescriptor) -> T): T { + private inline fun assertOnFileDescriptor( + content: String? = null, + fn: (FileDescriptor) -> T, + ): T { return assertOnPath(content) { FileInputStream(filePath.toFile()).use { fis -> fn(fis.fd) @@ -125,7 +130,10 @@ class RequestBodyTest { } } - private inline fun assertOnPath(content: String? = null, fn: (okio.Path) -> T): T { + private inline fun assertOnPath( + content: String? = null, + fn: (okio.Path) -> T, + ): T { FileSystem.SYSTEM.write(filePath) { if (content != null) { writeUtf8(content) diff --git a/okhttp/src/test/java/okhttp3/RequestCommonTest.kt b/okhttp/src/test/java/okhttp3/RequestCommonTest.kt index 4d979398a7f1..263314ce3227 100644 --- a/okhttp/src/test/java/okhttp3/RequestCommonTest.kt +++ b/okhttp/src/test/java/okhttp3/RequestCommonTest.kt @@ -29,19 +29,19 @@ import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.RequestBody.Companion.toRequestBody class RequestCommonTest { - @Test fun constructorNormal() { val url = "https://example.com/".toHttpUrl() val body = "hello".toRequestBody() val headers = headersOf("User-Agent", "RequestTest") val method = "PUT" - val request = Request( - url = url, - headers = headers, - method = method, - body = body - ) + val request = + Request( + url = url, + headers = headers, + method = method, + body = body, + ) assertThat(request.url).isEqualTo(url) assertThat(request.headers).isEqualTo(headers) assertThat(request.method).isEqualTo(method) @@ -53,10 +53,11 @@ class RequestCommonTest { fun constructorNoBodyNoMethod() { val url = "https://example.com/".toHttpUrl() val headers = headersOf("User-Agent", "RequestTest") - val request = Request( - url = url, - headers = headers, - ) + val request = + Request( + url = url, + headers = headers, + ) assertThat(request.url).isEqualTo(url) assertThat(request.headers).isEqualTo(headers) assertThat(request.method).isEqualTo("GET") @@ -69,11 +70,12 @@ class RequestCommonTest { val url = "https://example.com/".toHttpUrl() val body = "hello".toRequestBody() val headers = headersOf("User-Agent", "RequestTest") - val request = Request( - url = url, - headers = headers, - body = body - ) + val request = + Request( + url = url, + headers = headers, + body = body, + ) assertThat(request.url).isEqualTo(url) assertThat(request.headers).isEqualTo(headers) assertThat(request.method).isEqualTo("POST") @@ -86,11 +88,12 @@ class RequestCommonTest { val url = "https://example.com/".toHttpUrl() val headers = headersOf("User-Agent", "RequestTest") val method = "DELETE" - val request = Request( - url = url, - headers = headers, - method = method, - ) + val request = + Request( + url = url, + headers = headers, + method = method, + ) assertThat(request.url).isEqualTo(url) assertThat(request.headers).isEqualTo(headers) assertThat(request.method).isEqualTo(method) @@ -103,36 +106,41 @@ class RequestCommonTest { val requestWithoutCache = Request.Builder().url("http://localhost/api").build() val builtRequestWithoutCache = requestWithoutCache.newBuilder().url("http://localhost/api/foo").build() assertThat(builtRequestWithoutCache.url).isEqualTo( - "http://localhost/api/foo".toHttpUrl()) - val requestWithCache = Request.Builder() - .url("http://localhost/api") - .build() + "http://localhost/api/foo".toHttpUrl(), + ) + val requestWithCache = + Request.Builder() + .url("http://localhost/api") + .build() // cache url object requestWithCache.url - val builtRequestWithCache = requestWithCache.newBuilder() - .url("http://localhost/api/foo") - .build() + val builtRequestWithCache = + requestWithCache.newBuilder() + .url("http://localhost/api/foo") + .build() assertThat(builtRequestWithCache.url) .isEqualTo("http://localhost/api/foo".toHttpUrl()) } @Test fun cacheControl() { - val request = Request.Builder() - .cacheControl(CacheControl.Builder().noCache().build()) - .url("https://square.com") - .build() + val request = + Request.Builder() + .cacheControl(CacheControl.Builder().noCache().build()) + .url("https://square.com") + .build() assertThat(request.headers("Cache-Control")).containsExactly("no-cache") assertThat(request.cacheControl.noCache).isTrue() } @Test fun emptyCacheControlClearsAllCacheControlHeaders() { - val request = Request.Builder() - .header("Cache-Control", "foo") - .cacheControl(CacheControl.Builder().build()) - .url("https://square.com") - .build() + val request = + Request.Builder() + .header("Cache-Control", "foo") + .cacheControl(CacheControl.Builder().build()) + .url("https://square.com") + .build() assertThat(request.headers("Cache-Control")).isEmpty() } @@ -192,9 +200,10 @@ class RequestCommonTest { @Test fun noTag() { - val request = Request.Builder() - .url("https://square.com") - .build() + val request = + Request.Builder() + .url("https://square.com") + .build() assertThat(request.tag()).isNull() assertThat(request.tag(Any::class)).isNull() assertThat(request.tag(String::class)).isNull() @@ -207,10 +216,11 @@ class RequestCommonTest { @Test fun defaultTag() { val tag = "1234" - val request = Request.Builder() - .url("https://square.com") - .tag(tag as Any) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(tag as Any) + .build() assertThat(request.tag()).isSameAs(tag) assertThat(request.tag(Any::class)).isSameAs(tag) assertThat(request.tag(String::class)).isNull() @@ -222,30 +232,33 @@ class RequestCommonTest { @Test fun nullRemovesTag() { - val request = Request.Builder() - .url("https://square.com") - .tag("a" as Any) - .tag(null) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag("a" as Any) + .tag(null) + .build() assertThat(request.tag()).isNull() } @Test fun removeAbsentTag() { - val request = Request.Builder() - .url("https://square.com") - .tag(null) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(null) + .build() assertThat(request.tag()).isNull() } @Test fun objectTag() { val tag = "1234" - val request = Request.Builder() - .url("https://square.com") - .tag(Any::class, tag) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(Any::class, tag) + .build() assertThat(request.tag()).isSameAs(tag) assertThat(request.tag(Any::class)).isSameAs(tag) assertThat(request.tag(String::class)).isNull() @@ -258,10 +271,11 @@ class RequestCommonTest { @Test fun kotlinReifiedTag() { val uuidTag = "1234" - val request = Request.Builder() - .url("https://square.com") - .tag(uuidTag) // Use the type parameter. - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(uuidTag) // Use the type parameter. + .build() assertThat(request.tag()).isSameAs("1234") assertThat(request.tag()).isNull() @@ -272,10 +286,11 @@ class RequestCommonTest { @Test fun kotlinClassTag() { val uuidTag = "1234" - val request = Request.Builder() - .url("https://square.com") - .tag(String::class, uuidTag) // Use the KClass<*> parameter. - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(String::class, uuidTag) // Use the KClass<*> parameter. + .build() assertThat(request.tag(Any::class)).isNull() assertThat(request.tag(String::class)).isSameAs("1234") @@ -288,11 +303,12 @@ class RequestCommonTest { fun replaceOnlyTag() { val uuidTag1 = "1234" val uuidTag2 = "4321" - val request = Request.Builder() - .url("https://square.com") - .tag(String::class, uuidTag1) - .tag(String::class, uuidTag2) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(String::class, uuidTag1) + .tag(String::class, uuidTag2) + .build() assertThat(request.tag(String::class)).isSameAs(uuidTag2) } @@ -301,12 +317,13 @@ class RequestCommonTest { val stringTag = "dilophosaurus" val longTag = 20170815L as Long? val objectTag = Any() - val request = Request.Builder() - .url("https://square.com") - .tag(Any::class, objectTag) - .tag(String::class, stringTag) - .tag(Long::class, longTag) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(Any::class, objectTag) + .tag(String::class, stringTag) + .tag(Long::class, longTag) + .build() assertThat(request.tag()).isSameAs(objectTag) assertThat(request.tag(Any::class)).isSameAs(objectTag) assertThat(request.tag(String::class)).isSameAs(stringTag) @@ -318,8 +335,9 @@ class RequestCommonTest { /** Confirm that we don't accidentally share the backing map between objects. */ @Test fun tagsAreImmutable() { - val builder = Request.Builder() - .url("https://square.com") + val builder = + Request.Builder() + .url("https://square.com") val requestA = builder.tag(String::class, "a").build() val requestB = builder.tag(String::class, "b").build() val requestC = requestA.newBuilder().tag(String::class, "c").build() @@ -330,18 +348,20 @@ class RequestCommonTest { @Test fun requestToStringRedactsSensitiveHeaders() { - val headers = Headers.Builder() - .add("content-length", "99") - .add("authorization", "peanutbutter") - .add("proxy-authorization", "chocolate") - .add("cookie", "drink=coffee") - .add("set-cookie", "accessory=sugar") - .add("user-agent", "OkHttp") - .build() - val request = Request( - "https://square.com".toHttpUrl(), - headers - ) + val headers = + Headers.Builder() + .add("content-length", "99") + .add("authorization", "peanutbutter") + .add("proxy-authorization", "chocolate") + .add("cookie", "drink=coffee") + .add("set-cookie", "accessory=sugar") + .add("user-agent", "OkHttp") + .build() + val request = + Request( + "https://square.com".toHttpUrl(), + headers, + ) assertThat(request.toString()).isEqualTo( "Request{method=GET, url=https://square.com/, headers=[" + "content-length:99," + @@ -350,7 +370,7 @@ class RequestCommonTest { " cookie:██," + " set-cookie:██," + " user-agent:OkHttp" + - "]}" + "]}", ) } } diff --git a/okhttp/src/test/java/okhttp3/RequestTest.kt b/okhttp/src/test/java/okhttp3/RequestTest.kt index 6700abdca376..f5c3a2a30784 100644 --- a/okhttp/src/test/java/okhttp3/RequestTest.kt +++ b/okhttp/src/test/java/okhttp3/RequestTest.kt @@ -37,19 +37,19 @@ import okio.ByteString.Companion.encodeUtf8 import org.junit.jupiter.api.Test class RequestTest { - @Test fun constructor() { val url = "https://example.com/".toHttpUrl() val body = "hello".toRequestBody() val headers = headersOf("User-Agent", "RequestTest") val method = "PUT" - val request = Request( - url = url, - headers = headers, - method = method, - body = body - ) + val request = + Request( + url = url, + headers = headers, + method = method, + body = body, + ) assertThat(request.url).isEqualTo(url) assertThat(request.headers).isEqualTo(headers) assertThat(request.method).isEqualTo(method) @@ -61,10 +61,11 @@ class RequestTest { fun constructorNoBodyNoMethod() { val url = "https://example.com/".toHttpUrl() val headers = headersOf("User-Agent", "RequestTest") - val request = Request( - url = url, - headers = headers, - ) + val request = + Request( + url = url, + headers = headers, + ) assertThat(request.url).isEqualTo(url) assertThat(request.headers).isEqualTo(headers) assertThat(request.method).isEqualTo("GET") @@ -77,11 +78,12 @@ class RequestTest { val url = "https://example.com/".toHttpUrl() val body = "hello".toRequestBody() val headers = headersOf("User-Agent", "RequestTest") - val request = Request( - url = url, - headers = headers, - body = body - ) + val request = + Request( + url = url, + headers = headers, + body = body, + ) assertThat(request.url).isEqualTo(url) assertThat(request.headers).isEqualTo(headers) assertThat(request.method).isEqualTo("POST") @@ -94,11 +96,12 @@ class RequestTest { val url = "https://example.com/".toHttpUrl() val headers = headersOf("User-Agent", "RequestTest") val method = "DELETE" - val request = Request( - url = url, - headers = headers, - method = method, - ) + val request = + Request( + url = url, + headers = headers, + method = method, + ) assertThat(request.url).isEqualTo(url) assertThat(request.headers).isEqualTo(headers) assertThat(request.method).isEqualTo(method) @@ -221,36 +224,41 @@ class RequestTest { val requestWithoutCache = Request.Builder().url("http://localhost/api").build() val builtRequestWithoutCache = requestWithoutCache.newBuilder().url("http://localhost/api/foo").build() assertThat(builtRequestWithoutCache.url).isEqualTo( - "http://localhost/api/foo".toHttpUrl()) - val requestWithCache = Request.Builder() - .url("http://localhost/api") - .build() + "http://localhost/api/foo".toHttpUrl(), + ) + val requestWithCache = + Request.Builder() + .url("http://localhost/api") + .build() // cache url object requestWithCache.url - val builtRequestWithCache = requestWithCache.newBuilder() - .url("http://localhost/api/foo") - .build() + val builtRequestWithCache = + requestWithCache.newBuilder() + .url("http://localhost/api/foo") + .build() assertThat(builtRequestWithCache.url) .isEqualTo("http://localhost/api/foo".toHttpUrl()) } @Test fun cacheControl() { - val request = Request.Builder() - .cacheControl(CacheControl.Builder().noCache().build()) - .url("https://square.com") - .build() + val request = + Request.Builder() + .cacheControl(CacheControl.Builder().noCache().build()) + .url("https://square.com") + .build() assertThat(request.headers("Cache-Control")).containsExactly("no-cache") assertThat(request.cacheControl.noCache).isTrue() } @Test fun emptyCacheControlClearsAllCacheControlHeaders() { - val request = Request.Builder() - .header("Cache-Control", "foo") - .cacheControl(CacheControl.Builder().build()) - .url("https://square.com") - .build() + val request = + Request.Builder() + .header("Cache-Control", "foo") + .cacheControl(CacheControl.Builder().build()) + .url("https://square.com") + .build() assertThat(request.headers("Cache-Control")).isEmpty() } @@ -310,9 +318,10 @@ class RequestTest { @Test fun noTag() { - val request = Request.Builder() - .url("https://square.com") - .build() + val request = + Request.Builder() + .url("https://square.com") + .build() assertThat(request.tag()).isNull() assertThat(request.tag(Any::class.java)).isNull() assertThat(request.tag(UUID::class.java)).isNull() @@ -326,10 +335,11 @@ class RequestTest { @Test fun defaultTag() { val tag = UUID.randomUUID() - val request = Request.Builder() - .url("https://square.com") - .tag(tag) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(tag) + .build() assertThat(request.tag()).isSameAs(tag) assertThat(request.tag(Any::class.java)).isSameAs(tag) assertThat(request.tag(UUID::class.java)).isNull() @@ -342,30 +352,33 @@ class RequestTest { @Test fun nullRemovesTag() { - val request = Request.Builder() - .url("https://square.com") - .tag("a") - .tag(null) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag("a") + .tag(null) + .build() assertThat(request.tag()).isNull() } @Test fun removeAbsentTag() { - val request = Request.Builder() - .url("https://square.com") - .tag(null) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(null) + .build() assertThat(request.tag()).isNull() } @Test fun objectTag() { val tag = UUID.randomUUID() - val request = Request.Builder() - .url("https://square.com") - .tag(Any::class.java, tag) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(Any::class.java, tag) + .build() assertThat(request.tag()).isSameAs(tag) assertThat(request.tag(Any::class.java)).isSameAs(tag) assertThat(request.tag(UUID::class.java)).isNull() @@ -379,10 +392,11 @@ class RequestTest { @Test fun javaClassTag() { val uuidTag = UUID.randomUUID() - val request = Request.Builder() - .url("https://square.com") - .tag(UUID::class.java, uuidTag) // Use the Class<*> parameter. - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(UUID::class.java, uuidTag) // Use the Class<*> parameter. + .build() assertThat(request.tag()).isNull() assertThat(request.tag(Any::class.java)).isNull() assertThat(request.tag(UUID::class.java)).isSameAs(uuidTag) @@ -396,10 +410,11 @@ class RequestTest { @Test fun kotlinReifiedTag() { val uuidTag = UUID.randomUUID() - val request = Request.Builder() - .url("https://square.com") - .tag(uuidTag) // Use the type parameter. - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(uuidTag) // Use the type parameter. + .build() assertThat(request.tag()).isNull() assertThat(request.tag()).isNull() assertThat(request.tag()).isSameAs(uuidTag) @@ -413,10 +428,11 @@ class RequestTest { @Test fun kotlinClassTag() { val uuidTag = UUID.randomUUID() - val request = Request.Builder() - .url("https://square.com") - .tag(UUID::class, uuidTag) // Use the KClass<*> parameter. - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(UUID::class, uuidTag) // Use the KClass<*> parameter. + .build() assertThat(request.tag()).isNull() assertThat(request.tag(Any::class)).isNull() assertThat(request.tag(UUID::class)).isSameAs(uuidTag) @@ -431,11 +447,12 @@ class RequestTest { fun replaceOnlyTag() { val uuidTag1 = UUID.randomUUID() val uuidTag2 = UUID.randomUUID() - val request = Request.Builder() - .url("https://square.com") - .tag(UUID::class.java, uuidTag1) - .tag(UUID::class.java, uuidTag2) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(UUID::class.java, uuidTag1) + .tag(UUID::class.java, uuidTag2) + .build() assertThat(request.tag(UUID::class.java)).isSameAs(uuidTag2) } @@ -445,13 +462,14 @@ class RequestTest { val stringTag = "dilophosaurus" val longTag = 20170815L as Long? val objectTag = Any() - val request = Request.Builder() - .url("https://square.com") - .tag(Any::class.java, objectTag) - .tag(UUID::class.java, uuidTag) - .tag(String::class.java, stringTag) - .tag(Long::class.javaObjectType, longTag) - .build() + val request = + Request.Builder() + .url("https://square.com") + .tag(Any::class.java, objectTag) + .tag(UUID::class.java, uuidTag) + .tag(String::class.java, stringTag) + .tag(Long::class.javaObjectType, longTag) + .build() assertThat(request.tag()).isSameAs(objectTag) assertThat(request.tag(Any::class.java)).isSameAs(objectTag) assertThat(request.tag(UUID::class.java)).isSameAs(uuidTag) @@ -462,8 +480,9 @@ class RequestTest { /** Confirm that we don't accidentally share the backing map between objects. */ @Test fun tagsAreImmutable() { - val builder = Request.Builder() - .url("https://square.com") + val builder = + Request.Builder() + .url("https://square.com") val requestA = builder.tag(String::class.java, "a").build() val requestB = builder.tag(String::class.java, "b").build() val requestC = requestA.newBuilder().tag(String::class.java, "c").build() @@ -474,18 +493,20 @@ class RequestTest { @Test fun requestToStringRedactsSensitiveHeaders() { - val headers = Headers.Builder() - .add("content-length", "99") - .add("authorization", "peanutbutter") - .add("proxy-authorization", "chocolate") - .add("cookie", "drink=coffee") - .add("set-cookie", "accessory=sugar") - .add("user-agent", "OkHttp") - .build() - val request = Request( - "https://square.com".toHttpUrl(), - headers - ) + val headers = + Headers.Builder() + .add("content-length", "99") + .add("authorization", "peanutbutter") + .add("proxy-authorization", "chocolate") + .add("cookie", "drink=coffee") + .add("set-cookie", "accessory=sugar") + .add("user-agent", "OkHttp") + .build() + val request = + Request( + "https://square.com".toHttpUrl(), + headers, + ) assertThat(request.toString()).isEqualTo( "Request{method=GET, url=https://square.com/, headers=[" + "content-length:99," + @@ -494,7 +515,7 @@ class RequestTest { " cookie:██," + " set-cookie:██," + " user-agent:OkHttp" + - "]}" + "]}", ) } diff --git a/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt b/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt index 83481c08f680..a7967e92f3f1 100644 --- a/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt +++ b/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt @@ -18,7 +18,6 @@ package okhttp3 import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isTrue -import assertk.fail import java.io.IOException import java.io.InputStreamReader import java.io.Reader @@ -100,26 +99,27 @@ class ResponseBodyJvmTest { @Test fun stringClosesUnderlyingSource() { val closed = AtomicBoolean() - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 5 + } + + override fun source(): BufferedSource { + val source = Buffer().writeUtf8("hello") + return object : ForwardingSource(source) { + @Throws(IOException::class) + override fun close() { + closed.set(true) + super.close() + } + }.buffer() + } } - - override fun contentLength(): Long { - return 5 - } - - override fun source(): BufferedSource { - val source = Buffer().writeUtf8("hello") - return object : ForwardingSource(source) { - @Throws(IOException::class) - override fun close() { - closed.set(true) - super.close() - } - }.buffer() - } - } assertThat(body.string()).isEqualTo("hello") assertThat(closed.get()).isTrue() } @@ -181,26 +181,27 @@ class ResponseBodyJvmTest { @Test fun readerClosedBeforeBomClosesUnderlyingSource() { val closed = AtomicBoolean() - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null - } - - override fun contentLength(): Long { - return 5 + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 5 + } + + override fun source(): BufferedSource { + val body = body("fffe680065006c006c006f00") + return object : ForwardingSource(body.source()) { + @Throws(IOException::class) + override fun close() { + closed.set(true) + super.close() + } + }.buffer() + } } - - override fun source(): BufferedSource { - val body = body("fffe680065006c006c006f00") - return object : ForwardingSource(body.source()) { - @Throws(IOException::class) - override fun close() { - closed.set(true) - super.close() - } - }.buffer() - } - } body.charStream().close() assertThat(closed.get()).isTrue() } @@ -208,26 +209,27 @@ class ResponseBodyJvmTest { @Test fun readerClosedAfterBomClosesUnderlyingSource() { val closed = AtomicBoolean() - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 5 + } + + override fun source(): BufferedSource { + val body = body("fffe680065006c006c006f00") + return object : ForwardingSource(body.source()) { + @Throws(IOException::class) + override fun close() { + closed.set(true) + super.close() + } + }.buffer() + } } - - override fun contentLength(): Long { - return 5 - } - - override fun source(): BufferedSource { - val body = body("fffe680065006c006c006f00") - return object : ForwardingSource(body.source()) { - @Throws(IOException::class) - override fun close() { - closed.set(true) - super.close() - } - }.buffer() - } - } val reader = body.charStream() assertThat(reader.read()).isEqualTo('h'.code) reader.close() @@ -263,74 +265,77 @@ class ResponseBodyJvmTest { @Test fun bytesClosesUnderlyingSource() { val closed = AtomicBoolean() - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null - } - - override fun contentLength(): Long { - return 5 - } - - override fun source(): BufferedSource { - val source = Buffer().writeUtf8("hello") - return object : ForwardingSource(source) { - @Throws(IOException::class) - override fun close() { - closed.set(true) - super.close() - } - }.buffer() + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 5 + } + + override fun source(): BufferedSource { + val source = Buffer().writeUtf8("hello") + return object : ForwardingSource(source) { + @Throws(IOException::class) + override fun close() { + closed.set(true) + super.close() + } + }.buffer() + } } - } assertThat(body.bytes().size).isEqualTo(5) assertThat(closed.get()).isTrue() } @Test fun bytesThrowsWhenLengthsDisagree() { - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null - } - - override fun contentLength(): Long { - return 10 + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 10 + } + + override fun source(): BufferedSource { + return Buffer().writeUtf8("hello") + } } - - override fun source(): BufferedSource { - return Buffer().writeUtf8("hello") - } - } assertFailsWith { body.bytes() }.also { expected -> assertThat(expected.message).isEqualTo( - "Content-Length (10) and stream length (5) disagree" + "Content-Length (10) and stream length (5) disagree", ) } } @Test fun bytesThrowsMoreThanIntMaxValue() { - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return Int.MAX_VALUE + 1L + } + + override fun source(): BufferedSource { + throw AssertionError() + } } - - override fun contentLength(): Long { - return Int.MAX_VALUE + 1L - } - - override fun source(): BufferedSource { - throw AssertionError() - } - } assertFailsWith { body.bytes() }.also { expected -> assertThat(expected.message).isEqualTo( - "Cannot buffer entire body for content length: 2147483648" + "Cannot buffer entire body for content length: 2147483648", ) } } @@ -352,74 +357,77 @@ class ResponseBodyJvmTest { @Test fun byteStringClosesUnderlyingSource() { val closed = AtomicBoolean() - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null - } - - override fun contentLength(): Long { - return 5 + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 5 + } + + override fun source(): BufferedSource { + val source = Buffer().writeUtf8("hello") + return object : ForwardingSource(source) { + @Throws(IOException::class) + override fun close() { + closed.set(true) + super.close() + } + }.buffer() + } } - - override fun source(): BufferedSource { - val source = Buffer().writeUtf8("hello") - return object : ForwardingSource(source) { - @Throws(IOException::class) - override fun close() { - closed.set(true) - super.close() - } - }.buffer() - } - } assertThat(body.byteString().size).isEqualTo(5) assertThat(closed.get()).isTrue() } @Test fun byteStringThrowsWhenLengthsDisagree() { - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 10 + } + + override fun source(): BufferedSource { + return Buffer().writeUtf8("hello") + } } - - override fun contentLength(): Long { - return 10 - } - - override fun source(): BufferedSource { - return Buffer().writeUtf8("hello") - } - } assertFailsWith { body.byteString() }.also { expected -> assertThat(expected.message).isEqualTo( - "Content-Length (10) and stream length (5) disagree" + "Content-Length (10) and stream length (5) disagree", ) } } @Test fun byteStringThrowsMoreThanIntMaxValue() { - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null - } - - override fun contentLength(): Long { - return Int.MAX_VALUE + 1L - } - - override fun source(): BufferedSource { - throw AssertionError() + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return Int.MAX_VALUE + 1L + } + + override fun source(): BufferedSource { + throw AssertionError() + } } - } assertFailsWith { body.byteString() }.also { expected -> assertThat(expected.message).isEqualTo( - "Cannot buffer entire body for content length: 2147483648" + "Cannot buffer entire body for content length: 2147483648", ) } } @@ -444,26 +452,27 @@ class ResponseBodyJvmTest { @Test fun byteStreamClosesUnderlyingSource() { val closed = AtomicBoolean() - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null - } - - override fun contentLength(): Long { - return 5 + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 5 + } + + override fun source(): BufferedSource { + val source = Buffer().writeUtf8("hello") + return object : ForwardingSource(source) { + @Throws(IOException::class) + override fun close() { + closed.set(true) + super.close() + } + }.buffer() + } } - - override fun source(): BufferedSource { - val source = Buffer().writeUtf8("hello") - return object : ForwardingSource(source) { - @Throws(IOException::class) - override fun close() { - closed.set(true) - super.close() - } - }.buffer() - } - } body.byteStream().close() assertThat(closed.get()).isTrue() } @@ -477,7 +486,10 @@ class ResponseBodyJvmTest { companion object { @JvmOverloads - fun body(hex: String, charset: String? = null): ResponseBody { + fun body( + hex: String, + charset: String? = null, + ): ResponseBody { val mediaType = if (charset == null) null else "any/thing; charset=$charset".toMediaType() return hex.decodeHex().toResponseBody(mediaType) } diff --git a/okhttp/src/test/java/okhttp3/ResponseBodyTest.kt b/okhttp/src/test/java/okhttp3/ResponseBodyTest.kt index 2a0dbdb3af61..f893fe6229dd 100644 --- a/okhttp/src/test/java/okhttp3/ResponseBodyTest.kt +++ b/okhttp/src/test/java/okhttp3/ResponseBodyTest.kt @@ -43,50 +43,52 @@ class ResponseBodyTest { fun sourceClosesUnderlyingSource() { var closed = false - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 5 + } + + override fun source(): BufferedSource { + val source = Buffer().writeUtf8("hello") + return object : ForwardingSource(source) { + override fun close() { + closed = true + super.close() + } + }.buffer() + } } - - override fun contentLength(): Long { - return 5 - } - - override fun source(): BufferedSource { - val source = Buffer().writeUtf8("hello") - return object : ForwardingSource(source) { - override fun close() { - closed = true - super.close() - } - }.buffer() - } - } body.source().close() assertThat(closed).isTrue() } @Test fun throwingUnderlyingSourceClosesQuietly() { - val body: ResponseBody = object : ResponseBody() { - override fun contentType(): MediaType? { - return null - } - - override fun contentLength(): Long { - return 5 - } - - override fun source(): BufferedSource { - val source = Buffer().writeUtf8("hello") - return object : ForwardingSource(source) { - @Throws(IOException::class) - override fun close() { - throw IOException("Broken!") - } - }.buffer() + val body: ResponseBody = + object : ResponseBody() { + override fun contentType(): MediaType? { + return null + } + + override fun contentLength(): Long { + return 5 + } + + override fun source(): BufferedSource { + val source = Buffer().writeUtf8("hello") + return object : ForwardingSource(source) { + @Throws(IOException::class) + override fun close() { + throw IOException("Broken!") + } + }.buffer() + } } - } assertThat(body.source().readUtf8()).isEqualTo("hello") body.close() } @@ -135,9 +137,12 @@ class ResponseBodyTest { } abstract class ForwardingSource( - val delegate: Source + val delegate: Source, ) : Source { - override fun read(sink: Buffer, byteCount: Long): Long = delegate.read(sink, byteCount) + override fun read( + sink: Buffer, + byteCount: Long, + ): Long = delegate.read(sink, byteCount) override fun timeout() = delegate.timeout() diff --git a/okhttp/src/test/java/okhttp3/ResponseCommonTest.kt b/okhttp/src/test/java/okhttp3/ResponseCommonTest.kt index 0f2b2c04a94e..4a66cc81abd6 100644 --- a/okhttp/src/test/java/okhttp3/ResponseCommonTest.kt +++ b/okhttp/src/test/java/okhttp3/ResponseCommonTest.kt @@ -63,16 +63,17 @@ class ResponseCommonTest { } @Test fun defaultResponseBodyIsEmpty() { - val response = Response.Builder() - .request( - Request.Builder() - .url("https://example.com/") - .build() - ) - .protocol(Protocol.HTTP_1_1) - .code(200) - .message("OK") - .build() + val response = + Response.Builder() + .request( + Request.Builder() + .url("https://example.com/") + .build(), + ) + .protocol(Protocol.HTTP_1_1) + .code(200) + .message("OK") + .build() assertThat(response.body.contentType()).isNull() assertThat(response.body.contentLength()).isEqualTo(0L) assertThat(response.body.byteString()).isEqualTo(EMPTY) @@ -84,30 +85,38 @@ class ResponseCommonTest { */ private fun responseBody(content: String): ResponseBody { val data = Buffer().writeUtf8(content) - val source: Source = object : Source { - var closed = false - override fun close() { - closed = true - } + val source: Source = + object : Source { + var closed = false - override fun read(sink: Buffer, byteCount: Long): Long { - check(!closed) - return data.read(sink, byteCount) - } + override fun close() { + closed = true + } - override fun timeout(): Timeout { - return Timeout.NONE + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { + check(!closed) + return data.read(sink, byteCount) + } + + override fun timeout(): Timeout { + return Timeout.NONE + } } - } return source.buffer().asResponseBody(null, -1) } - private fun newResponse(responseBody: ResponseBody, code: Int = 200): Response { + private fun newResponse( + responseBody: ResponseBody, + code: Int = 200, + ): Response { return Response.Builder() .request( Request.Builder() .url("https://example.com/") - .build() + .build(), ) .protocol(Protocol.HTTP_1_1) .code(code) diff --git a/okhttp/src/test/java/okhttp3/ResponseJvmTest.kt b/okhttp/src/test/java/okhttp3/ResponseJvmTest.kt index 5b19dee21e22..b69990c1cf5a 100644 --- a/okhttp/src/test/java/okhttp3/ResponseJvmTest.kt +++ b/okhttp/src/test/java/okhttp3/ResponseJvmTest.kt @@ -38,10 +38,11 @@ class ResponseJvmTest { @Test fun testFailsIfTrailersNotSet() { - val response = newResponse("".toResponseBody()) { - // All live paths (Http1, Http2) in OkHttp do this - trailers { error("trailers not available") } - } + val response = + newResponse("".toResponseBody()) { + // All live paths (Http1, Http2) in OkHttp do this + trailers { error("trailers not available") } + } assertFailsWith(message = "trailers not available") { response.trailers() @@ -50,11 +51,12 @@ class ResponseJvmTest { @Test fun worksIfTrailersSet() { - val response = newResponse("".toResponseBody()) { - trailers { - Headers.headersOf("a", "b") + val response = + newResponse("".toResponseBody()) { + trailers { + Headers.headersOf("a", "b") + } } - } assertThat(response.trailers()["a"]).isEqualTo("b") } @@ -74,34 +76,39 @@ class ResponseJvmTest { */ private fun responseBody(content: String): ResponseBody { val data = Buffer().writeUtf8(content) - val source: Source = object : Source { - var closed = false - override fun close() { - closed = true - } + val source: Source = + object : Source { + var closed = false - override fun read(sink: Buffer, byteCount: Long): Long { - check(!closed) - return data.read(sink, byteCount) - } + override fun close() { + closed = true + } + + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { + check(!closed) + return data.read(sink, byteCount) + } - override fun timeout(): Timeout { - return Timeout.NONE + override fun timeout(): Timeout { + return Timeout.NONE + } } - } return source.buffer().asResponseBody(null, -1) } private fun newResponse( responseBody: ResponseBody, code: Int = 200, - fn: Response.Builder.() -> Unit = {} + fn: Response.Builder.() -> Unit = {}, ): Response { return Response.Builder() .request( Request.Builder() .url("https://example.com/") - .build() + .build(), ) .protocol(Protocol.HTTP_1_1) .code(code) diff --git a/okhttp/src/test/java/okhttp3/RouteFailureTest.kt b/okhttp/src/test/java/okhttp3/RouteFailureTest.kt index 7751c56a1e0c..e56875e7c173 100644 --- a/okhttp/src/test/java/okhttp3/RouteFailureTest.kt +++ b/okhttp/src/test/java/okhttp3/RouteFailureTest.kt @@ -59,26 +59,28 @@ class RouteFailureTest { val ipv4 = InetAddress.getByName("203.0.113.1") val ipv6 = InetAddress.getByName("2001:db8:ffff:ffff:ffff:ffff:ffff:1") - val refusedStream = MockResponse( - socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode), - ) + val refusedStream = + MockResponse( + socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode), + ) val bodyResponse = MockResponse(body = "body") @BeforeEach fun setUp( server: MockWebServer, - @MockWebServerInstance("server2") server2: MockWebServer + @MockWebServerInstance("server2") server2: MockWebServer, ) { this.server1 = server this.server2 = server2 socketFactory = SpecificHostSocketFactory(InetSocketAddress(server.hostName, server.port)) - client = clientTestRule.newClientBuilder() - .dns(dns) - .socketFactory(socketFactory) - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + client = + clientTestRule.newClientBuilder() + .dns(dns) + .socketFactory(socketFactory) + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() } @Test @@ -94,12 +96,13 @@ class RouteFailureTest { socketFactory[ipv6] = server1.inetSocketAddress socketFactory[ipv4] = server2.inetSocketAddress - client = client.newBuilder() - .fastFallback(false) - .apply { - retryOnConnectionFailure = false - } - .build() + client = + client.newBuilder() + .fastFallback(false) + .apply { + retryOnConnectionFailure = false + } + .build() executeSynchronously(request) .assertFailureMatches("stream was reset: REFUSED_STREAM") @@ -112,7 +115,7 @@ class RouteFailureTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @@ -130,12 +133,13 @@ class RouteFailureTest { socketFactory[ipv6] = server1.inetSocketAddress socketFactory[ipv4] = server2.inetSocketAddress - client = client.newBuilder() - .fastFallback(false) - .apply { - retryOnConnectionFailure = true - } - .build() + client = + client.newBuilder() + .fastFallback(false) + .apply { + retryOnConnectionFailure = true + } + .build() executeSynchronously(request) .assertBody("body") @@ -172,12 +176,13 @@ class RouteFailureTest { socketFactory[ipv6] = server1.inetSocketAddress socketFactory[ipv4] = server2.inetSocketAddress - client = client.newBuilder() - .fastFallback(true) - .apply { - retryOnConnectionFailure = false - } - .build() + client = + client.newBuilder() + .fastFallback(true) + .apply { + retryOnConnectionFailure = false + } + .build() executeSynchronously(request) .assertFailureMatches("stream was reset: REFUSED_STREAM") @@ -190,7 +195,7 @@ class RouteFailureTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @@ -208,12 +213,13 @@ class RouteFailureTest { socketFactory[ipv6] = server1.inetSocketAddress socketFactory[ipv4] = server2.inetSocketAddress - client = client.newBuilder() - .fastFallback(true) - .apply { - retryOnConnectionFailure = true - } - .build() + client = + client.newBuilder() + .fastFallback(true) + .apply { + retryOnConnectionFailure = true + } + .build() executeSynchronously(request) .assertBody("body") @@ -233,7 +239,7 @@ class RouteFailureTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @@ -249,12 +255,13 @@ class RouteFailureTest { dns[server1.hostName] = listOf(ipv6) socketFactory[ipv6] = server1.inetSocketAddress - client = client.newBuilder() - .fastFallback(false) - .apply { - retryOnConnectionFailure = true - } - .build() + client = + client.newBuilder() + .fastFallback(false) + .apply { + retryOnConnectionFailure = true + } + .build() executeSynchronously(request) .assertFailureMatches("stream was reset: REFUSED_STREAM") @@ -266,7 +273,7 @@ class RouteFailureTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @@ -282,12 +289,13 @@ class RouteFailureTest { dns[server1.hostName] = listOf(ipv6) socketFactory[ipv6] = server1.inetSocketAddress - client = client.newBuilder() - .fastFallback(true) - .apply { - retryOnConnectionFailure = true - } - .build() + client = + client.newBuilder() + .fastFallback(true) + .apply { + retryOnConnectionFailure = true + } + .build() executeSynchronously(request) .assertFailureMatches("stream was reset: REFUSED_STREAM") @@ -299,15 +307,13 @@ class RouteFailureTest { "ConnectStart", "ConnectEnd", "ConnectionAcquired", - "ConnectionReleased" + "ConnectionReleased", ) } @ParameterizedTest @ValueSource(booleans = [false, true]) - fun proxyMoveTest( - cleanShutdown: Boolean - ) { + fun proxyMoveTest(cleanShutdown: Boolean) { // Define a single Proxy at myproxy:8008 that will artificially move during the test val proxySelector = RecordingProxySelector() proxySelector.proxies.add(Proxy(Proxy.Type.HTTP, InetSocketAddress("myproxy", 8008))) @@ -372,20 +378,22 @@ class RouteFailureTest { private fun enableProtocol(protocol: Protocol) { enableTls() - client = client.newBuilder() - .protocols(listOf(protocol, Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .protocols(listOf(protocol, Protocol.HTTP_1_1)) + .build() server1.protocols = client.protocols server2.protocols = client.protocols } private fun enableTls() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() server1.useHttps(handshakeCertificates.sslSocketFactory()) server2.useHttps(handshakeCertificates.sslSocketFactory()) } diff --git a/okhttp/src/test/java/okhttp3/ServerTruncatesRequestTest.kt b/okhttp/src/test/java/okhttp3/ServerTruncatesRequestTest.kt index 9b84fb239cf7..1f8a28fe67d0 100644 --- a/okhttp/src/test/java/okhttp3/ServerTruncatesRequestTest.kt +++ b/okhttp/src/test/java/okhttp3/ServerTruncatesRequestTest.kt @@ -19,7 +19,9 @@ import assertk.assertThat import assertk.assertions.hasMessage import assertk.assertions.isEqualTo import assertk.assertions.isNotNull +import assertk.fail import javax.net.ssl.SSLSocket +import kotlin.test.assertFailsWith import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import mockwebserver3.SocketPolicy.DoNotReadRequestBody @@ -36,8 +38,6 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.Timeout import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.RegisterExtension -import assertk.fail -import kotlin.test.assertFailsWith @Timeout(30) @Tag("Slowish") @@ -45,6 +45,7 @@ class ServerTruncatesRequestTest { @RegisterExtension @JvmField val platform = PlatformRule() + @RegisterExtension @JvmField var clientTestRule = OkHttpClientTestRule() @@ -52,9 +53,10 @@ class ServerTruncatesRequestTest { private val listener = RecordingEventListener() private val handshakeCertificates = platform.localhostHandshakeCertificates() - private var client = clientTestRule.newClientBuilder() - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + private var client = + clientTestRule.newClientBuilder() + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() private lateinit var server: MockWebServer @@ -81,15 +83,16 @@ class ServerTruncatesRequestTest { MockResponse( body = "abc", socketPolicy = DoNotReadRequestBody(ErrorCode.NO_ERROR.httpCode), - ) + ), ) - val call = client.newCall( - Request( - url = server.url("/"), - body = SlowRequestBody, + val call = + client.newCall( + Request( + url = server.url("/"), + body = SlowRequestBody, + ), ) - ) call.execute().use { response -> assertThat(response.body.string()).isEqualTo("abc") @@ -138,17 +141,18 @@ class ServerTruncatesRequestTest { MockResponse( body = "abc", socketPolicy = DoNotReadRequestBody(ErrorCode.NO_ERROR.httpCode), - ) + ), ) val requestBody = AsyncRequestBody() - val call = client.newCall( - Request( - url = server.url("/"), - body = requestBody, + val call = + client.newCall( + Request( + url = server.url("/"), + body = requestBody, + ), ) - ) call.execute().use { response -> assertThat(response.body.string()).isEqualTo("abc") @@ -177,9 +181,10 @@ class ServerTruncatesRequestTest { } private fun serverTruncatesRequestButTrailersCanStillBeRead(http2: Boolean) { - val mockResponse = MockResponse.Builder() - .socketPolicy(DoNotReadRequestBody(ErrorCode.NO_ERROR.httpCode)) - .trailers(headersOf("caboose", "xyz")) + val mockResponse = + MockResponse.Builder() + .socketPolicy(DoNotReadRequestBody(ErrorCode.NO_ERROR.httpCode)) + .trailers(headersOf("caboose", "xyz")) // Trailers always work for HTTP/2, but only for chunked bodies in HTTP/1. if (http2) { @@ -190,12 +195,13 @@ class ServerTruncatesRequestTest { server.enqueue(mockResponse.build()) - val call = client.newCall( - Request( - url = server.url("/"), - body = SlowRequestBody, + val call = + client.newCall( + Request( + url = server.url("/"), + body = SlowRequestBody, + ), ) - ) call.execute().use { response -> assertThat(response.body.string()).isEqualTo("abc") @@ -211,20 +217,24 @@ class ServerTruncatesRequestTest { server.enqueue(MockResponse(code = 200, body = "Req1")) server.enqueue(MockResponse(code = 200, body = "Req2")) - val eventListener = object : EventListener() { - var socket: SSLSocket? = null - var closed = false + val eventListener = + object : EventListener() { + var socket: SSLSocket? = null + var closed = false - override fun connectionAcquired(call: Call, connection: Connection) { - socket = connection.socket() as SSLSocket - } + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + socket = connection.socket() as SSLSocket + } - override fun requestHeadersStart(call: Call) { - if (closed) { - throw IOException("fake socket failure") + override fun requestHeadersStart(call: Call) { + if (closed) { + throw IOException("fake socket failure") + } } } - } val localClient = client.newBuilder().eventListener(eventListener).build() val call1 = localClient.newCall(Request(server.url("/"))) @@ -248,20 +258,22 @@ class ServerTruncatesRequestTest { fun noAttemptToReadResponseIfLoadingRequestBodyIsSourceOfFailure() { server.enqueue(MockResponse(body = "abc")) - val requestBody = object : RequestBody() { - override fun contentType(): MediaType? = null + val requestBody = + object : RequestBody() { + override fun contentType(): MediaType? = null - override fun writeTo(sink: BufferedSink) { - throw IOException("boom") // Despite this exception, 'sink' is healthy. + override fun writeTo(sink: BufferedSink) { + throw IOException("boom") // Despite this exception, 'sink' is healthy. + } } - } - val callA = client.newCall( - Request( - url = server.url("/"), - body = requestBody, + val callA = + client.newCall( + Request( + url = server.url("/"), + body = requestBody, + ), ) - ) assertFailsWith { callA.execute() @@ -289,20 +301,22 @@ class ServerTruncatesRequestTest { private fun enableProtocol(protocol: Protocol) { enableTls() - client = client.newBuilder() - .protocols(listOf(protocol, Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .protocols(listOf(protocol, Protocol.HTTP_1_1)) + .build() server.protocols = client.protocols } private fun enableTls() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } diff --git a/okhttp/src/test/java/okhttp3/SessionReuseTest.kt b/okhttp/src/test/java/okhttp3/SessionReuseTest.kt index 0149f9663fb3..0bbbbfe70950 100644 --- a/okhttp/src/test/java/okhttp3/SessionReuseTest.kt +++ b/okhttp/src/test/java/okhttp3/SessionReuseTest.kt @@ -35,8 +35,11 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource class SessionReuseTest { - @JvmField @RegisterExtension var platform = PlatformRule() - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule() + @JvmField @RegisterExtension + var platform = PlatformRule() + + @JvmField @RegisterExtension + val clientTestRule = OkHttpClientTestRule() private val handshakeCertificates = platform.localhostHandshakeCertificates() @@ -69,35 +72,45 @@ class SessionReuseTest { enableTls() val tlsVersion = TlsVersion.forJavaName(tlsVersion) - val spec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .tlsVersions(tlsVersion) - .build() + val spec = + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(tlsVersion) + .build() var reuseSession = false val sslContext = handshakeCertificates.sslContext() val systemSslSocketFactory = sslContext.socketFactory - val sslSocketFactory = object : DelegatingSSLSocketFactory(systemSslSocketFactory) { - override fun configureSocket(sslSocket: SSLSocket): SSLSocket { - return sslSocket.apply { - if (reuseSession) { - this.enableSessionCreation = false + val sslSocketFactory = + object : DelegatingSSLSocketFactory(systemSslSocketFactory) { + override fun configureSocket(sslSocket: SSLSocket): SSLSocket { + return sslSocket.apply { + if (reuseSession) { + this.enableSessionCreation = false + } } } } - } - client = client.newBuilder() - .connectionSpecs(listOf(spec)) - .eventListenerFactory(clientTestRule.wrap(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - val sslSocket = connection.socket() as SSLSocket - - sessionIds.add(sslSocket.session.id.toByteString().hex()) - } - })) - .sslSocketFactory(sslSocketFactory, handshakeCertificates.trustManager) - .build() + client = + client.newBuilder() + .connectionSpecs(listOf(spec)) + .eventListenerFactory( + clientTestRule.wrap( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + val sslSocket = connection.socket() as SSLSocket + + sessionIds.add(sslSocket.session.id.toByteString().hex()) + } + }, + ), + ) + .sslSocketFactory(sslSocketFactory, handshakeCertificates.trustManager) + .build() server.enqueue(MockResponse(body = "abc1")) server.enqueue(MockResponse(body = "abc2")) @@ -156,11 +169,12 @@ class SessionReuseTest { } private fun enableTls() { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) } } diff --git a/okhttp/src/test/java/okhttp3/SocketChannelTest.kt b/okhttp/src/test/java/okhttp3/SocketChannelTest.kt index 68d5b9c285fb..b60ccd9582a2 100644 --- a/okhttp/src/test/java/okhttp3/SocketChannelTest.kt +++ b/okhttp/src/test/java/okhttp3/SocketChannelTest.kt @@ -54,25 +54,31 @@ import org.junit.jupiter.params.provider.MethodSource @Timeout(6) @Tag("slow") class SocketChannelTest { - @JvmField @RegisterExtension val platform = PlatformRule() - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule().apply { - recordFrames = true - // recordSslDebug = true - } + @JvmField @RegisterExtension + val platform = PlatformRule() + + @JvmField @RegisterExtension + val clientTestRule = + OkHttpClientTestRule().apply { + recordFrames = true + // recordSslDebug = true + } // https://tools.ietf.org/html/rfc6066#page-6 specifies a FQDN is required. val hostname = "local.host" - private val handshakeCertificates = run { - // Generate a self-signed cert for the server to serve and the client to trust. - val heldCertificate = HeldCertificate.Builder() - .commonName(hostname) - .addSubjectAlternativeName(hostname) - .build() - HandshakeCertificates.Builder() - .heldCertificate(heldCertificate) - .addTrustedCertificate(heldCertificate.certificate) - .build() - } + private val handshakeCertificates = + run { + // Generate a self-signed cert for the server to serve and the client to trust. + val heldCertificate = + HeldCertificate.Builder() + .commonName(hostname) + .addSubjectAlternativeName(hostname) + .build() + HandshakeCertificates.Builder() + .heldCertificate(heldCertificate) + .addTrustedCertificate(heldCertificate.certificate) + .build() + } private var acceptedHostName: String? = null private lateinit var server: MockWebServer @@ -94,90 +100,108 @@ class SocketChannelTest { socketMode.socketMode == Channel && socketMode.protocol == HTTP_2 && socketMode.tlsExtensionMode == STANDARD, - "failing for channel and h2" + "failing for channel and h2", ) if (socketMode is TlsInstance) { assumeTrue((socketMode.provider == CONSCRYPT) == platform.isConscrypt()) } - val client = clientTestRule.newClientBuilder() - .dns { listOf(InetAddress.getByName("localhost")) } - .callTimeout(4, SECONDS) - .writeTimeout(2, SECONDS) - .readTimeout(2, SECONDS) - .apply { - if (socketMode is TlsInstance) { - if (socketMode.socketMode == Channel) { - socketFactory(ChannelSocketFactory()) - } + val client = + clientTestRule.newClientBuilder() + .dns { listOf(InetAddress.getByName("localhost")) } + .callTimeout(4, SECONDS) + .writeTimeout(2, SECONDS) + .readTimeout(2, SECONDS) + .apply { + if (socketMode is TlsInstance) { + if (socketMode.socketMode == Channel) { + socketFactory(ChannelSocketFactory()) + } - connectionSpecs( - listOf( - ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS) - .tlsVersions(socketMode.tlsVersion) - .supportsTlsExtensions(socketMode.tlsExtensionMode == STANDARD) - .build() + connectionSpecs( + listOf( + ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS) + .tlsVersions(socketMode.tlsVersion) + .supportsTlsExtensions(socketMode.tlsExtensionMode == STANDARD) + .build(), + ), ) - ) - val sslSocketFactory = handshakeCertificates.sslSocketFactory() + val sslSocketFactory = handshakeCertificates.sslSocketFactory() - sslSocketFactory( - sslSocketFactory, handshakeCertificates.trustManager - ) + sslSocketFactory( + sslSocketFactory, + handshakeCertificates.trustManager, + ) - when (socketMode.protocol) { - HTTP_2 -> protocols(listOf(HTTP_2, HTTP_1_1)) - HTTP_1_1 -> protocols(listOf(HTTP_1_1)) - else -> TODO() - } + when (socketMode.protocol) { + HTTP_2 -> protocols(listOf(HTTP_2, HTTP_1_1)) + HTTP_1_1 -> protocols(listOf(HTTP_1_1)) + else -> TODO() + } - val serverSslSocketFactory = object: DelegatingSSLSocketFactory(sslSocketFactory) { - override fun configureSocket(sslSocket: SSLSocket): SSLSocket { - return sslSocket.apply { - sslParameters = sslParameters.apply { - sniMatchers = listOf(object : SNIMatcher(StandardConstants.SNI_HOST_NAME) { - override fun matches(serverName: SNIServerName): Boolean { - acceptedHostName = (serverName as SNIHostName).asciiName - return true - } - }) + val serverSslSocketFactory = + object : DelegatingSSLSocketFactory(sslSocketFactory) { + override fun configureSocket(sslSocket: SSLSocket): SSLSocket { + return sslSocket.apply { + sslParameters = + sslParameters.apply { + sniMatchers = + listOf( + object : SNIMatcher(StandardConstants.SNI_HOST_NAME) { + override fun matches(serverName: SNIServerName): Boolean { + acceptedHostName = (serverName as SNIHostName).asciiName + return true + } + }, + ) + } + } } } - } + server.useHttps(serverSslSocketFactory) + } else if (socketMode == Channel) { + socketFactory(ChannelSocketFactory()) } - server.useHttps(serverSslSocketFactory) - } else if (socketMode == Channel) { - socketFactory(ChannelSocketFactory()) } - } - .build() + .build() server.enqueue(MockResponse(body = "abc")) - @Suppress("HttpUrlsUsage") val url = - if (socketMode is TlsInstance) + @Suppress("HttpUrlsUsage") + val url = + if (socketMode is TlsInstance) { "https://$hostname:${server.port}/get" - else + } else { "http://$hostname:${server.port}/get" + } - val request = Request.Builder() - .url(url) - .build() + val request = + Request.Builder() + .url(url) + .build() val promise = CompletableFuture() val call = client.newCall(request) - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - promise.completeExceptionally(e) - } + call.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + promise.completeExceptionally(e) + } - override fun onResponse(call: Call, response: Response) { - promise.complete(response) - } - }) + override fun onResponse( + call: Call, + response: Response, + ) { + promise.complete(response) + } + }, + ) val response = promise.get(4, SECONDS) @@ -199,7 +223,8 @@ class SocketChannelTest { } companion object { - @Suppress("unused") @JvmStatic + @Suppress("unused") + @JvmStatic fun connectionTypes(): List = listOf(CONSCRYPT, JSSE).flatMap { provider -> listOf(HTTP_1_1, HTTP_2).flatMap { protocol -> @@ -230,17 +255,17 @@ data class TlsInstance( val protocol: Protocol, val tlsVersion: TlsVersion, val socketMode: SocketMode, - val tlsExtensionMode: TlsExtensionMode + val tlsExtensionMode: TlsExtensionMode, ) : SocketMode() { override fun toString(): String = "$provider/$protocol/$tlsVersion/$socketMode/$tlsExtensionMode" } enum class Provider { JSSE, - CONSCRYPT + CONSCRYPT, } enum class TlsExtensionMode { DISABLED, - STANDARD + STANDARD, } diff --git a/okhttp/src/test/java/okhttp3/SocksProxy.kt b/okhttp/src/test/java/okhttp3/SocksProxy.kt index 4dc4e390d653..6873a0a1c911 100644 --- a/okhttp/src/test/java/okhttp3/SocksProxy.kt +++ b/okhttp/src/test/java/okhttp3/SocksProxy.kt @@ -79,7 +79,7 @@ class SocksProxy { fun proxy(): Proxy { return Proxy( Proxy.Type.SOCKS, - InetSocketAddress.createUnresolved("localhost", serverSocket!!.localPort) + InetSocketAddress.createUnresolved("localhost", serverSocket!!.localPort), ) } @@ -111,7 +111,7 @@ class SocksProxy { private fun hello( fromSource: BufferedSource, - fromSink: BufferedSink + fromSink: BufferedSink, ) { val version = fromSource.readByte() and 0xff val methodCount = fromSource.readByte() and 0xff @@ -136,8 +136,9 @@ class SocksProxy { } private fun acceptCommand( - fromAddress: InetAddress, fromSource: BufferedSource, - fromSink: BufferedSink + fromAddress: InetAddress, + fromSource: BufferedSource, + fromSink: BufferedSink, ) { // Read the command. val version = fromSource.readByte() and 0xff @@ -149,25 +150,26 @@ class SocksProxy { if (reserved != 0) throw ProtocolException("unexpected reserved: $reserved") val addressType = fromSource.readByte() and 0xff - val toAddress = when (addressType) { - ADDRESS_TYPE_IPV4 -> { - InetAddress.getByAddress(fromSource.readByteArray(4L)) - } + val toAddress = + when (addressType) { + ADDRESS_TYPE_IPV4 -> { + InetAddress.getByAddress(fromSource.readByteArray(4L)) + } - ADDRESS_TYPE_DOMAIN_NAME -> { - val domainNameLength: Int = fromSource.readByte() and 0xff - val domainName = fromSource.readUtf8(domainNameLength.toLong()) - // Resolve HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS to localhost. - when { - domainName.equals(HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS, ignoreCase = true) -> { - InetAddress.getByName("localhost") + ADDRESS_TYPE_DOMAIN_NAME -> { + val domainNameLength: Int = fromSource.readByte() and 0xff + val domainName = fromSource.readUtf8(domainNameLength.toLong()) + // Resolve HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS to localhost. + when { + domainName.equals(HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS, ignoreCase = true) -> { + InetAddress.getByName("localhost") + } + else -> InetAddress.getByName(domainName) } - else -> InetAddress.getByName(domainName) } - } - else -> throw ProtocolException("unsupported address type: $addressType") - } + else -> throw ProtocolException("unsupported address type: $addressType") + } val port = fromSource.readShort() and 0xffff @@ -205,7 +207,7 @@ class SocksProxy { fromAddress: InetAddress, toAddress: InetAddress, source: BufferedSource, - sink: BufferedSink + sink: BufferedSink, ) { executor.execute { val name = "SocksProxy $fromAddress to $toAddress" diff --git a/okhttp/src/test/java/okhttp3/SocksProxyTest.kt b/okhttp/src/test/java/okhttp3/SocksProxyTest.kt index efa69e41d439..65db364d9dcb 100644 --- a/okhttp/src/test/java/okhttp3/SocksProxyTest.kt +++ b/okhttp/src/test/java/okhttp3/SocksProxyTest.kt @@ -53,9 +53,10 @@ class SocksProxyTest { fun proxy() { server.enqueue(MockResponse.Builder().body("abc").build()) server.enqueue(MockResponse.Builder().body("def").build()) - val client = clientTestRule.newClientBuilder() - .proxy(socksProxy.proxy()) - .build() + val client = + clientTestRule.newClientBuilder() + .proxy(socksProxy.proxy()) + .build() val request1 = Request.Builder().url(server.url("/")).build() val response1 = client.newCall(request1).execute() assertThat(response1.body.string()).isEqualTo("abc") @@ -70,18 +71,20 @@ class SocksProxyTest { @Test fun proxySelector() { server.enqueue(MockResponse.Builder().body("abc").build()) - val proxySelector: ProxySelector = object : ProxySelector() { - override fun select(uri: URI) = listOf(socksProxy.proxy()) + val proxySelector: ProxySelector = + object : ProxySelector() { + override fun select(uri: URI) = listOf(socksProxy.proxy()) - override fun connectFailed( - uri: URI, - socketAddress: SocketAddress, - e: IOException, - ) = error("unexpected call") - } - val client = clientTestRule.newClientBuilder() - .proxySelector(proxySelector) - .build() + override fun connectFailed( + uri: URI, + socketAddress: SocketAddress, + e: IOException, + ) = error("unexpected call") + } + val client = + clientTestRule.newClientBuilder() + .proxySelector(proxySelector) + .build() val request = Request.Builder().url(server.url("/")).build() val response = client.newCall(request).execute() assertThat(response.body.string()).isEqualTo("abc") @@ -92,13 +95,15 @@ class SocksProxyTest { fun checkRemoteDNSResolve() { // This testcase will fail if the target is resolved locally instead of through the proxy. server.enqueue(MockResponse.Builder().body("abc").build()) - val client = clientTestRule.newClientBuilder() - .proxy(socksProxy.proxy()) - .build() - val url = server.url("/") - .newBuilder() - .host(SocksProxy.HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS) - .build() + val client = + clientTestRule.newClientBuilder() + .proxy(socksProxy.proxy()) + .build() + val url = + server.url("/") + .newBuilder() + .host(SocksProxy.HOSTNAME_THAT_ONLY_THE_PROXY_KNOWS) + .build() val request = Request.Builder().url(url).build() val response1 = client.newCall(request).execute() assertThat(response1.body.string()).isEqualTo("abc") diff --git a/okhttp/src/test/java/okhttp3/TestLogHandler.kt b/okhttp/src/test/java/okhttp3/TestLogHandler.kt index 9e0d8efa8b35..f1a688898136 100644 --- a/okhttp/src/test/java/okhttp3/TestLogHandler.kt +++ b/okhttp/src/test/java/okhttp3/TestLogHandler.kt @@ -39,17 +39,18 @@ class TestLogHandler( private val logs = LinkedBlockingQueue() - private val handler = object : Handler() { - override fun publish(logRecord: LogRecord) { - logs += "${logRecord.level}: ${logRecord.message}" - } + private val handler = + object : Handler() { + override fun publish(logRecord: LogRecord) { + logs += "${logRecord.level}: ${logRecord.message}" + } - override fun flush() { - } + override fun flush() { + } - override fun close() { + override fun close() { + } } - } private var previousLevel: Level? = null diff --git a/okhttp/src/test/java/okhttp3/TestTls13Request.kt b/okhttp/src/test/java/okhttp3/TestTls13Request.kt index a5d1862799b2..f414a10b51fa 100644 --- a/okhttp/src/test/java/okhttp3/TestTls13Request.kt +++ b/okhttp/src/test/java/okhttp3/TestTls13Request.kt @@ -6,29 +6,35 @@ import okhttp3.internal.platform.Platform import org.conscrypt.Conscrypt // TLS 1.3 -private val TLS13_CIPHER_SUITES = listOf( - CipherSuite.TLS_AES_128_GCM_SHA256, - CipherSuite.TLS_AES_256_GCM_SHA384, - CipherSuite.TLS_CHACHA20_POLY1305_SHA256, - CipherSuite.TLS_AES_128_CCM_SHA256, - CipherSuite.TLS_AES_128_CCM_8_SHA256 -) +private val TLS13_CIPHER_SUITES = + listOf( + CipherSuite.TLS_AES_128_GCM_SHA256, + CipherSuite.TLS_AES_256_GCM_SHA384, + CipherSuite.TLS_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_AES_128_CCM_SHA256, + CipherSuite.TLS_AES_128_CCM_8_SHA256, + ) /** * A TLS 1.3 only Connection Spec. This will be eventually be exposed * as part of MODERN_TLS or folded into the default OkHttp client once published and * available in JDK11 or Conscrypt. */ -private val TLS_13 = ConnectionSpec.Builder(true) - .cipherSuites(*TLS13_CIPHER_SUITES.toTypedArray()) - .tlsVersions(TlsVersion.TLS_1_3) - .build() +private val TLS_13 = + ConnectionSpec.Builder(true) + .cipherSuites(*TLS13_CIPHER_SUITES.toTypedArray()) + .tlsVersions(TlsVersion.TLS_1_3) + .build() -private val TLS_12 = ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS) - .tlsVersions(TlsVersion.TLS_1_2) - .build() +private val TLS_12 = + ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS) + .tlsVersions(TlsVersion.TLS_1_2) + .build() -private fun testClient(urls: List, client: OkHttpClient) { +private fun testClient( + urls: List, + client: OkHttpClient, +) { try { for (url in urls) { sendRequest(client, url) @@ -45,19 +51,23 @@ private fun buildClient(vararg specs: ConnectionSpec): OkHttpClient { .build() } -private fun sendRequest(client: OkHttpClient, url: String) { +private fun sendRequest( + client: OkHttpClient, + url: String, +) { System.out.printf("%-40s ", url) System.out.flush() println(Platform.get()) - val request = Request.Builder() - .url(url) - .build() + val request = + Request.Builder() + .url(url) + .build() try { client.newCall(request).execute().use { response -> val handshake = response.handshake println( "${handshake!!.tlsVersion} ${handshake.cipherSuite} ${response.protocol} " + - "${response.code} ${response.body.bytes().size}b" + "${response.code} ${response.body.bytes().size}b", ) } } catch (ioe: IOException) { @@ -71,24 +81,25 @@ fun main(vararg args: String) { println("Running tests using ${Platform.get()} ${System.getProperty("java.vm.version")}") // https://github.com/tlswg/tls13-spec/wiki/Implementations - val urls = listOf( - "https://enabled.tls13.com", - "https://www.howsmyssl.com/a/check", - "https://tls13.cloudflare.com", - "https://www.allizom.org/robots.txt", - "https://tls13.crypto.mozilla.org/", - "https://tls.ctf.network/robots.txt", - "https://rustls.jbp.io/", - "https://h2o.examp1e.net", - "https://mew.org/", - "https://tls13.baishancloud.com/", - "https://tls13.akamai.io/", - "https://swifttls.org/", - "https://www.googleapis.com/robots.txt", - "https://graph.facebook.com/robots.txt", - "https://api.twitter.com/robots.txt", - "https://connect.squareup.com/robots.txt", - ) + val urls = + listOf( + "https://enabled.tls13.com", + "https://www.howsmyssl.com/a/check", + "https://tls13.cloudflare.com", + "https://www.allizom.org/robots.txt", + "https://tls13.crypto.mozilla.org/", + "https://tls.ctf.network/robots.txt", + "https://rustls.jbp.io/", + "https://h2o.examp1e.net", + "https://mew.org/", + "https://tls13.baishancloud.com/", + "https://tls13.akamai.io/", + "https://swifttls.org/", + "https://www.googleapis.com/robots.txt", + "https://graph.facebook.com/robots.txt", + "https://api.twitter.com/robots.txt", + "https://connect.squareup.com/robots.txt", + ) println("TLS1.3+TLS1.2") testClient(urls, buildClient(ConnectionSpec.RESTRICTED_TLS)) diff --git a/okhttp/src/test/java/okhttp3/URLConnectionTest.kt b/okhttp/src/test/java/okhttp3/URLConnectionTest.kt index 4715444a9840..6414551c298a 100644 --- a/okhttp/src/test/java/okhttp3/URLConnectionTest.kt +++ b/okhttp/src/test/java/okhttp3/URLConnectionTest.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("ktlint:standard:filename") + package okhttp3 import assertk.assertThat @@ -84,12 +85,12 @@ import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.TestUtil.assertSuppressed import okhttp3.internal.RecordingAuthenticator import okhttp3.internal.RecordingOkAuthenticator +import okhttp3.internal.USER_AGENT import okhttp3.internal.addHeaderLenient import okhttp3.internal.authenticator.JavaNetAuthenticator import okhttp3.internal.http.HTTP_PERM_REDIRECT import okhttp3.internal.http.HTTP_TEMP_REDIRECT import okhttp3.internal.platform.Platform.Companion.get -import okhttp3.internal.USER_AGENT import okhttp3.java.net.cookiejar.JavaNetCookieJar import okhttp3.testing.Flaky import okhttp3.testing.PlatformRule @@ -127,7 +128,10 @@ class URLConnectionTest { private var cache: Cache? = null @BeforeEach - fun setUp(server: MockWebServer, @MockWebServerInstance("server2") server2: MockWebServer) { + fun setUp( + server: MockWebServer, + @MockWebServerInstance("server2") server2: MockWebServer, + ) { this.server = server this.server2 = server2 server.protocolNegotiationEnabled = false @@ -150,11 +154,12 @@ class URLConnectionTest { @Test fun requestHeaders() { server.enqueue(MockResponse()) - val request = Request.Builder() - .url(server.url("/")) - .addHeader("D", "e") - .addHeader("D", "f") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .addHeader("D", "e") + .addHeader("D", "f") + .build() assertThat(request.header("D")).isEqualTo("f") assertThat(request.header("d")).isEqualTo("f") val requestHeaders = request.headers @@ -170,11 +175,12 @@ class URLConnectionTest { @Test fun getRequestPropertyReturnsLastValue() { - val request = Request.Builder() - .url(server.url("/")) - .addHeader("A", "value1") - .addHeader("A", "value2") - .build() + val request = + Request.Builder() + .url(server.url("/")) + .addHeader("A", "value1") + .addHeader("A", "value2") + .build() assertThat(request.header("A")).isEqualTo("value2") } @@ -187,7 +193,7 @@ class URLConnectionTest { .addHeader("B: d") .addHeader("A: e") .chunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8) - .build() + .build(), ) val request = newRequest("/") val response = getResponse(request) @@ -207,9 +213,11 @@ class URLConnectionTest { @Test fun serverSendsInvalidStatusLine() { - server.enqueue(MockResponse.Builder() - .status("HTP/1.1 200 OK") - .build()) + server.enqueue( + MockResponse.Builder() + .status("HTP/1.1 200 OK") + .build(), + ) val request = newRequest("/") assertFailsWith { getResponse(request) @@ -218,9 +226,11 @@ class URLConnectionTest { @Test fun serverSendsInvalidCodeTooLarge() { - server.enqueue(MockResponse.Builder() - .status("HTTP/1.1 2147483648 OK") - .build()) + server.enqueue( + MockResponse.Builder() + .status("HTTP/1.1 2147483648 OK") + .build(), + ) val request = newRequest("/") assertFailsWith { getResponse(request) @@ -229,9 +239,11 @@ class URLConnectionTest { @Test fun serverSendsInvalidCodeNotANumber() { - server.enqueue(MockResponse.Builder() - .status("HTTP/1.1 00a OK") - .build()) + server.enqueue( + MockResponse.Builder() + .status("HTTP/1.1 00a OK") + .build(), + ) val request = newRequest("/") assertFailsWith { getResponse(request) @@ -240,9 +252,11 @@ class URLConnectionTest { @Test fun serverSendsUnnecessaryWhitespace() { - server.enqueue(MockResponse.Builder() - .status(" HTTP/1.1 2147483648 OK") - .build()) + server.enqueue( + MockResponse.Builder() + .status(" HTTP/1.1 2147483648 OK") + .build(), + ) val request = newRequest("/") assertFailsWith { getResponse(request) @@ -272,18 +286,20 @@ class URLConnectionTest { server.enqueue(MockResponse(body = "abc")) // Use a misconfigured proxy to guarantee that the request is retried. - client = client.newBuilder() - .proxySelector( - FakeProxySelector() - .addProxy(server2.toProxyAddress()) - .addProxy(Proxy.NO_PROXY) - ) - .build() + client = + client.newBuilder() + .proxySelector( + FakeProxySelector() + .addProxy(server2.toProxyAddress()) + .addProxy(Proxy.NO_PROXY), + ) + .build() server2.shutdown() - val request = Request( - url = server.url("/def"), - body = transferKind.newRequestBody("body"), - ) + val request = + Request( + url = server.url("/def"), + body = transferKind.newRequestBody("body"), + ) val response = getResponse(request) assertContent("abc", response) assertThat(server.takeRequest().body.readUtf8()).isEqualTo("body") @@ -294,9 +310,10 @@ class URLConnectionTest { // http://code.google.com/p/android/issues/detail?id=2939 @Test fun bug2939() { - val response = MockResponse.Builder() - .chunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8) - .build() + val response = + MockResponse.Builder() + .chunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8) + .build() server.enqueue(response) server.enqueue(response) val request = newRequest("/") @@ -310,9 +327,10 @@ class URLConnectionTest { @Test fun connectionsArePooled() { - val response = MockResponse( - body = "ABCDEFGHIJKLMNOPQR", - ) + val response = + MockResponse( + body = "ABCDEFGHIJKLMNOPQR", + ) server.enqueue(response) server.enqueue(response) server.enqueue(response) @@ -326,9 +344,10 @@ class URLConnectionTest { @Test fun chunkedConnectionsArePooled() { - val response = MockResponse.Builder() - .chunkedBody("ABCDEFGHIJKLMNOPQR", 5) - .build() + val response = + MockResponse.Builder() + .chunkedBody("ABCDEFGHIJKLMNOPQR", 5) + .build() server.enqueue(response) server.enqueue(response) server.enqueue(response) @@ -358,14 +377,15 @@ class URLConnectionTest { @Test fun invalidHost() { // Note that 1234.1.1.1 is an invalid host in a URI, but URL isn't as strict. - client = client.newBuilder() - .dns(FakeDns()) - .build() + client = + client.newBuilder() + .dns(FakeDns()) + .build() assertFailsWith { getResponse( Request.Builder() .url("http://1234.1.1.1/index.html".toHttpUrl()) - .build() + .build(), ) } } @@ -375,7 +395,7 @@ class URLConnectionTest { MockResponse( body = "This connection won't pool properly", socketPolicy = socketPolicy, - ) + ), ) val responseAfter = MockResponse(body = "This comes after a busted connection") server.enqueue(responseAfter) @@ -399,15 +419,15 @@ class URLConnectionTest { // of recording is non-deterministic. val requestAfter = server.takeRequest() assertThat( - requestAfter.sequenceNumber == 0 - || server.requestCount == 3 && server.takeRequest().sequenceNumber == 0 + requestAfter.sequenceNumber == 0 || + server.requestCount == 3 && server.takeRequest().sequenceNumber == 0, ).isTrue() } internal enum class WriteKind { BYTE_BY_BYTE, SMALL_BUFFERS, - LARGE_BUFFERS + LARGE_BUFFERS, } @Test @@ -440,41 +460,46 @@ class URLConnectionTest { doUpload(TransferKind.FIXED_LENGTH, WriteKind.LARGE_BUFFERS) } - private fun doUpload(uploadKind: TransferKind, writeKind: WriteKind) { + private fun doUpload( + uploadKind: TransferKind, + writeKind: WriteKind, + ) { val n = 512 * 1024 server.bodyLimit = 0 server.enqueue(MockResponse()) - val requestBody: RequestBody = object : RequestBody() { - override fun contentType(): MediaType? { - return null - } + val requestBody: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType? { + return null + } - override fun contentLength(): Long { - return if (uploadKind === TransferKind.CHUNKED) -1L else n.toLong() - } + override fun contentLength(): Long { + return if (uploadKind === TransferKind.CHUNKED) -1L else n.toLong() + } - override fun writeTo(sink: BufferedSink) { - if (writeKind == WriteKind.BYTE_BY_BYTE) { - for (i in 0 until n) { - sink.writeByte('x'.code) - } - } else { - val buf = ByteArray(if (writeKind == WriteKind.SMALL_BUFFERS) 256 else 64 * 1024) - Arrays.fill(buf, 'x'.code.toByte()) - var i = 0 - while (i < n) { - sink.write(buf, 0, Math.min(buf.size, n - i)) - i += buf.size + override fun writeTo(sink: BufferedSink) { + if (writeKind == WriteKind.BYTE_BY_BYTE) { + for (i in 0 until n) { + sink.writeByte('x'.code) + } + } else { + val buf = ByteArray(if (writeKind == WriteKind.SMALL_BUFFERS) 256 else 64 * 1024) + Arrays.fill(buf, 'x'.code.toByte()) + var i = 0 + while (i < n) { + sink.write(buf, 0, Math.min(buf.size, n - i)) + i += buf.size + } } } } - } - val response = getResponse( - Request( - url = server.url("/"), - body = requestBody, + val response = + getResponse( + Request( + url = server.url("/"), + body = requestBody, + ), ) - ) assertThat(response.code).isEqualTo(200) val request = server.takeRequest() assertThat(request.bodySize).isEqualTo(n.toLong()) @@ -489,12 +514,13 @@ class URLConnectionTest { fun connectViaHttps() { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(body = "this response comes via HTTPS")) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val response = getResponse(newRequest("/foo")) assertContent("this response comes via HTTPS", response) val request = server.takeRequest() @@ -521,23 +547,25 @@ class URLConnectionTest { val hostnameVerifier = RecordingHostnameVerifier() val cookieJar: CookieJar = JavaNetCookieJar(CookieManager()) val connectionPool = ConnectionPool() - client = OkHttpClient.Builder() - .cache(cache) - .connectionPool(connectionPool) - .cookieJar(cookieJar) - .sslSocketFactory(clientSocketFactory, handshakeCertificates.trustManager) - .hostnameVerifier(hostnameVerifier) - .build() - val response1 = getResponse(newRequest("/")) - assertContent("this response comes via HTTPS", response1) - if (rebuildClient) { - client = OkHttpClient.Builder() + client = + OkHttpClient.Builder() .cache(cache) .connectionPool(connectionPool) .cookieJar(cookieJar) .sslSocketFactory(clientSocketFactory, handshakeCertificates.trustManager) .hostnameVerifier(hostnameVerifier) .build() + val response1 = getResponse(newRequest("/")) + assertContent("this response comes via HTTPS", response1) + if (rebuildClient) { + client = + OkHttpClient.Builder() + .cache(cache) + .connectionPool(connectionPool) + .cookieJar(cookieJar) + .sslSocketFactory(clientSocketFactory, handshakeCertificates.trustManager) + .hostnameVerifier(hostnameVerifier) + .build() } val response2 = getResponse(newRequest("/")) assertContent("another response via HTTPS", response2) @@ -552,26 +580,29 @@ class URLConnectionTest { server.enqueue(MockResponse(body = "another response via HTTPS")) // install a custom SSL socket factory so the server can be authorized - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val response1 = getResponse(newRequest("/")) assertContent("this response comes via HTTPS", response1) val sslContext2 = get().newSSLContext() sslContext2.init(null, null, null) val sslSocketFactory2 = sslContext2.socketFactory - val trustManagerFactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm() - ) + val trustManagerFactory = + TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm(), + ) trustManagerFactory.init(null as KeyStore?) val trustManager = trustManagerFactory.trustManagers[0] as X509TrustManager - client = client.newBuilder() - .sslSocketFactory(sslSocketFactory2, trustManager) - .build() + client = + client.newBuilder() + .sslSocketFactory(sslSocketFactory2, trustManager) + .build() assertFailsWith { getResponse(newRequest("/")) }.also { expected -> @@ -590,15 +621,16 @@ class URLConnectionTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(socketPolicy = FailHandshake)) server.enqueue(MockResponse(body = "this response comes via SSL")) - client = client.newBuilder() - .hostnameVerifier( - RecordingHostnameVerifier() - ) // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. - .connectionSpecs(Arrays.asList(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS)) - .sslSocketFactory( - suppressTlsFallbackClientSocketFactory(), handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .hostnameVerifier( + RecordingHostnameVerifier(), + ) // Attempt RESTRICTED_TLS then fall back to MODERN_TLS. + .connectionSpecs(Arrays.asList(ConnectionSpec.RESTRICTED_TLS, ConnectionSpec.MODERN_TLS)) + .sslSocketFactory( + suppressTlsFallbackClientSocketFactory(), handshakeCertificates.trustManager, + ) + .build() val response = getResponse(newRequest("/foo")) assertContent("this response comes via SSL", response) val failHandshakeRequest = server.takeRequest() @@ -615,13 +647,14 @@ class URLConnectionTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(socketPolicy = FailHandshake)) server.enqueue(MockResponse(socketPolicy = FailHandshake)) - client = client.newBuilder() - .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS)) - .hostnameVerifier(RecordingHostnameVerifier()) - .sslSocketFactory( - suppressTlsFallbackClientSocketFactory(), handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS)) + .hostnameVerifier(RecordingHostnameVerifier()) + .sslSocketFactory( + suppressTlsFallbackClientSocketFactory(), handshakeCertificates.trustManager, + ) + .build() assertFailsWith { getResponse(newRequest("/foo")) }.also { expected -> @@ -644,24 +677,27 @@ class URLConnectionTest { MockResponse( body = "abc", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue(MockResponse(body = "def")) - client = client.newBuilder() - .hostnameVerifier(RecordingHostnameVerifier()) - .sslSocketFactory( - suppressTlsFallbackClientSocketFactory(), handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .hostnameVerifier(RecordingHostnameVerifier()) + .sslSocketFactory( + suppressTlsFallbackClientSocketFactory(), handshakeCertificates.trustManager, + ) + .build() assertContent("abc", getResponse(newRequest("/"))) // Give the server time to disconnect. Thread.sleep(500) assertContent("def", getResponse(newRequest("/"))) - val tlsVersions: Set = EnumSet.of( - TlsVersion.TLS_1_0, TlsVersion.TLS_1_2, - TlsVersion.TLS_1_3 - ) // v1.2 on OpenJDK 8. + val tlsVersions: Set = + EnumSet.of( + TlsVersion.TLS_1_0, + TlsVersion.TLS_1_2, + TlsVersion.TLS_1_3, + ) // v1.2 on OpenJDK 8. val request1 = server.takeRequest() assertThat(tlsVersions).contains(request1.handshake?.tlsVersion) val request2 = server.takeRequest() @@ -713,14 +749,14 @@ class URLConnectionTest { private fun testConnectViaProxy(proxyConfig: ProxyConfig) { server.enqueue( - MockResponse(body = "this response comes via a proxy") + MockResponse(body = "this response comes via a proxy"), ) val url = "http://android.com/foo".toHttpUrl() val response = proxyConfig.connect(server, client, url).execute() assertContent("this response comes via a proxy", response) val request = server.takeRequest() assertThat(request.requestLine).isEqualTo( - "GET http://android.com/foo HTTP/1.1" + "GET http://android.com/foo HTTP/1.1", ) assertThat(request.headers["Host"]).isEqualTo("android.com") } @@ -732,7 +768,7 @@ class URLConnectionTest { .body("abc\r\nYOU SHOULD NOT SEE THIS") .clearHeaders() .addHeader("Content-Length: 3") - .build() + .build(), ) assertContent("abc", getResponse(newRequest("/"))) } @@ -744,7 +780,8 @@ class URLConnectionTest { .body("abc") .setHeader("Content-Length", "5") .socketPolicy(DisconnectAtEnd) - .build()) + .build(), + ) assertFailsWith { val response = getResponse(newRequest("/")) response.body.source().readUtf8(5) @@ -752,48 +789,58 @@ class URLConnectionTest { } private fun testConnectViaSocketFactory(useHttps: Boolean) { - val uselessSocketFactory: SocketFactory = object : SocketFactory() { - override fun createSocket(): Socket { - throw IllegalArgumentException("useless") - } - - override fun createSocket(host: InetAddress, port: Int): Socket? = null - - override fun createSocket( - address: InetAddress, - port: Int, - localAddress: InetAddress, - localPort: Int - ): Socket? = null - - override fun createSocket(host: String, port: Int): Socket? = null + val uselessSocketFactory: SocketFactory = + object : SocketFactory() { + override fun createSocket(): Socket { + throw IllegalArgumentException("useless") + } - override fun createSocket( - host: String, - port: Int, - localHost: InetAddress, - localPort: Int - ): Socket? = null - } + override fun createSocket( + host: InetAddress, + port: Int, + ): Socket? = null + + override fun createSocket( + address: InetAddress, + port: Int, + localAddress: InetAddress, + localPort: Int, + ): Socket? = null + + override fun createSocket( + host: String, + port: Int, + ): Socket? = null + + override fun createSocket( + host: String, + port: Int, + localHost: InetAddress, + localPort: Int, + ): Socket? = null + } if (useHttps) { server.useHttps(handshakeCertificates.sslSocketFactory()) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() } server.enqueue(MockResponse()) - client = client.newBuilder() - .socketFactory(uselessSocketFactory) - .build() + client = + client.newBuilder() + .socketFactory(uselessSocketFactory) + .build() assertFailsWith { getResponse(newRequest("/")) } - client = client.newBuilder() - .socketFactory(SocketFactory.getDefault()) - .build() + client = + client.newBuilder() + .socketFactory(SocketFactory.getDefault()) + .build() val response = getResponse(newRequest("/")) assertThat(response.code).isEqualTo(200) } @@ -810,8 +857,9 @@ class URLConnectionTest { @Test fun contentDisagreesWithChunkedHeaderBodyTooLong() { - val builder = MockResponse.Builder() - .chunkedBody("abc", 3) + val builder = + MockResponse.Builder() + .chunkedBody("abc", 3) val buffer = Buffer() builder.body!!.writeTo(buffer) buffer.writeUtf8("\r\nYOU SHOULD NOT SEE THIS") @@ -824,8 +872,9 @@ class URLConnectionTest { @Test fun contentDisagreesWithChunkedHeaderBodyTooShort() { - val builder = MockResponse.Builder() - .chunkedBody("abcdefg", 5) + val builder = + MockResponse.Builder() + .chunkedBody("abcdefg", 5) val fullBody = Buffer() builder.body!!.writeTo(fullBody) val truncatedBody = Buffer() @@ -855,15 +904,16 @@ class URLConnectionTest { private fun testConnectViaDirectProxyToHttps(proxyConfig: ProxyConfig) { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue( - MockResponse(body = "this response comes via HTTPS") + MockResponse(body = "this response comes via HTTPS"), ) val url = server.url("/foo") - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val call = proxyConfig.connect(server, client, url) assertContent("this response comes via HTTPS", call.execute()) val request = server.takeRequest() @@ -899,12 +949,13 @@ class URLConnectionTest { server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "this response comes via a secure proxy")) val url = "https://android.com/foo".toHttpUrl() - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(hostnameVerifier) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(hostnameVerifier) + .build() val call = proxyConfig.connect(server, client, url) assertContent("this response comes via a secure proxy", call.execute()) val connect = server.takeRequest() @@ -915,7 +966,7 @@ class URLConnectionTest { assertThat(get.requestLine).isEqualTo("GET /foo HTTP/1.1") assertThat(get.headers["Host"]).isEqualTo("android.com") assertThat(hostnameVerifier.calls).isEqualTo( - Arrays.asList("verify android.com") + Arrays.asList("verify android.com"), ) } @@ -929,38 +980,41 @@ class URLConnectionTest { MockResponse( body = "bogus proxy connect response content", inTunnel = true, - ) + ), ) server.enqueue(MockResponse(body = "response")) // Configure a single IP address for the host and a single configuration, so we only need one // failure to fail permanently. - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS)) - .hostnameVerifier(RecordingHostnameVerifier()) - .proxy(server.toProxyAddress()) - .build() - val response = getResponse( - Request.Builder() - .url("https://android.com/foo".toHttpUrl()) + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .connectionSpecs(listOf(ConnectionSpec.MODERN_TLS)) + .hostnameVerifier(RecordingHostnameVerifier()) + .proxy(server.toProxyAddress()) .build() - ) + val response = + getResponse( + Request.Builder() + .url("https://android.com/foo".toHttpUrl()) + .build(), + ) assertContent("response", response) val connect = server.takeRequest() assertThat(connect.requestLine).isEqualTo( - "CONNECT android.com:443 HTTP/1.1" + "CONNECT android.com:443 HTTP/1.1", ) assertThat(connect.headers["Host"]).isEqualTo("android.com:443") } private fun initResponseCache() { cache = Cache(tempDir, Int.MAX_VALUE.toLong()) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() } /** Test which headers are sent unencrypted to the HTTP proxy. */ @@ -970,21 +1024,23 @@ class URLConnectionTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "encrypted response from the origin server")) - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(hostnameVerifier) - .build() - val response = getResponse( - Request.Builder() - .url("https://android.com/foo".toHttpUrl()) - .header("Private", "Secret") - .header("Proxy-Authorization", "bar") - .header("User-Agent", "baz") + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(hostnameVerifier) .build() - ) + val response = + getResponse( + Request.Builder() + .url("https://android.com/foo".toHttpUrl()) + .header("Private", "Secret") + .header("Proxy-Authorization", "bar") + .header("User-Agent", "baz") + .build(), + ) assertContent("encrypted response from the origin server", response) val connect = server.takeRequest() assertThat(connect.headers["Private"]).isNull() @@ -1006,23 +1062,25 @@ class URLConnectionTest { code = 407, headers = headersOf("Proxy-Authenticate", "Basic realm=\"localhost\""), inTunnel = true, - ) + ), ) server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "A")) - client = client.newBuilder() - .proxyAuthenticator(Authenticator.JAVA_NET_AUTHENTICATOR) - .proxy(server.toProxyAddress()) - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() - val response = getResponse( - Request.Builder() - .url("https://android.com/foo".toHttpUrlOrNull()!!) + client = + client.newBuilder() + .proxyAuthenticator(Authenticator.JAVA_NET_AUTHENTICATOR) + .proxy(server.toProxyAddress()) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) .build() - ) + val response = + getResponse( + Request.Builder() + .url("https://android.com/foo".toHttpUrlOrNull()!!) + .build(), + ) assertContent("A", response) val connect1 = server.takeRequest() assertThat(connect1.requestLine).isEqualTo("CONNECT android.com:443 HTTP/1.1") @@ -1043,19 +1101,21 @@ class URLConnectionTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "this response comes via a proxy")) - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() - val response = getResponse( - Request.Builder() - .url("https://android.com/foo") - .header("Connection", "close") + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) .build() - ) + val response = + getResponse( + Request.Builder() + .url("https://android.com/foo") + .header("Connection", "close") + .build(), + ) assertContent("this response comes via a proxy", response) } @@ -1067,11 +1127,12 @@ class URLConnectionTest { server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "response 1")) server.enqueue(MockResponse(body = "response 2")) - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .sslSocketFactory(socketFactory, handshakeCertificates.trustManager) - .hostnameVerifier(hostnameVerifier) - .build() + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .sslSocketFactory(socketFactory, handshakeCertificates.trustManager) + .hostnameVerifier(hostnameVerifier) + .build() assertContent("response 1", getResponse(Request("https://android.com/foo".toHttpUrl()))) assertContent("response 2", getResponse(Request("https://android.com/foo".toHttpUrl()))) } @@ -1079,17 +1140,25 @@ class URLConnectionTest { @Test fun proxySelectorHttpWithConnectionReuse() { server.enqueue( - MockResponse(body = "response 1") + MockResponse(body = "response 1"), ) server.enqueue( - MockResponse(code = 407) + MockResponse(code = 407), ) - client = client.newBuilder() - .proxySelector(object : ProxySelector() { - override fun select(uri: URI): List = listOf(server.toProxyAddress()) - override fun connectFailed(uri: URI, socketAddress: SocketAddress, e: IOException) { - } - }).build() + client = + client.newBuilder() + .proxySelector( + object : ProxySelector() { + override fun select(uri: URI): List = listOf(server.toProxyAddress()) + + override fun connectFailed( + uri: URI, + socketAddress: SocketAddress, + e: IOException, + ) { + } + }, + ).build() val url = "http://android.com/foo".toHttpUrl() assertContent("response 1", getResponse(Request(url))) assertThat(getResponse(Request(url)).code).isEqualTo(407) @@ -1101,7 +1170,7 @@ class URLConnectionTest { MockResponse.Builder() .throttleBody(2, 100, TimeUnit.MILLISECONDS) .body("ABCD") - .build() + .build(), ) val call = client.newCall(newRequest("/")) val response = call.execute() @@ -1123,15 +1192,20 @@ class URLConnectionTest { val callReference = AtomicReference() class DisconnectingCookieJar : CookieJar { - override fun saveFromResponse(url: HttpUrl, cookies: List) {} + override fun saveFromResponse( + url: HttpUrl, + cookies: List, + ) {} + override fun loadForRequest(url: HttpUrl): List { callReference.get().cancel() return emptyList() } } - client = client.newBuilder() - .cookieJar(DisconnectingCookieJar()) - .build() + client = + client.newBuilder() + .cookieJar(DisconnectingCookieJar()) + .build() val call = client.newCall(newRequest("/")) callReference.set(call) assertFailsWith { @@ -1144,7 +1218,7 @@ class URLConnectionTest { @Test fun disconnectBeforeConnect() { server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) val call = client.newCall(newRequest("/")) call.cancel() @@ -1163,7 +1237,10 @@ class URLConnectionTest { * Reads `count` characters from the stream. If the stream is exhausted before `count` * characters can be read, the remaining characters are returned and the stream is closed. */ - private fun readAscii(inputStream: InputStream, count: Int): String { + private fun readAscii( + inputStream: InputStream, + count: Int, + ): String { val result = StringBuilder() for (i in 0 until count) { val value = inputStream.read() @@ -1205,7 +1282,7 @@ class URLConnectionTest { inputStream.reset() } assertThat(readAscii(inputStream, Int.MAX_VALUE)).isEqualTo( - "FGHIJKLMNOPQRSTUVWXYZ" + "FGHIJKLMNOPQRSTUVWXYZ", ) inputStream.close() assertContent("ABCDEFGHIJKLMNOPQRSTUVWXYZ", getResponse(newRequest("/"))) @@ -1217,11 +1294,12 @@ class URLConnectionTest { */ @Test fun unauthorizedResponseHandling() { - val mockResponse = MockResponse( - code = HttpURLConnection.HTTP_UNAUTHORIZED, - headers = headersOf("WWW-Authenticate", "challenge"), - body = "Unauthorized", - ) + val mockResponse = + MockResponse( + code = HttpURLConnection.HTTP_UNAUTHORIZED, + headers = headersOf("WWW-Authenticate", "challenge"), + body = "Unauthorized", + ) server.enqueue(mockResponse) server.enqueue(mockResponse) server.enqueue(mockResponse) @@ -1240,7 +1318,7 @@ class URLConnectionTest { .body("5\r\nABCDE\r\nG\r\nFGHIJKLMNOPQRSTU\r\n0\r\n\r\n") .clearHeaders() .addHeader("Transfer-encoding: chunked") - .build() + .build(), ) assertFailsWith { getResponse(newRequest("/")).use { response -> @@ -1256,7 +1334,7 @@ class URLConnectionTest { .body("5:x\r\nABCDE\r\n0\r\n\r\n") .clearHeaders() .addHeader("Transfer-encoding: chunked") - .build() + .build(), ) assertFailsWith { getResponse(newRequest("/")).use { response -> @@ -1272,7 +1350,7 @@ class URLConnectionTest { .body("5;x\r\nABCDE\r\n0\r\n\r\n") .clearHeaders() .addHeader("Transfer-encoding: chunked") - .build() + .build(), ) getResponse(newRequest("/")).use { response -> assertContent("ABCDE", response) } } @@ -1285,7 +1363,7 @@ class URLConnectionTest { .clearHeaders() .addHeader("Transfer-encoding: chunked") .socketPolicy(DisconnectAtEnd) - .build() + .build(), ) assertFailsWith { getResponse(newRequest("/")).use { response -> @@ -1304,11 +1382,11 @@ class URLConnectionTest { MockResponse.Builder() .body(gzip("ABCABCABC")) .addHeader("Content-Encoding: gzip") - .build() + .build(), ) val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)).isEqualTo( - "ABCABCABC" + "ABCABCABC", ) assertThat(response.header("Content-Encoding")).isNull() assertThat(response.body.contentLength()).isEqualTo(-1L) @@ -1323,14 +1401,15 @@ class URLConnectionTest { MockResponse.Builder() .body(bodyBytes) .addHeader("Content-Encoding: gzip") - .build() - ) - val response = getResponse( - Request.Builder() - .url(server.url("/")) - .header("Accept-Encoding", "gzip") - .build() + .build(), ) + val response = + getResponse( + Request.Builder() + .url(server.url("/")) + .header("Accept-Encoding", "gzip") + .build(), + ) val gunzippedIn: InputStream = GZIPInputStream(response.body.byteStream()) assertThat(readAscii(gunzippedIn, Int.MAX_VALUE)).isEqualTo("ABCDEFGHIJKLMNOPQRSTUVWXYZ") assertThat(response.body.contentLength()).isEqualTo(bodyBytes.size) @@ -1364,14 +1443,15 @@ class URLConnectionTest { MockResponse( headers = headersOf("Content-Encoding", "custom"), body = "ABCDE", - ) - ) - val response = getResponse( - Request.Builder() - .url(server.url("/")) - .header("Accept-Encoding", "custom") - .build() + ), ) + val response = + getResponse( + Request.Builder() + .url(server.url("/")) + .header("Accept-Encoding", "custom") + .build(), + ) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)).isEqualTo("ABCDE") val request = server.takeRequest() assertThat(request.headers["Accept-Encoding"]).isEqualTo("custom") @@ -1384,38 +1464,42 @@ class URLConnectionTest { */ private fun testClientConfiguredGzipContentEncodingAndConnectionReuse( transferKind: TransferKind, - tls: Boolean + tls: Boolean, ) { if (tls) { val socketFactory = handshakeCertificates.sslSocketFactory() val hostnameVerifier = RecordingHostnameVerifier() server.useHttps(socketFactory) - client = client.newBuilder() - .sslSocketFactory(socketFactory, handshakeCertificates.trustManager) - .hostnameVerifier(hostnameVerifier) - .build() + client = + client.newBuilder() + .sslSocketFactory(socketFactory, handshakeCertificates.trustManager) + .hostnameVerifier(hostnameVerifier) + .build() } - val responseOne = MockResponse.Builder() - .addHeader("Content-Encoding: gzip") + val responseOne = + MockResponse.Builder() + .addHeader("Content-Encoding: gzip") transferKind.setBody(responseOne, gzip("one (gzipped)"), 5) server.enqueue(responseOne.build()) val responseTwo = MockResponse.Builder() transferKind.setBody(responseTwo, "two (identity)", 5) server.enqueue(responseTwo.build()) - val response1 = getResponse( - Request.Builder() - .header("Accept-Encoding", "gzip") - .url(server.url("/")) - .build() - ) + val response1 = + getResponse( + Request.Builder() + .header("Accept-Encoding", "gzip") + .url(server.url("/")) + .build(), + ) val gunzippedIn: InputStream = GZIPInputStream(response1.body.byteStream()) assertThat(readAscii(gunzippedIn, Int.MAX_VALUE)).isEqualTo("one (gzipped)") assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) - val response2 = getResponse( - Request.Builder() - .url(server.url("/")) - .build() - ) + val response2 = + getResponse( + Request.Builder() + .url(server.url("/")) + .build(), + ) assertThat(readAscii(response2.body.byteStream(), Int.MAX_VALUE)).isEqualTo("two (identity)") assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) } @@ -1426,13 +1510,13 @@ class URLConnectionTest { MockResponse( body = "a", socketPolicy = ShutdownInputAtEnd, - ) + ), ) server.enqueue( MockResponse.Builder() .addHeader("Content-Encoding: gzip") .body(gzip("b")) - .build() + .build(), ) // Seed the pool with a bad connection. @@ -1456,7 +1540,7 @@ class URLConnectionTest { .body("{}") .clearHeaders() .socketPolicy(DisconnectAtEnd) - .build() + .build(), ) val response = getResponse(newRequest("/")) assertContent("{}", response) @@ -1504,9 +1588,10 @@ class URLConnectionTest { MockResponse.Builder() .body(Buffer().write(ByteArray(10000))) .throttleBody(100, 10, TimeUnit.MILLISECONDS) - .build()) + .build(), + ) server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) val startNanos = System.nanoTime() val connection1 = getResponse(newRequest("/")) @@ -1530,17 +1615,18 @@ class URLConnectionTest { @Test fun setChunkedStreamingMode() { server.enqueue(MockResponse()) - val response = getResponse( - Request( - url = server.url("/"), - body = TransferKind.CHUNKED.newRequestBody("ABCDEFGHIJKLMNOPQ"), + val response = + getResponse( + Request( + url = server.url("/"), + body = TransferKind.CHUNKED.newRequestBody("ABCDEFGHIJKLMNOPQ"), + ), ) - ) assertThat(response.code).isEqualTo(200) val request = server.takeRequest() assertThat(request.body.readUtf8()).isEqualTo("ABCDEFGHIJKLMNOPQ") assertThat(request.chunkSizes).isEqualTo( - Arrays.asList("ABCDEFGHIJKLMNOPQ".length) + Arrays.asList("ABCDEFGHIJKLMNOPQ".length), ) } @@ -1560,19 +1646,21 @@ class URLConnectionTest { code = 401, headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), body = "Please authenticate.", - ) + ), ) server.enqueue( - MockResponse(body = "Authenticated!") + MockResponse(body = "Authenticated!"), ) java.net.Authenticator.setDefault(RecordingAuthenticator()) - client = client.newBuilder() - .authenticator(JavaNetAuthenticator()) - .build() - val request = Request( - url = server.url("/"), - body = streamingMode.newRequestBody("ABCD"), - ) + client = + client.newBuilder() + .authenticator(JavaNetAuthenticator()) + .build() + val request = + Request( + url = server.url("/"), + body = streamingMode.newRequestBody("ABCD"), + ) val response = getResponse(request) assertThat(response.code).isEqualTo(200) assertContent("Authenticated!", response) @@ -1610,19 +1698,21 @@ class URLConnectionTest { private fun postBodyRetransmittedAfterAuthorizationFail(body: String) { server.enqueue( - MockResponse(code = 401) + MockResponse(code = 401), ) server.enqueue(MockResponse()) val credential = basic("jesse", "secret") - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(credential, null)) - .build() - val response = getResponse( - Request( - url = server.url("/"), - body = body.toRequestBody(), + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(credential, null)) + .build() + val response = + getResponse( + Request( + url = server.url("/"), + body = body.toRequestBody(), + ), ) - ) assertThat(response.code).isEqualTo(200) response.body.byteStream().close() val recordedRequest1 = server.takeRequest() @@ -1651,12 +1741,13 @@ class URLConnectionTest { // http://code.google.com/p/android/issues/detail?id=11140 @Test fun digestAuthentication() { - val calls = authCallsForHeader( - "WWW-Authenticate: Digest " - + "realm=\"testrealm@host.com\", qop=\"auth,auth-int\", " - + "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", " - + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"" - ) + val calls = + authCallsForHeader( + "WWW-Authenticate: Digest " + + "realm=\"testrealm@host.com\", qop=\"auth,auth-int\", " + + "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", " + + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"", + ) assertThat(calls.size).isEqualTo(0) } @@ -1703,18 +1794,21 @@ class URLConnectionTest { .code(responseCode) .addHeader(authHeader) .body("Please authenticate.") - .build()) + .build(), + ) val response: Response if (proxy) { - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .proxyAuthenticator(JavaNetAuthenticator()) - .build() + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .proxyAuthenticator(JavaNetAuthenticator()) + .build() response = getResponse(Request("http://android.com/".toHttpUrl())) } else { - client = client.newBuilder() - .authenticator(JavaNetAuthenticator()) - .build() + client = + client.newBuilder() + .authenticator(JavaNetAuthenticator()) + .build() response = getResponse(newRequest("/")) } assertThat(response.code).isEqualTo(responseCode) @@ -1743,10 +1837,11 @@ class URLConnectionTest { } private fun assertMethodPermitsRequestBody(requestMethod: String) { - val request = Request.Builder() - .url(server.url("/")) - .method(requestMethod, "abc".toRequestBody(null)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .method(requestMethod, "abc".toRequestBody(null)) + .build() assertThat(request.method).isEqualTo(requestMethod) } @@ -1760,10 +1855,11 @@ class URLConnectionTest { } private fun assertMethodPermitsNoRequestBody(requestMethod: String) { - val request = Request.Builder() - .url(server.url("/")) - .method(requestMethod, null) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .method(requestMethod, null) + .build() assertThat(request.method).isEqualTo(requestMethod) } @@ -1788,12 +1884,13 @@ class URLConnectionTest { private fun assertValidRequestMethod(requestMethod: String) { server.enqueue(MockResponse()) - val response = getResponse( - Request.Builder() - .url(server.url("/")) - .method(requestMethod, null) - .build() - ) + val response = + getResponse( + Request.Builder() + .url(server.url("/")) + .method(requestMethod, null) + .build(), + ) assertThat(response.code).isEqualTo(200) val recordedRequest = server.takeRequest() assertThat(recordedRequest.method).isEqualTo(requestMethod) @@ -1820,7 +1917,8 @@ class URLConnectionTest { .addHeader("Expires: Mon, 26 Jul 1997 05:00:00 GMT") .addHeader("icy-metaint:16000") .body("mp3 data") - .build()) + .build(), + ) val response = getResponse(newRequest("/")) assertThat(response.code).isEqualTo(200) assertThat(response.message).isEqualTo("OK") @@ -1836,11 +1934,15 @@ class URLConnectionTest { .addHeader("Date: 23/Jan/2004:08:54:59 UTC") .addHeader("Content-Type: text/plain") .body("STR;FFMJ2;Frankfurt;RTCM 2.1;1(1),3(19),16(59);0;GPS;GREF;DEU;50.12;8.68;0;1;GPSNet V2.10;none;N;N;560;Demo\nENDSOURCETABLE") - .build()) + .build(), + ) val response = getResponse(newRequest("/")) assertThat(response.code).isEqualTo(200) assertThat(response.message).isEqualTo("OK") - assertContent("STR;FFMJ2;Frankfurt;RTCM 2.1;1(1),3(19),16(59);0;GPS;GREF;DEU;50.12;8.68;0;1;GPSNet V2.10;none;N;N;560;Demo\nENDSOURCETABLE", response) + assertContent( + "STR;FFMJ2;Frankfurt;RTCM 2.1;1(1),3(19),16(59);0;GPS;GREF;DEU;50.12;8.68;0;1;GPSNet V2.10;none;N;N;560;Demo\nENDSOURCETABLE", + response, + ) } @Test @@ -1860,22 +1962,24 @@ class URLConnectionTest { private fun testSecureStreamingPost(streamingMode: TransferKind) { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue( - MockResponse(body = "Success!") + MockResponse(body = "Success!"), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() - val response = getResponse( - Request( - url = server.url("/"), - body = streamingMode.newRequestBody("ABCD"), + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() + val response = + getResponse( + Request( + url = server.url("/"), + body = streamingMode.newRequestBody("ABCD"), + ), ) - ) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)).isEqualTo( - "Success!" + "Success!", ) val request = server.takeRequest() assertThat(request.requestLine).isEqualTo("POST / HTTP/1.1") @@ -1889,31 +1993,34 @@ class URLConnectionTest { @Test fun authenticateWithPost() { - val pleaseAuthenticate = MockResponse( - code = 401, - headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), - body = "Please authenticate.", - ) + val pleaseAuthenticate = + MockResponse( + code = 401, + headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), + body = "Please authenticate.", + ) // Fail auth three times... server.enqueue(pleaseAuthenticate) server.enqueue(pleaseAuthenticate) server.enqueue(pleaseAuthenticate) // ...then succeed the fourth time. server.enqueue( - MockResponse(body = "Successful auth!") + MockResponse(body = "Successful auth!"), ) java.net.Authenticator.setDefault(RecordingAuthenticator()) - client = client.newBuilder() - .authenticator(JavaNetAuthenticator()) - .build() - val response = getResponse( - Request( - url = server.url("/"), - body = "ABCD".toRequestBody(null), + client = + client.newBuilder() + .authenticator(JavaNetAuthenticator()) + .build() + val response = + getResponse( + Request( + url = server.url("/"), + body = "ABCD".toRequestBody(null), + ), ) - ) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)).isEqualTo( - "Successful auth!" + "Successful auth!", ) // No authorization header for the first request... @@ -1925,7 +2032,7 @@ class URLConnectionTest { request = server.takeRequest() assertThat(request.requestLine).isEqualTo("POST / HTTP/1.1") assertThat(request.headers["Authorization"]).isEqualTo( - "Basic " + RecordingAuthenticator.BASE_64_CREDENTIALS + "Basic " + RecordingAuthenticator.BASE_64_CREDENTIALS, ) assertThat(request.body.readUtf8()).isEqualTo("ABCD") } @@ -1933,23 +2040,25 @@ class URLConnectionTest { @Test fun authenticateWithGet() { - val pleaseAuthenticate = MockResponse( - code = 401, - headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), - body = "Please authenticate.", - ) + val pleaseAuthenticate = + MockResponse( + code = 401, + headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), + body = "Please authenticate.", + ) // Fail auth three times... server.enqueue(pleaseAuthenticate) server.enqueue(pleaseAuthenticate) server.enqueue(pleaseAuthenticate) // ...then succeed the fourth time. server.enqueue( - MockResponse(body = "Successful auth!") + MockResponse(body = "Successful auth!"), ) java.net.Authenticator.setDefault(RecordingAuthenticator()) - client = client.newBuilder() - .authenticator(JavaNetAuthenticator()) - .build() + client = + client.newBuilder() + .authenticator(JavaNetAuthenticator()) + .build() val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("Successful auth!") @@ -1972,32 +2081,37 @@ class URLConnectionTest { server.enqueue( MockResponse( code = 401, - headers = headersOf( - "WWW-Authenticate", "Basic realm=\"protected area\", charset=\"UTF-8\"" - ), + headers = + headersOf( + "WWW-Authenticate", + "Basic realm=\"protected area\", charset=\"UTF-8\"", + ), body = "Please authenticate with UTF-8.", - ) + ), ) server.enqueue( MockResponse( code = 401, - headers = headersOf( - "WWW-Authenticate", "Basic realm=\"protected area\"" - ), + headers = + headersOf( + "WWW-Authenticate", + "Basic realm=\"protected area\"", + ), body = "Please authenticate with ISO-8859-1.", - ) + ), ) server.enqueue( - MockResponse(body = "Successful auth!") + MockResponse(body = "Successful auth!"), ) java.net.Authenticator.setDefault( RecordingAuthenticator( - PasswordAuthentication("username", "mötorhead".toCharArray()) - ) + PasswordAuthentication("username", "mötorhead".toCharArray()), + ), ) - client = client.newBuilder() - .authenticator(JavaNetAuthenticator()) - .build() + client = + client.newBuilder() + .authenticator(JavaNetAuthenticator()) + .build() val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("Successful auth!") @@ -2009,7 +2123,7 @@ class URLConnectionTest { // UTF-8 encoding for the first credential. val request2 = server.takeRequest() assertThat(request2.headers["Authorization"]).isEqualTo( - "Basic dXNlcm5hbWU6bcO2dG9yaGVhZA==" + "Basic dXNlcm5hbWU6bcO2dG9yaGVhZA==", ) // ISO-8859-1 encoding for the second credential. @@ -2021,25 +2135,28 @@ class URLConnectionTest { /** https://code.google.com/p/android/issues/detail?id=74026 */ @Test fun authenticateWithGetAndTransparentGzip() { - val pleaseAuthenticate = MockResponse( - code = 401, - headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), - body = "Please authenticate.", - ) + val pleaseAuthenticate = + MockResponse( + code = 401, + headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), + body = "Please authenticate.", + ) // Fail auth three times... server.enqueue(pleaseAuthenticate) server.enqueue(pleaseAuthenticate) server.enqueue(pleaseAuthenticate) // ...then succeed the fourth time. - val successfulResponse = MockResponse.Builder() - .addHeader("Content-Encoding", "gzip") - .body(gzip("Successful auth!")) - .build() + val successfulResponse = + MockResponse.Builder() + .addHeader("Content-Encoding", "gzip") + .body(gzip("Successful auth!")) + .build() server.enqueue(successfulResponse) java.net.Authenticator.setDefault(RecordingAuthenticator()) - client = client.newBuilder() - .authenticator(JavaNetAuthenticator()) - .build() + client = + client.newBuilder() + .authenticator(JavaNetAuthenticator()) + .build() val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("Successful auth!") @@ -2053,7 +2170,7 @@ class URLConnectionTest { request = server.takeRequest() assertThat(request.requestLine).isEqualTo("GET / HTTP/1.1") assertThat(request.headers["Authorization"]).isEqualTo( - "Basic ${RecordingAuthenticator.BASE_64_CREDENTIALS}" + "Basic ${RecordingAuthenticator.BASE_64_CREDENTIALS}", ) } } @@ -2065,16 +2182,17 @@ class URLConnectionTest { MockResponse( code = 401, headers = headersOf("wWw-aUtHeNtIcAtE", "bAsIc rEaLm=\"pRoTeCtEd aReA\""), - body = "Please authenticate." - ) + body = "Please authenticate.", + ), ) server.enqueue( - MockResponse(body = "Successful auth!") + MockResponse(body = "Successful auth!"), ) java.net.Authenticator.setDefault(RecordingAuthenticator()) - client = client.newBuilder() - .authenticator(JavaNetAuthenticator()) - .build() + client = + client.newBuilder() + .authenticator(JavaNetAuthenticator()) + .build() val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("Successful auth!") @@ -2095,16 +2213,20 @@ class URLConnectionTest { testRedirected(TransferKind.END_OF_STREAM, false) } - private fun testRedirected(transferKind: TransferKind, reuse: Boolean) { - val mockResponse = MockResponse.Builder() - .code(HttpURLConnection.HTTP_MOVED_TEMP) - .addHeader("Location: /foo") + private fun testRedirected( + transferKind: TransferKind, + reuse: Boolean, + ) { + val mockResponse = + MockResponse.Builder() + .code(HttpURLConnection.HTTP_MOVED_TEMP) + .addHeader("Location: /foo") transferKind.setBody(mockResponse, "This page has moved!", 10) server.enqueue(mockResponse.build()) server.enqueue(MockResponse(body = "This is the new location!")) val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)).isEqualTo( - "This is the new location!" + "This is the new location!", ) val first = server.takeRequest() assertThat(first.requestLine).isEqualTo("GET / HTTP/1.1") @@ -2124,20 +2246,21 @@ class URLConnectionTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "/foo"), body = "This page has moved!", - ) + ), ) server.enqueue( - MockResponse(body = "This is the new location!") + MockResponse(body = "This is the new location!"), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)).isEqualTo( - "This is the new location!" + "This is the new location!", ) val first = server.takeRequest() assertThat(first.requestLine).isEqualTo("GET / HTTP/1.1") @@ -2155,15 +2278,16 @@ class URLConnectionTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "http://anyhost/foo"), body = "This page has moved!", - ) + ), ) - client = client.newBuilder() - .followSslRedirects(false) - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .followSslRedirects(false) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("This page has moved!") @@ -2176,11 +2300,12 @@ class URLConnectionTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "https://anyhost/foo"), body = "This page has moved!", - ) + ), ) - client = client.newBuilder() - .followSslRedirects(false) - .build() + client = + client.newBuilder() + .followSslRedirects(false) + .build() val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("This page has moved!") @@ -2189,7 +2314,7 @@ class URLConnectionTest { @Test fun redirectedFromHttpsToHttpFollowingProtocolRedirects() { server2.enqueue( - MockResponse(body = "This is insecure HTTP!") + MockResponse(body = "This is insecure HTTP!"), ) server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue( @@ -2197,15 +2322,16 @@ class URLConnectionTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", server2.url("/").toString()), body = "This page has moved!", - ) + ), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .followSslRedirects(true) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .followSslRedirects(true) + .build() val response = getResponse(newRequest("/")) assertContent("This is insecure HTTP!", response) assertThat(response.handshake).isNull() @@ -2215,22 +2341,23 @@ class URLConnectionTest { fun redirectedFromHttpToHttpsFollowingProtocolRedirects() { server2.useHttps(handshakeCertificates.sslSocketFactory()) server2.enqueue( - MockResponse(body = "This is secure HTTPS!") + MockResponse(body = "This is secure HTTPS!"), ) server.enqueue( MockResponse( code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", server2.url("/").toString()), body = "This page has moved!", - ) + ), ) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .followSslRedirects(true) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .followSslRedirects(true) + .build() val response = getResponse(newRequest("/")) assertContent("This is secure HTTPS!", response) } @@ -2250,33 +2377,34 @@ class URLConnectionTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server2.useHttps(handshakeCertificates.sslSocketFactory()) server2.protocolNegotiationEnabled = false - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() } server2.enqueue( - MockResponse(body = "This is the 2nd server!") + MockResponse(body = "This is the 2nd server!"), ) server2.enqueue( - MockResponse(body = "This is the 2nd server, again!") + MockResponse(body = "This is the 2nd server, again!"), ) server.enqueue( MockResponse( code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", server2.url("/").toString()), body = "This page has moved!", - ) + ), ) server.enqueue( - MockResponse(body = "This is the first server again!") + MockResponse(body = "This is the first server again!"), ) val response = getResponse(newRequest("/")) assertContent("This is the 2nd server!", response) assertThat(response.request.url).isEqualTo( - server2.url("/") + server2.url("/"), ) // make sure the first server was careful to recycle the connection @@ -2295,55 +2423,63 @@ class URLConnectionTest { @Test fun redirectWithProxySelector() { val proxySelectionRequests: MutableList = ArrayList() - client = client.newBuilder() - .proxySelector(object : ProxySelector() { - override fun select(uri: URI): List { - proxySelectionRequests.add(uri) - val proxyServer = if (uri.port == server.port) server else server2 - return listOf(proxyServer.toProxyAddress()) - } + client = + client.newBuilder() + .proxySelector( + object : ProxySelector() { + override fun select(uri: URI): List { + proxySelectionRequests.add(uri) + val proxyServer = if (uri.port == server.port) server else server2 + return listOf(proxyServer.toProxyAddress()) + } - override fun connectFailed(uri: URI, address: SocketAddress, failure: IOException) { - throw AssertionError() - } - }) - .build() + override fun connectFailed( + uri: URI, + address: SocketAddress, + failure: IOException, + ) { + throw AssertionError() + } + }, + ) + .build() server2.enqueue( - MockResponse(body = "This is the 2nd server!") + MockResponse(body = "This is the 2nd server!"), ) server.enqueue( MockResponse( code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", server2.url("/b").toString()), body = "This page has moved!", - ) + ), ) assertContent("This is the 2nd server!", getResponse(newRequest("/a"))) assertThat(proxySelectionRequests).isEqualTo( listOf( server.url("/").toUrl().toURI(), - server2.url("/").toUrl().toURI() - ) + server2.url("/").toUrl().toURI(), + ), ) } @Test fun redirectWithAuthentication() { server2.enqueue( - MockResponse(body = "Page 2") + MockResponse(body = "Page 2"), ) server.enqueue( - MockResponse(code = 401) + MockResponse(code = 401), ) server.enqueue( MockResponse( code = 302, - headers = headersOf("Location", server2.url("/b").toString()) - ) + headers = headersOf("Location", server2.url("/b").toString()), + ), ) - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(basic("jesse", "secret"), null)) - .build() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(basic("jesse", "secret"), null)) + .build() assertContent("Page 2", getResponse(newRequest("/a"))) val redirectRequest = server2.takeRequest() assertThat(redirectRequest.headers["Authorization"]).isNull() @@ -2381,23 +2517,27 @@ class URLConnectionTest { testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_TEMP, TransferKind.FIXED_LENGTH) } - private fun testResponseRedirectedWithPost(redirectCode: Int, transferKind: TransferKind) { + private fun testResponseRedirectedWithPost( + redirectCode: Int, + transferKind: TransferKind, + ) { server.enqueue( MockResponse( code = redirectCode, headers = headersOf("Location", "/page2"), body = "This page has moved!", - ) + ), ) server.enqueue( - MockResponse(body = "Page 2") + MockResponse(body = "Page 2"), ) - val response = getResponse( - Request( - url = server.url("/page1"), - body = transferKind.newRequestBody("ABCD"), + val response = + getResponse( + Request( + url = server.url("/page1"), + body = transferKind.newRequestBody("ABCD"), + ), ) - ) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("Page 2") val page1 = server.takeRequest() @@ -2413,18 +2553,19 @@ class URLConnectionTest { MockResponse( code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "/page2"), - ) + ), ) server.enqueue( - MockResponse(body = "Page 2") - ) - val response = getResponse( - Request.Builder() - .url(server.url("/page1")) - .post("ABCD".toRequestBody("text/plain; charset=utf-8".toMediaType())) - .header("Transfer-Encoding", "identity") - .build() + MockResponse(body = "Page 2"), ) + val response = + getResponse( + Request.Builder() + .url(server.url("/page1")) + .post("ABCD".toRequestBody("text/plain; charset=utf-8".toMediaType())) + .header("Transfer-Encoding", "identity") + .build(), + ) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("Page 2") assertThat(server.takeRequest().requestLine) @@ -2443,10 +2584,10 @@ class URLConnectionTest { code = HttpURLConnection.HTTP_USE_PROXY, headers = headersOf("Location", server.url("/").toString()), body = "This page has moved!", - ) + ), ) server.enqueue( - MockResponse(body = "Proxy Response") + MockResponse(body = "Proxy Response"), ) val response = getResponse(newRequest("/foo")) // Fails on the RI, which gets "Proxy Response". @@ -2530,19 +2671,22 @@ class URLConnectionTest { @Test fun response307WithPostReverted() { - client = client.newBuilder() - .addNetworkInterceptor(LegacyRedirectInterceptor()) - .build() - val response1 = MockResponse( - code = HTTP_TEMP_REDIRECT, - headers = headersOf("Location", "/page2"), - body = "This page has moved!", - ) + client = + client.newBuilder() + .addNetworkInterceptor(LegacyRedirectInterceptor()) + .build() + val response1 = + MockResponse( + code = HTTP_TEMP_REDIRECT, + headers = headersOf("Location", "/page2"), + body = "This page has moved!", + ) server.enqueue(response1) - val request = Request( - url = server.url("/page1"), - body = "ABCD".toRequestBody(null), - ) + val request = + Request( + url = server.url("/page1"), + body = "ABCD".toRequestBody(null), + ) val response = getResponse(request) val responseString = readAscii(response.body.byteStream(), Int.MAX_VALUE) val page1 = server.takeRequest() @@ -2554,19 +2698,22 @@ class URLConnectionTest { @Test fun response308WithPostReverted() { - client = client.newBuilder() - .addNetworkInterceptor(LegacyRedirectInterceptor()) - .build() - val response1 = MockResponse( - code = HTTP_PERM_REDIRECT, - body = "This page has moved!", - headers = headersOf("Location", "/page2"), - ) + client = + client.newBuilder() + .addNetworkInterceptor(LegacyRedirectInterceptor()) + .build() + val response1 = + MockResponse( + code = HTTP_PERM_REDIRECT, + body = "This page has moved!", + headers = headersOf("Location", "/page2"), + ) server.enqueue(response1) - val request = Request( - url = server.url("/page1"), - body = "ABCD".toRequestBody(null), - ) + val request = + Request( + url = server.url("/page1"), + body = "ABCD".toRequestBody(null), + ) val response = getResponse(request) val responseString = readAscii(response.body.byteStream(), Int.MAX_VALUE) val page1 = server.takeRequest() @@ -2576,19 +2723,24 @@ class URLConnectionTest { assertThat(responseString).isEqualTo("This page has moved!") } - private fun testRedirect(temporary: Boolean, method: String) { - val response1 = MockResponse.Builder() - .code( - if (temporary) HTTP_TEMP_REDIRECT else HTTP_PERM_REDIRECT - ) - .addHeader("Location: /page2") + private fun testRedirect( + temporary: Boolean, + method: String, + ) { + val response1 = + MockResponse.Builder() + .code( + if (temporary) HTTP_TEMP_REDIRECT else HTTP_PERM_REDIRECT, + ) + .addHeader("Location: /page2") if (method != "HEAD") { response1.body("This page has moved!") } server.enqueue(response1.build()) server.enqueue(MockResponse(body = "Page 2")) - val requestBuilder = Request.Builder() - .url(server.url("/page1")) + val requestBuilder = + Request.Builder() + .url(server.url("/page1")) if (method == "POST") { requestBuilder.post("ABCD".toRequestBody(null)) } else { @@ -2598,7 +2750,7 @@ class URLConnectionTest { val responseString = readAscii(response.body.byteStream(), Int.MAX_VALUE) val page1 = server.takeRequest() assertThat(page1.requestLine).isEqualTo( - "$method /page1 HTTP/1.1" + "$method /page1 HTTP/1.1", ) if (method == "GET") { assertThat(responseString).isEqualTo("Page 2") @@ -2619,11 +2771,11 @@ class URLConnectionTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "/" + (i + 1)), body = "Redirecting to /" + (i + 1), - ) + ), ) } server.enqueue( - MockResponse(body = "Success!") + MockResponse(body = "Success!"), ) val response = getResponse(newRequest("/0")) assertContent("Success!", response) @@ -2639,14 +2791,14 @@ class URLConnectionTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "/" + (i + 1)), body = "Redirecting to /" + (i + 1), - ) + ), ) } assertFailsWith { getResponse(newRequest("/0")) }.also { expected -> assertThat(expected.message).isEqualTo( - "Too many follow-up requests: 21" + "Too many follow-up requests: 21", ) } } @@ -2657,10 +2809,11 @@ class URLConnectionTest { val trustManager = RecordingTrustManager(handshakeCertificates.trustManager) val sslContext = get().newSSLContext() sslContext.init(null, arrayOf(trustManager), null) - client = client.newBuilder() - .hostnameVerifier(hostnameVerifier) - .sslSocketFactory(sslContext.socketFactory, trustManager) - .build() + client = + client.newBuilder() + .hostnameVerifier(hostnameVerifier) + .sslSocketFactory(sslContext.socketFactory, trustManager) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(body = "ABC")) server.enqueue(MockResponse(body = "DEF")) @@ -2690,22 +2843,23 @@ class URLConnectionTest { headers = headersOf("Connection", "Close"), body = "You took too long!", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue( - MockResponse(body = "Body") + MockResponse(body = "Body"), ) } @Test fun bufferedBodyWithClientRequestTimeout() { enqueueClientRequestTimeoutResponses() - val response = getResponse( - Request( - url = server.url("/"), - body = "Hello".toRequestBody(null), + val response = + getResponse( + Request( + url = server.url("/"), + body = "Hello".toRequestBody(null), + ), ) - ) assertThat(response.code).isEqualTo(200) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("Body") @@ -2718,12 +2872,13 @@ class URLConnectionTest { @Test fun streamedBodyWithClientRequestTimeout() { enqueueClientRequestTimeoutResponses() - val response = getResponse( - Request( - url = server.url("/"), - body = TransferKind.CHUNKED.newRequestBody("Hello"), + val response = + getResponse( + Request( + url = server.url("/"), + body = TransferKind.CHUNKED.newRequestBody("Hello"), + ), ) - ) assertThat(response.code).isEqualTo(200) assertContent("Body", response) response.close() @@ -2740,9 +2895,10 @@ class URLConnectionTest { .body("ABC") .clearHeaders() .addHeader("Content-Length: 4") - .build()) + .build(), + ) server.enqueue( - MockResponse(body = "unused") + MockResponse(body = "unused"), ) // to keep the server alive val response = getResponse(newRequest("/")) val source = response.body.source() @@ -2763,41 +2919,47 @@ class URLConnectionTest { // Sockets on some platforms can have large buffers that mean writes do not block when // required. These socket factories explicitly set the buffer sizes on sockets created. val socketBufferSize = 4 * 1024 - server.serverSocketFactory = object : DelegatingServerSocketFactory(getDefault()) { - override fun configureServerSocket(serverSocket: ServerSocket): ServerSocket { - serverSocket.receiveBufferSize = socketBufferSize - return serverSocket - } - } - client = client.newBuilder() - .socketFactory(object : DelegatingSocketFactory(getDefault()) { - override fun configureSocket(socket: Socket): Socket { - socket.receiveBufferSize = socketBufferSize - socket.sendBufferSize = socketBufferSize - return socket + server.serverSocketFactory = + object : DelegatingServerSocketFactory(getDefault()) { + override fun configureServerSocket(serverSocket: ServerSocket): ServerSocket { + serverSocket.receiveBufferSize = socketBufferSize + return serverSocket } - }) - .writeTimeout(Duration.ofMillis(500)) - .build() + } + client = + client.newBuilder() + .socketFactory( + object : DelegatingSocketFactory(getDefault()) { + override fun configureSocket(socket: Socket): Socket { + socket.receiveBufferSize = socketBufferSize + socket.sendBufferSize = socketBufferSize + return socket + } + }, + ) + .writeTimeout(Duration.ofMillis(500)) + .build() server.start() server.enqueue( MockResponse.Builder() .throttleBody(1, 1, TimeUnit.SECONDS) - .build() + .build(), ) // Prevent the server from reading! - val request = Request( - url = server.url("/"), - body = object : RequestBody() { - override fun contentType(): MediaType? { - return null - } + val request = + Request( + url = server.url("/"), + body = + object : RequestBody() { + override fun contentType(): MediaType? { + return null + } - override fun writeTo(sink: BufferedSink) { - val data = ByteArray(2 * 1024 * 1024) // 2 MiB. - sink.write(data) - } - }, - ) + override fun writeTo(sink: BufferedSink) { + val data = ByteArray(2 * 1024 * 1024) // 2 MiB. + sink.write(data) + } + }, + ) assertFailsWith { getResponse(request) } @@ -2806,13 +2968,14 @@ class URLConnectionTest { @Test fun setChunkedEncodingAsRequestProperty() { server.enqueue(MockResponse()) - val response = getResponse( - Request.Builder() - .url(server.url("/")) - .header("Transfer-encoding", "chunked") - .post(TransferKind.CHUNKED.newRequestBody("ABC")) - .build() - ) + val response = + getResponse( + Request.Builder() + .url(server.url("/")) + .header("Transfer-encoding", "chunked") + .post(TransferKind.CHUNKED.newRequestBody("ABC")) + .build(), + ) assertThat(response.code).isEqualTo(200) val request = server.takeRequest() assertThat(request.body.readUtf8()).isEqualTo("ABC") @@ -2822,19 +2985,20 @@ class URLConnectionTest { fun connectionCloseInRequest() { server.enqueue(MockResponse()) // Server doesn't honor the connection: close header! server.enqueue(MockResponse()) - val a = getResponse( - Request.Builder() - .url(server.url("/")) - .header("Connection", "close") - .build() - ) + val a = + getResponse( + Request.Builder() + .url(server.url("/")) + .header("Connection", "close") + .build(), + ) assertThat(a.code).isEqualTo(200) val b = getResponse(newRequest("/")) assertThat(b.code).isEqualTo(200) assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) assertThat( server.takeRequest().sequenceNumber, - "When connection: close is used, each request should get its own connection" + "When connection: close is used, each request should get its own connection", ).isEqualTo(0) } @@ -2858,21 +3022,24 @@ class URLConnectionTest { server.enqueue( MockResponse( code = HttpURLConnection.HTTP_MOVED_TEMP, - headers = headersOf( - "Location", "/foo", - "Connection", "close", - ), - ) + headers = + headersOf( + "Location", + "/foo", + "Connection", + "close", + ), + ), ) server.enqueue(MockResponse(body = "This is the new location!")) val response = getResponse(newRequest("/")) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)).isEqualTo( - "This is the new location!" + "This is the new location!", ) assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) assertThat( server.takeRequest().sequenceNumber, - "When connection: close is used, each request should get its own connection" + "When connection: close is used, each request should get its own connection", ).isEqualTo(0) } @@ -2887,7 +3054,7 @@ class URLConnectionTest { code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "/foo"), socketPolicy = ShutdownInputAtEnd, - ) + ), ) server.enqueue(MockResponse(body = "This is the new page!")) assertContent("This is the new page!", getResponse(newRequest("/"))) @@ -2901,7 +3068,7 @@ class URLConnectionTest { MockResponse( code = HttpURLConnection.HTTP_NO_CONTENT, body = "This body is not allowed!", - ) + ), ) assertFailsWith { getResponse(newRequest("/")) @@ -2917,9 +3084,10 @@ class URLConnectionTest { .body( Buffer() .writeByte(-2) - .writeByte(-1) + .writeByte(-1), ) - .build()) + .build(), + ) val response = getResponse(newRequest("/")) val inputStream = response.body.byteStream() assertThat(inputStream.read()).isEqualTo(254) @@ -2949,20 +3117,22 @@ class URLConnectionTest { */ private fun testFlushAfterStreamTransmitted(transferKind: TransferKind) { server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) val sinkReference = AtomicReference() - val response = getResponse( - Request( - url = server.url("/"), - body = object : ForwardingRequestBody(transferKind.newRequestBody("def")) { - override fun writeTo(sink: BufferedSink) { - sinkReference.set(sink) - super.writeTo(sink) - } - }, + val response = + getResponse( + Request( + url = server.url("/"), + body = + object : ForwardingRequestBody(transferKind.newRequestBody("def")) { + override fun writeTo(sink: BufferedSink) { + sinkReference.set(sink) + super.writeTo(sink) + } + }, + ), ) - ) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)) .isEqualTo("abc") assertFailsWith { @@ -2984,9 +3154,10 @@ class URLConnectionTest { @Test fun dnsFailureThrowsIOException() { - client = client.newBuilder() - .dns(FakeDns()) - .build() + client = + client.newBuilder() + .dns(FakeDns()) + .build() assertFailsWith { getResponse(Request("http://host.unlikelytld".toHttpUrl())) } @@ -3024,7 +3195,7 @@ class URLConnectionTest { .clearHeaders() .addHeader("Connection: close") .socketPolicy(DisconnectAtEnd) - .build() + .build(), ) val response = getResponse(newRequest("/")) val inputStream = response.body.byteStream() @@ -3047,14 +3218,15 @@ class URLConnectionTest { @Test fun clientSendsContentLength() { server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) - val response = getResponse( - Request( - url = server.url("/"), - body = "ABC".toRequestBody(null), + val response = + getResponse( + Request( + url = server.url("/"), + body = "ABC".toRequestBody(null), + ), ) - ) assertThat(readAscii(response.body.byteStream(), Int.MAX_VALUE)).isEqualTo("A") val request = server.takeRequest() assertThat(request.headers["Content-Length"]).isEqualTo("3") @@ -3064,7 +3236,7 @@ class URLConnectionTest { @Test fun getContentLengthConnects() { server.enqueue( - MockResponse(body = "ABC") + MockResponse(body = "ABC"), ) val response = getResponse(newRequest("/")) assertThat(response.body.contentLength()).isEqualTo(3L) @@ -3077,11 +3249,11 @@ class URLConnectionTest { MockResponse( headers = headersOf("Content-Type", "text/plain"), body = "ABC", - ) + ), ) val response = getResponse(newRequest("/")) assertThat(response.body.contentType()).isEqualTo( - "text/plain".toMediaType() + "text/plain".toMediaType(), ) response.body.close() } @@ -3092,7 +3264,7 @@ class URLConnectionTest { MockResponse( headers = headersOf("Content-Encoding", "identity"), body = "ABC", - ) + ), ) val response = getResponse(newRequest("/")) assertThat(response.header("Content-Encoding")).isEqualTo("identity") @@ -3102,7 +3274,7 @@ class URLConnectionTest { @Test fun urlContainsQueryButNoPath() { server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) val url = server.url("?query") val response = getResponse(Request(url)) @@ -3182,12 +3354,15 @@ class URLConnectionTest { reusedConnectionFailsWithPost(TransferKind.FIXED_LENGTH, 16384) } - private fun reusedConnectionFailsWithPost(transferKind: TransferKind, requestSize: Int) { + private fun reusedConnectionFailsWithPost( + transferKind: TransferKind, + requestSize: Int, + ) { server.enqueue( MockResponse( body = "A", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue(MockResponse(body = "B")) server.enqueue(MockResponse(body = "C")) @@ -3202,12 +3377,13 @@ class URLConnectionTest { val requestBody = String(requestBodyChars) for (j in 0..1) { try { - val response = getResponse( - Request( - url = server.url("/b"), - body = transferKind.newRequestBody(requestBody), + val response = + getResponse( + Request( + url = server.url("/b"), + body = transferKind.newRequestBody(requestBody), + ), ) - ) assertContent("B", response) break } catch (socketException: IOException) { @@ -3231,12 +3407,13 @@ class URLConnectionTest { // Seed the connection pool so we have something that can fail. assertContent("abc", getResponse(newRequest("/"))) - val post = getResponse( - Request( - url = server.url("/"), - body = "body!".toRequestBody(null), + val post = + getResponse( + Request( + url = server.url("/"), + body = "body!".toRequestBody(null), + ), ) - ) assertContent("def", post) val get = server.takeRequest() assertThat(get.sequenceNumber).isEqualTo(0) @@ -3251,23 +3428,24 @@ class URLConnectionTest { @Test fun fullyBufferedPostIsTooShort() { server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) - val requestBody: RequestBody = object : RequestBody() { - override fun contentType(): MediaType? = null + val requestBody: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType? = null - override fun contentLength(): Long = 4L + override fun contentLength(): Long = 4L - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("abc") + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("abc") + } } - } assertFailsWith { getResponse( Request( url = server.url("/b"), body = requestBody, - ) + ), ) } } @@ -3275,23 +3453,24 @@ class URLConnectionTest { @Test fun fullyBufferedPostIsTooLong() { server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) - val requestBody: RequestBody = object : RequestBody() { - override fun contentType(): MediaType? = null + val requestBody: RequestBody = + object : RequestBody() { + override fun contentType(): MediaType? = null - override fun contentLength(): Long = 3L + override fun contentLength(): Long = 3L - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("abcd") + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("abcd") + } } - } assertFailsWith { getResponse( Request( url = server.url("/b"), body = requestBody, - ) + ), ) } } @@ -3319,14 +3498,15 @@ class URLConnectionTest { @Test fun emptyRequestHeaderValueIsAllowed() { server.enqueue( - MockResponse(body = "body") - ) - val response = getResponse( - Request.Builder() - .url(server.url("/")) - .header("B", "") - .build() + MockResponse(body = "body"), ) + val response = + getResponse( + Request.Builder() + .url(server.url("/")) + .header("B", "") + .build(), + ) assertContent("body", response) assertThat(response.request.header("B")).isEqualTo("") } @@ -3337,7 +3517,7 @@ class URLConnectionTest { MockResponse( headers = headersOf("A", ""), body = "body", - ) + ), ) val response = getResponse(newRequest("/")) assertContent("body", response) @@ -3362,7 +3542,7 @@ class URLConnectionTest { MockResponse( headers = headers.build(), body = "body", - ) + ), ) val response = getResponse(newRequest("/")) assertThat(response.code).isEqualTo(200) @@ -3435,16 +3615,17 @@ class URLConnectionTest { code = 401, headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), body = "Please authenticate.", - ) + ), ) server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) val credential = basic("jesse", "peanutbutter") val authenticator = RecordingOkAuthenticator(credential, null) - client = client.newBuilder() - .authenticator(authenticator) - .build() + client = + client.newBuilder() + .authenticator(authenticator) + .build() assertContent("A", getResponse(newRequest("/private"))) assertThat(server.takeRequest().headers["Authorization"]).isNull() assertThat(server.takeRequest().headers["Authorization"]).isEqualTo(credential) @@ -3461,19 +3642,20 @@ class URLConnectionTest { code = 401, headers = headersOf("WWW-Authenticate", "Bearer realm=\"oauthed\""), body = "Please authenticate.", - ) + ), ) server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) val authenticator = RecordingOkAuthenticator("oauthed abc123", "Bearer") - client = client.newBuilder() - .authenticator(authenticator) - .build() + client = + client.newBuilder() + .authenticator(authenticator) + .build() assertContent("A", getResponse(newRequest("/private"))) assertThat(server.takeRequest().headers["Authorization"]).isNull() assertThat(server.takeRequest().headers["Authorization"]).isEqualTo( - "oauthed abc123" + "oauthed abc123", ) val response = authenticator.onlyResponse() assertThat(response.request.url.toUrl().path).isEqualTo("/private") @@ -3486,23 +3668,26 @@ class URLConnectionTest { MockResponse( code = 302, headers = headersOf("Location", "/b"), - ) + ), ) server.enqueue( MockResponse( code = 401, headers = headersOf("WWW-Authenticate", "Basic realm=\"protected area\""), - ) + ), ) server.enqueue( - MockResponse(body = "c") + MockResponse(body = "c"), ) - val authenticator = RecordingOkAuthenticator( - basic("jesse", "peanutbutter"), "Basic" - ) - client = client.newBuilder() - .authenticator(authenticator) - .build() + val authenticator = + RecordingOkAuthenticator( + basic("jesse", "peanutbutter"), + "Basic", + ) + client = + client.newBuilder() + .authenticator(authenticator) + .build() assertContent("c", getResponse(newRequest("/a"))) val challengeResponse = authenticator.responses[0] assertThat(challengeResponse.request.url.toUrl().path).isEqualTo("/b") @@ -3514,16 +3699,17 @@ class URLConnectionTest { fun attemptAuthorization20Times() { for (i in 0..19) { server.enqueue( - MockResponse(code = 401) + MockResponse(code = 401), ) } server.enqueue( - MockResponse(body = "Success!") + MockResponse(body = "Success!"), ) val credential = basic("jesse", "peanutbutter") - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(credential, null)) - .build() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(credential, null)) + .build() val response = getResponse(newRequest("/0")) assertContent("Success!", response) } @@ -3532,13 +3718,14 @@ class URLConnectionTest { fun doesNotAttemptAuthorization21Times() { for (i in 0..20) { server.enqueue( - MockResponse(code = 401) + MockResponse(code = 401), ) } val credential = basic("jesse", "peanutbutter") - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(credential, null)) - .build() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(credential, null)) + .build() assertFailsWith { getResponse(newRequest("/")) }.also { expected -> @@ -3555,11 +3742,12 @@ class URLConnectionTest { private fun setsNegotiatedProtocolHeader(protocol: Protocol) { enableProtocol(protocol) server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) - client = client.newBuilder() - .protocols(Arrays.asList(protocol, Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .protocols(Arrays.asList(protocol, Protocol.HTTP_1_1)) + .build() val response = getResponse(newRequest("/")) assertThat(response.protocol).isEqualTo(protocol) assertContent("A", response) @@ -3570,7 +3758,7 @@ class URLConnectionTest { server.enqueue( MockResponse.Builder() .status("HTTP/1.0 200 OK") - .build() + .build(), ) val response = getResponse(newRequest("/")) assertThat(response.protocol).isEqualTo(Protocol.HTTP_1_0) @@ -3581,7 +3769,7 @@ class URLConnectionTest { server.enqueue( MockResponse.Builder() .status("HTTP/1.1 200 OK") - .build() + .build(), ) val response = getResponse(newRequest("/")) assertThat(response.protocol).isEqualTo(Protocol.HTTP_1_1) @@ -3613,12 +3801,13 @@ class URLConnectionTest { private fun zeroLengthPayload(method: String) { server.enqueue(MockResponse()) - val response = getResponse( - Request.Builder() - .url(server.url("/")) - .method(method, "".toRequestBody(null)) - .build() - ) + val response = + getResponse( + Request.Builder() + .url(server.url("/")) + .method(method, "".toRequestBody(null)) + .build(), + ) assertContent("", response) val zeroLengthPayload = server.takeRequest() assertThat(zeroLengthPayload.method).isEqualTo(method) @@ -3629,11 +3818,12 @@ class URLConnectionTest { @Test fun setProtocols() { server.enqueue( - MockResponse(body = "A") + MockResponse(body = "A"), ) - client = client.newBuilder() - .protocols(Arrays.asList(Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .protocols(Arrays.asList(Protocol.HTTP_1_1)) + .build() assertContent("A", getResponse(newRequest("/"))) } @@ -3658,30 +3848,32 @@ class URLConnectionTest { server.bodyLimit = 0 server.enqueue(MockResponse()) val contentLength = Int.MAX_VALUE + 1L - val response = getResponse( - Request( - url = server.url("/"), - body = object : RequestBody() { - override fun contentType(): MediaType? = null - - override fun contentLength(): Long = contentLength - - override fun writeTo(sink: BufferedSink) { - val buffer = ByteArray(1024 * 1024) - var bytesWritten: Long = 0 - while (bytesWritten < contentLength) { - val byteCount = Math.min(buffer.size.toLong(), contentLength - bytesWritten).toInt() - bytesWritten += byteCount.toLong() - sink.write(buffer, 0, byteCount) - } - } - }, + val response = + getResponse( + Request( + url = server.url("/"), + body = + object : RequestBody() { + override fun contentType(): MediaType? = null + + override fun contentLength(): Long = contentLength + + override fun writeTo(sink: BufferedSink) { + val buffer = ByteArray(1024 * 1024) + var bytesWritten: Long = 0 + while (bytesWritten < contentLength) { + val byteCount = Math.min(buffer.size.toLong(), contentLength - bytesWritten).toInt() + bytesWritten += byteCount.toLong() + sink.write(buffer, 0, byteCount) + } + } + }, + ), ) - ) assertContent("", response) val request = server.takeRequest() assertThat(request.headers["Content-Length"]).isEqualTo( - java.lang.Long.toString(contentLength) + java.lang.Long.toString(contentLength), ) } @@ -3692,11 +3884,12 @@ class URLConnectionTest { server.useHttps(handshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse(socketPolicy = FailHandshake)) server.enqueue(MockResponse(body = "Response that would have needed fallbacks")) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .build() assertFailsWith { getResponse(newRequest("/")) }.also { expected -> @@ -3731,9 +3924,10 @@ class URLConnectionTest { .clearHeaders() .code(HttpURLConnection.HTTP_NOT_MODIFIED) .addHeader("Content-Encoding: gzip") - .build()) + .build(), + ) server.enqueue( - MockResponse(body = "b") + MockResponse(body = "b"), ) val response1 = getResponse(newRequest("/")) assertThat(response1.code).isEqualTo(HttpURLConnection.HTTP_NOT_MODIFIED) @@ -3759,9 +3953,10 @@ class URLConnectionTest { .addHeader("Location: /foo") .addHeader("Content-Encoding: gzip") .body(gzip("Moved! Moved! Moved!")) - .build()) + .build(), + ) server.enqueue( - MockResponse(body = "This is the new page!") + MockResponse(body = "This is the new page!"), ) val response = getResponse(newRequest("/")) assertContent("This is the new page!", response) @@ -3778,12 +3973,13 @@ class URLConnectionTest { @Test fun bodyPermittedOnDelete() { server.enqueue(MockResponse()) - val response = getResponse( - Request.Builder() - .url(server.url("/")) - .delete("BODY".toRequestBody(null)) - .build() - ) + val response = + getResponse( + Request.Builder() + .url(server.url("/")) + .delete("BODY".toRequestBody(null)) + .build(), + ) assertThat(response.code).isEqualTo(200) val request = server.takeRequest() assertThat(request.method).isEqualTo("DELETE") @@ -3793,7 +3989,7 @@ class URLConnectionTest { @Test fun userAgentDefaultsToOkHttpVersion() { server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) assertContent("abc", getResponse(newRequest("/"))) val request = server.takeRequest() @@ -3828,7 +4024,7 @@ class URLConnectionTest { MockResponse.Builder() .code(302) .addHeaderLenient("Location", redirectUrl) - .build() + .build(), ) val response = getResponse(newRequest("/")) assertThat(response.code).isEqualTo(302) @@ -3855,9 +4051,10 @@ class URLConnectionTest { /** Confirm that runtime exceptions thrown inside of OkHttp propagate to the caller. */ @Test fun unexpectedExceptionSync() { - client = client.newBuilder() - .dns { hostname: String? -> throw RuntimeException("boom!") } - .build() + client = + client.newBuilder() + .dns { hostname: String? -> throw RuntimeException("boom!") } + .build() server.enqueue(MockResponse()) assertFailsWith { getResponse(newRequest("/")) @@ -3874,10 +4071,10 @@ class URLConnectionTest { MockResponse( body = "abc", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue( - MockResponse(body = "def") + MockResponse(body = "def"), ) // Send a separate request which will trigger a GOAWAY frame on the healthy connection. @@ -3892,8 +4089,8 @@ class URLConnectionTest { Request( url = server.url("/"), body = "123".toRequestBody(null), - ) - ) + ), + ), ) val request1 = server.takeRequest() assertThat(request1.sequenceNumber).isEqualTo(0) @@ -3909,12 +4106,13 @@ class URLConnectionTest { code = 401, headers = headersOf("Connection", "close"), socketPolicy = DisconnectAtEnd, - ) + ), ) java.net.Authenticator.setDefault(RecordingAuthenticator(null)) - client = client.newBuilder() - .authenticator(JavaNetAuthenticator()) - .build() + client = + client.newBuilder() + .authenticator(JavaNetAuthenticator()) + .build() val response = getResponse(newRequest("/")) assertThat(response.code).isEqualTo(401) } @@ -3937,7 +4135,7 @@ class URLConnectionTest { private fun assertContent( expected: String, response: Response, - limit: Int = Int.MAX_VALUE + limit: Int = Int.MAX_VALUE, ) { assertThat(readAscii(response.body.byteStream(), limit)).isEqualTo(expected) } @@ -3948,7 +4146,11 @@ class URLConnectionTest { internal enum class TransferKind { CHUNKED { - override fun setBody(response: MockResponse.Builder, content: Buffer?, chunkSize: Int) { + override fun setBody( + response: MockResponse.Builder, + content: Buffer?, + chunkSize: Int, + ) { response.chunkedBody(content!!, chunkSize) } @@ -3966,7 +4168,11 @@ class URLConnectionTest { }, FIXED_LENGTH { - override fun setBody(response: MockResponse.Builder, content: Buffer?, chunkSize: Int) { + override fun setBody( + response: MockResponse.Builder, + content: Buffer?, + chunkSize: Int, + ) { response.body(content!!) } @@ -3984,7 +4190,11 @@ class URLConnectionTest { }, END_OF_STREAM { - override fun setBody(response: MockResponse.Builder, content: Buffer?, chunkSize: Int) { + override fun setBody( + response: MockResponse.Builder, + content: Buffer?, + chunkSize: Int, + ) { response.body(content!!) response.socketPolicy(DisconnectAtEnd) response.removeHeader("Content-Length") @@ -3993,19 +4203,20 @@ class URLConnectionTest { override fun newRequestBody(body: String): RequestBody { throw TestAbortedException("END_OF_STREAM not implemented for requests") } - }; + }, ; abstract fun setBody( response: MockResponse.Builder, content: Buffer?, - chunkSize: Int + chunkSize: Int, ) abstract fun newRequestBody(body: String): RequestBody + fun setBody( response: MockResponse.Builder, content: String?, - chunkSize: Int + chunkSize: Int, ) { setBody(response, Buffer().writeUtf8(content!!), chunkSize) } @@ -4013,44 +4224,66 @@ class URLConnectionTest { internal enum class ProxyConfig { NO_PROXY { - override fun connect(server: MockWebServer, client: OkHttpClient): Call.Factory { + override fun connect( + server: MockWebServer, + client: OkHttpClient, + ): Call.Factory { return client.newBuilder() .proxy(Proxy.NO_PROXY) .build() } }, CREATE_ARG { - override fun connect(server: MockWebServer, client: OkHttpClient): Call.Factory { + override fun connect( + server: MockWebServer, + client: OkHttpClient, + ): Call.Factory { return client.newBuilder() .proxy(server.toProxyAddress()) .build() } }, PROXY_SYSTEM_PROPERTY { - override fun connect(server: MockWebServer, client: OkHttpClient): Call.Factory { + override fun connect( + server: MockWebServer, + client: OkHttpClient, + ): Call.Factory { System.setProperty("proxyHost", server.hostName) System.setProperty("proxyPort", server.port.toString()) return client } }, HTTP_PROXY_SYSTEM_PROPERTY { - override fun connect(server: MockWebServer, client: OkHttpClient): Call.Factory { + override fun connect( + server: MockWebServer, + client: OkHttpClient, + ): Call.Factory { System.setProperty("http.proxyHost", server.hostName) System.setProperty("http.proxyPort", server.port.toString()) return client } }, HTTPS_PROXY_SYSTEM_PROPERTY { - override fun connect(server: MockWebServer, client: OkHttpClient): Call.Factory { + override fun connect( + server: MockWebServer, + client: OkHttpClient, + ): Call.Factory { System.setProperty("https.proxyHost", server.hostName) System.setProperty("https.proxyPort", server.port.toString()) return client } - }; - - abstract fun connect(server: MockWebServer, client: OkHttpClient): Call.Factory - - fun connect(server: MockWebServer, client: OkHttpClient, url: HttpUrl): Call { + }, ; + + abstract fun connect( + server: MockWebServer, + client: OkHttpClient, + ): Call.Factory + + fun connect( + server: MockWebServer, + client: OkHttpClient, + url: HttpUrl, + ): Call { return connect(server, client) .newCall(Request(url)) } @@ -4061,11 +4294,17 @@ class URLConnectionTest { override fun getAcceptedIssuers(): Array = delegate.acceptedIssuers - override fun checkClientTrusted(chain: Array, authType: String) { + override fun checkClientTrusted( + chain: Array, + authType: String, + ) { calls.add("checkClientTrusted " + certificatesToString(chain)) } - override fun checkServerTrusted(chain: Array, authType: String) { + override fun checkServerTrusted( + chain: Array, + authType: String, + ) { calls.add("checkServerTrusted " + certificatesToString(chain)) } @@ -4082,14 +4321,15 @@ class URLConnectionTest { * Tests that use this will fail unless boot classpath is set. Ex. `-Xbootclasspath/p:/tmp/alpn-boot-8.0.0.v20140317` */ private fun enableProtocol(protocol: Protocol) { - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .protocols(Arrays.asList(protocol, Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .protocols(Arrays.asList(protocol, Protocol.HTTP_1_1)) + .build() server.useHttps(handshakeCertificates.sslSocketFactory()) server.protocolNegotiationEnabled = true server.protocols = client.protocols @@ -4100,6 +4340,5 @@ class URLConnectionTest { * TLS_FALLBACK_SCSV cipher on fallback connections. See [FallbackTestClientSocketFactory] * for details. */ - private fun suppressTlsFallbackClientSocketFactory() = - FallbackTestClientSocketFactory(handshakeCertificates.sslSocketFactory()) + private fun suppressTlsFallbackClientSocketFactory() = FallbackTestClientSocketFactory(handshakeCertificates.sslSocketFactory()) } diff --git a/okhttp/src/test/java/okhttp3/UrlComponentEncodingTester.kt b/okhttp/src/test/java/okhttp3/UrlComponentEncodingTester.kt index abaff3fe7eb4..594b8c39c473 100644 --- a/okhttp/src/test/java/okhttp3/UrlComponentEncodingTester.kt +++ b/okhttp/src/test/java/okhttp3/UrlComponentEncodingTester.kt @@ -33,88 +33,103 @@ import okio.ByteString.Companion.encodeUtf8 class UrlComponentEncodingTester private constructor() { private val encodings: MutableMap = LinkedHashMap() - private fun allAscii(encoding: Encoding) = apply { - for (i in 0..127) { - encodings[i] = encoding + private fun allAscii(encoding: Encoding) = + apply { + for (i in 0..127) { + encodings[i] = encoding + } } - } - fun override(encoding: Encoding, vararg codePoints: Int) = apply { + fun override( + encoding: Encoding, + vararg codePoints: Int, + ) = apply { for (codePoint in codePoints) { encodings[codePoint] = encoding } } - fun nonPrintableAscii(encoding: Encoding) = apply { - encodings[ 0x0] = encoding // Null character - encodings[ 0x1] = encoding // Start of Header - encodings[ 0x2] = encoding // Start of Text - encodings[ 0x3] = encoding // End of Text - encodings[ 0x4] = encoding // End of Transmission - encodings[ 0x5] = encoding // Enquiry - encodings[ 0x6] = encoding // Acknowledgment - encodings[ 0x7] = encoding // Bell - encodings['\b'.code] = encoding // Backspace - encodings[ 0xb] = encoding // Vertical Tab - encodings[ 0xe] = encoding // Shift Out - encodings[ 0xf] = encoding // Shift In - encodings[ 0x10] = encoding // Data Link Escape - encodings[ 0x11] = encoding // Device Control 1 (oft. XON) - encodings[ 0x12] = encoding // Device Control 2 - encodings[ 0x13] = encoding // Device Control 3 (oft. XOFF) - encodings[ 0x14] = encoding // Device Control 4 - encodings[ 0x15] = encoding // Negative Acknowledgment - encodings[ 0x16] = encoding // Synchronous idle - encodings[ 0x17] = encoding // End of Transmission Block - encodings[ 0x18] = encoding // Cancel - encodings[ 0x19] = encoding // End of Medium - encodings[ 0x1a] = encoding // Substitute - encodings[ 0x1b] = encoding // Escape - encodings[ 0x1c] = encoding // File Separator - encodings[ 0x1d] = encoding // Group Separator - encodings[ 0x1e] = encoding // Record Separator - encodings[ 0x1f] = encoding // Unit Separator - encodings[ 0x7f] = encoding // Delete - } + fun nonPrintableAscii(encoding: Encoding) = + apply { + encodings[ 0x0] = encoding // Null character + encodings[ 0x1] = encoding // Start of Header + encodings[ 0x2] = encoding // Start of Text + encodings[ 0x3] = encoding // End of Text + encodings[ 0x4] = encoding // End of Transmission + encodings[ 0x5] = encoding // Enquiry + encodings[ 0x6] = encoding // Acknowledgment + encodings[ 0x7] = encoding // Bell + encodings['\b'.code] = encoding // Backspace + encodings[ 0xb] = encoding // Vertical Tab + encodings[ 0xe] = encoding // Shift Out + encodings[ 0xf] = encoding // Shift In + encodings[ 0x10] = encoding // Data Link Escape + encodings[ 0x11] = encoding // Device Control 1 (oft. XON) + encodings[ 0x12] = encoding // Device Control 2 + encodings[ 0x13] = encoding // Device Control 3 (oft. XOFF) + encodings[ 0x14] = encoding // Device Control 4 + encodings[ 0x15] = encoding // Negative Acknowledgment + encodings[ 0x16] = encoding // Synchronous idle + encodings[ 0x17] = encoding // End of Transmission Block + encodings[ 0x18] = encoding // Cancel + encodings[ 0x19] = encoding // End of Medium + encodings[ 0x1a] = encoding // Substitute + encodings[ 0x1b] = encoding // Escape + encodings[ 0x1c] = encoding // File Separator + encodings[ 0x1d] = encoding // Group Separator + encodings[ 0x1e] = encoding // Record Separator + encodings[ 0x1f] = encoding // Unit Separator + encodings[ 0x7f] = encoding // Delete + } - fun nonAscii(encoding: Encoding) = apply { - encodings[UNICODE_2] = encoding - encodings[UNICODE_3] = encoding - encodings[UNICODE_4] = encoding - } + fun nonAscii(encoding: Encoding) = + apply { + encodings[UNICODE_2] = encoding + encodings[UNICODE_3] = encoding + encodings[UNICODE_4] = encoding + } - fun test(component: Component) = apply { - for ((codePoint, encoding) in encodings) { - val codePointString = Encoding.IDENTITY.encode(codePoint) - if (encoding == Encoding.FORBIDDEN) { - testForbidden(codePoint, codePointString, component) - continue - } - if (encoding == Encoding.PUNYCODE) { - testPunycode(codePointString, component) - continue - } - testEncodeAndDecode(codePoint, codePointString, component) - if (encoding == Encoding.SKIP) continue - testParseOriginal(codePoint, codePointString, encoding, component) - testParseAlreadyEncoded(codePoint, encoding, component) + fun test(component: Component) = + apply { + for ((codePoint, encoding) in encodings) { + val codePointString = Encoding.IDENTITY.encode(codePoint) + if (encoding == Encoding.FORBIDDEN) { + testForbidden(codePoint, codePointString, component) + continue + } + if (encoding == Encoding.PUNYCODE) { + testPunycode(codePointString, component) + continue + } + testEncodeAndDecode(codePoint, codePointString, component) + if (encoding == Encoding.SKIP) continue + testParseOriginal(codePoint, codePointString, encoding, component) + testParseAlreadyEncoded(codePoint, encoding, component) - val platform = urlComponentEncodingTesterJvmPlatform(component) - platform.test(codePoint, codePointString, encoding, component) + val platform = urlComponentEncodingTesterJvmPlatform(component) + platform.test(codePoint, codePointString, encoding, component) + } } - } - private fun testParseAlreadyEncoded(codePoint: Int, encoding: Encoding, component: Component) { + private fun testParseAlreadyEncoded( + codePoint: Int, + encoding: Encoding, + component: Component, + ) { val expected = component.canonicalize(encoding.encode(codePoint)) val urlString = component.urlString(expected) val url = urlString.toHttpUrl() val actual = component.encodedValue(url) if (actual != expected) { - fail("Encoding $component $codePoint using $encoding: '$actual' != '$expected'") + fail("Encoding $component $codePoint using $encoding: '$actual' != '$expected'") } } - private fun testEncodeAndDecode(codePoint: Int, codePointString: String, component: Component) { + private fun testEncodeAndDecode( + codePoint: Int, + codePointString: String, + component: Component, + ) { val builder = "http://host/".toHttpUrl().newBuilder() component[builder] = codePointString val url = builder.build() @@ -141,14 +156,21 @@ class UrlComponentEncodingTester private constructor() { } } - private fun testForbidden(codePoint: Int, codePointString: String, component: Component) { + private fun testForbidden( + codePoint: Int, + codePointString: String, + component: Component, + ) { val builder = "http://host/".toHttpUrl().newBuilder() assertFailsWith { component[builder] = codePointString } } - private fun testPunycode(codePointString: String, component: Component) { + private fun testPunycode( + codePointString: String, + component: Component, + ) { val builder = "http://host/".toHttpUrl().newBuilder() component[builder] = codePointString val url = builder.build() @@ -180,7 +202,9 @@ class UrlComponentEncodingTester private constructor() { PUNYCODE, /** This code point is special and should not be tested. */ - SKIP; + SKIP, + + ; open fun encode(codePoint: Int): String { throw UnsupportedOperationException() @@ -190,44 +214,69 @@ class UrlComponentEncodingTester private constructor() { enum class Component { USER { override fun urlString(value: String): String = "http://$value@example.com/" + override fun encodedValue(url: HttpUrl): String = url.encodedUsername - override operator fun set(builder: HttpUrl.Builder, value: String) { + + override operator fun set( + builder: HttpUrl.Builder, + value: String, + ) { builder.username(value) } + override operator fun get(url: HttpUrl): String = url.username }, PASSWORD { override fun urlString(value: String): String = "http://:$value@example.com/" + override fun encodedValue(url: HttpUrl): String = url.encodedPassword - override operator fun set(builder: HttpUrl.Builder, value: String) { + + override operator fun set( + builder: HttpUrl.Builder, + value: String, + ) { builder.password(value) } + override operator fun get(url: HttpUrl): String = url.password }, HOST { override fun urlString(value: String): String = "http://a${value}z.com/" + override fun encodedValue(url: HttpUrl): String = get(url) - override operator fun set(builder: HttpUrl.Builder, value: String) { + + override operator fun set( + builder: HttpUrl.Builder, + value: String, + ) { builder.host("a${value}z.com") } + override operator fun get(url: HttpUrl): String { val host = url.host return host.substring(1, host.length - 5).lowercase() } + override fun canonicalize(s: String): String = s.lowercase() }, PATH { override fun urlString(value: String): String = "http://example.com/a${value}z/" + override fun encodedValue(url: HttpUrl): String { val path = url.encodedPath return path.substring(2, path.length - 2) } - override operator fun set(builder: HttpUrl.Builder, value: String) { + + override operator fun set( + builder: HttpUrl.Builder, + value: String, + ) { builder.addPathSegment("a${value}z") } + override operator fun get(url: HttpUrl): String { val pathSegment = url.pathSegments[0] return pathSegment.substring(1, pathSegment.length - 1) @@ -236,13 +285,19 @@ class UrlComponentEncodingTester private constructor() { QUERY { override fun urlString(value: String): String = "http://example.com/?a${value}z" + override fun encodedValue(url: HttpUrl): String { val query = url.encodedQuery return query!!.substring(1, query.length - 1) } - override operator fun set(builder: HttpUrl.Builder, value: String) { + + override operator fun set( + builder: HttpUrl.Builder, + value: String, + ) { builder.query("a${value}z") } + override operator fun get(url: HttpUrl): String { val query = url.query return query!!.substring(1, query.length - 1) @@ -251,13 +306,19 @@ class UrlComponentEncodingTester private constructor() { QUERY_VALUE { override fun urlString(value: String): String = "http://example.com/?q=a${value}z" + override fun encodedValue(url: HttpUrl): String { val query = url.encodedQuery return query!!.substring(3, query.length - 1) } - override operator fun set(builder: HttpUrl.Builder, value: String) { + + override operator fun set( + builder: HttpUrl.Builder, + value: String, + ) { builder.addQueryParameter("q", "a${value}z") } + override operator fun get(url: HttpUrl): String { val value = url.queryParameter("q") return value!!.substring(1, value.length - 1) @@ -266,22 +327,34 @@ class UrlComponentEncodingTester private constructor() { FRAGMENT { override fun urlString(value: String): String = "http://example.com/#a${value}z" + override fun encodedValue(url: HttpUrl): String { val fragment = url.encodedFragment return fragment!!.substring(1, fragment.length - 1) } - override operator fun set(builder: HttpUrl.Builder, value: String) { + + override operator fun set( + builder: HttpUrl.Builder, + value: String, + ) { builder.fragment("a${value}z") } + override operator fun get(url: HttpUrl): String { val fragment = url.fragment return fragment!!.substring(1, fragment.length - 1) } - }; + }, ; abstract fun urlString(value: String): String + abstract fun encodedValue(url: HttpUrl): String - abstract operator fun set(builder: HttpUrl.Builder, value: String) + + abstract operator fun set( + builder: HttpUrl.Builder, + value: String, + ) + abstract operator fun get(url: HttpUrl): String /** @@ -305,8 +378,10 @@ class UrlComponentEncodingTester private constructor() { companion object { /** Arbitrary code point that's 2 bytes in UTF-8 and valid in IdnaMappingTable.txt. */ private const val UNICODE_2 = 0x1a5 + /** Arbitrary code point that's 3 bytes in UTF-8 and valid in IdnaMappingTable.txt. */ private const val UNICODE_3 = 0x2202 + /** Arbitrary code point that's 4 bytes in UTF-8 and valid in IdnaMappingTable.txt. */ private const val UNICODE_4 = 0x1d11e @@ -326,7 +401,7 @@ class UrlComponentEncodingTester private constructor() { '\t'.code, '\n'.code, '\u000c'.code, - '\r'.code + '\r'.code, ) .override( Encoding.PERCENT, @@ -336,13 +411,13 @@ class UrlComponentEncodingTester private constructor() { '<'.code, '>'.code, '?'.code, - '`'.code + '`'.code, ) .override( Encoding.PERCENT, UNICODE_2, UNICODE_3, - UNICODE_4 + UNICODE_4, ) } } diff --git a/okhttp/src/test/java/okhttp3/UrlComponentEncodingTesterJvm.kt b/okhttp/src/test/java/okhttp3/UrlComponentEncodingTesterJvm.kt index 502495c62558..9bccf7c88ed5 100644 --- a/okhttp/src/test/java/okhttp3/UrlComponentEncodingTesterJvm.kt +++ b/okhttp/src/test/java/okhttp3/UrlComponentEncodingTesterJvm.kt @@ -20,72 +20,77 @@ import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.UrlComponentEncodingTester.Component -fun urlComponentEncodingTesterJvmPlatform( - component: Component, -): UrlComponentEncodingTester.Platform { +fun urlComponentEncodingTesterJvmPlatform(component: Component): UrlComponentEncodingTester.Platform { return when (component) { - Component.USER -> UrlComponentEncodingTesterJvmPlatform() - .escapeForUri('%'.code) - - Component.PASSWORD -> UrlComponentEncodingTesterJvmPlatform() - .escapeForUri('%'.code) - - Component.HOST -> UrlComponentEncodingTesterJvmPlatform() - .stripForUri( - '\"'.code, - '<'.code, - '>'.code, - '^'.code, - '`'.code, - '{'.code, - '|'.code, - '}'.code - ) - - Component.PATH -> UrlComponentEncodingTesterJvmPlatform() - .escapeForUri( - '%'.code, - '['.code, - ']'.code, - ) - - Component.QUERY -> UrlComponentEncodingTesterJvmPlatform() - .escapeForUri( - '%'.code, - '\\'.code, - '^'.code, - '`'.code, - '{'.code, - '|'.code, - '}'.code - ) - - Component.QUERY_VALUE -> UrlComponentEncodingTesterJvmPlatform() - .escapeForUri( - '%'.code, - '\\'.code, - '^'.code, - '`'.code, - '{'.code, - '|'.code, - '}'.code - ) - - Component.FRAGMENT -> UrlComponentEncodingTesterJvmPlatform() - .escapeForUri( - '%'.code, - ' '.code, - '"'.code, - '#'.code, - '<'.code, - '>'.code, - '\\'.code, - '^'.code, - '`'.code, - '{'.code, - '|'.code, - '}'.code - ) + Component.USER -> + UrlComponentEncodingTesterJvmPlatform() + .escapeForUri('%'.code) + + Component.PASSWORD -> + UrlComponentEncodingTesterJvmPlatform() + .escapeForUri('%'.code) + + Component.HOST -> + UrlComponentEncodingTesterJvmPlatform() + .stripForUri( + '\"'.code, + '<'.code, + '>'.code, + '^'.code, + '`'.code, + '{'.code, + '|'.code, + '}'.code, + ) + + Component.PATH -> + UrlComponentEncodingTesterJvmPlatform() + .escapeForUri( + '%'.code, + '['.code, + ']'.code, + ) + + Component.QUERY -> + UrlComponentEncodingTesterJvmPlatform() + .escapeForUri( + '%'.code, + '\\'.code, + '^'.code, + '`'.code, + '{'.code, + '|'.code, + '}'.code, + ) + + Component.QUERY_VALUE -> + UrlComponentEncodingTesterJvmPlatform() + .escapeForUri( + '%'.code, + '\\'.code, + '^'.code, + '`'.code, + '{'.code, + '|'.code, + '}'.code, + ) + + Component.FRAGMENT -> + UrlComponentEncodingTesterJvmPlatform() + .escapeForUri( + '%'.code, + ' '.code, + '"'.code, + '#'.code, + '<'.code, + '>'.code, + '\\'.code, + '^'.code, + '`'.code, + '{'.code, + '|'.code, + '}'.code, + ) } } @@ -97,23 +102,25 @@ private class UrlComponentEncodingTesterJvmPlatform : UrlComponentEncodingTester * Configure code points to be escaped for conversion to `java.net.URI`. That class is more * strict than the others. */ - fun escapeForUri(vararg codePoints: Int) = apply { - uriEscapedCodePoints.append(String(*codePoints)) - } + fun escapeForUri(vararg codePoints: Int) = + apply { + uriEscapedCodePoints.append(String(*codePoints)) + } /** * Configure code points to be stripped in conversion to `java.net.URI`. That class is more * strict than the others. */ - fun stripForUri(vararg codePoints: Int) = apply { - uriStrippedCodePoints.append(String(*codePoints)) - } + fun stripForUri(vararg codePoints: Int) = + apply { + uriStrippedCodePoints.append(String(*codePoints)) + } override fun test( codePoint: Int, codePointString: String, encoding: UrlComponentEncodingTester.Encoding, - component: Component + component: Component, ) { testToUrl(codePoint, encoding, component) testFromUrl(codePoint, encoding, component) diff --git a/okhttp/src/test/java/okhttp3/WebPlatformToAsciiTest.kt b/okhttp/src/test/java/okhttp3/WebPlatformToAsciiTest.kt index 74cd2740d06d..70c7b65b11e2 100644 --- a/okhttp/src/test/java/okhttp3/WebPlatformToAsciiTest.kt +++ b/okhttp/src/test/java/okhttp3/WebPlatformToAsciiTest.kt @@ -23,40 +23,34 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull /** Runs the web platform ToAscii tests. */ class WebPlatformToAsciiTest { @Suppress("ktlint:standard:max-line-length") - val knownFailures = setOf( - // OkHttp rejects empty labels. - "x..xn--zca", - "x..ß", - - // OkHttp rejects labels longer than 63 code points, the web platform tests don't. - "x01234567890123456789012345678901234567890123456789012345678901x.xn--zca", - "x01234567890123456789012345678901234567890123456789012345678901x.ß", - "x01234567890123456789012345678901234567890123456789012345678901x", - "x01234567890123456789012345678901234567890123456789012345678901†", - - // OkHttp rejects domain names longer than 253 code points, the web platform tests don't. - "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.x", - "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--zca", - "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.ß", - - // OkHttp does not reject invalid Punycode. - "xn--a", - "xn--a.ß", - "xn--a.xn--zca", - "xn--a-yoc", - - // OkHttp doesn't reject U+FFFD encoded in Punycode. - "xn--zn7c.com", - - // OkHttp doesn't reject a U+200D. https://www.rfc-editor.org/rfc/rfc5892.html#appendix-A.2 - "xn--1ug.example", - - // OkHttp doesn't implement CheckJoiners. - "\u200D.example", - - // OkHttp doesn't implement CheckBidi. - "يa", - ) + val knownFailures = + setOf( + // OkHttp rejects empty labels. + "x..xn--zca", + "x..ß", + // OkHttp rejects labels longer than 63 code points, the web platform tests don't. + "x01234567890123456789012345678901234567890123456789012345678901x.xn--zca", + "x01234567890123456789012345678901234567890123456789012345678901x.ß", + "x01234567890123456789012345678901234567890123456789012345678901x", + "x01234567890123456789012345678901234567890123456789012345678901†", + // OkHttp rejects domain names longer than 253 code points, the web platform tests don't. + "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.x", + "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--zca", + "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.ß", + // OkHttp does not reject invalid Punycode. + "xn--a", + "xn--a.ß", + "xn--a.xn--zca", + "xn--a-yoc", + // OkHttp doesn't reject U+FFFD encoded in Punycode. + "xn--zn7c.com", + // OkHttp doesn't reject a U+200D. https://www.rfc-editor.org/rfc/rfc5892.html#appendix-A.2 + "xn--1ug.example", + // OkHttp doesn't implement CheckJoiners. + "\u200D.example", + // OkHttp doesn't implement CheckBidi. + "يa", + ) @Test fun test() { @@ -85,7 +79,11 @@ class WebPlatformToAsciiTest { } } - private fun testToAscii(input: String, output: String?, comment: String?) { + private fun testToAscii( + input: String, + output: String?, + comment: String?, + ) { val url = "https://$input/".toHttpUrlOrNull() assertThat(url?.host, name = comment ?: input).isEqualTo(output) } diff --git a/okhttp/src/test/java/okhttp3/WebPlatformUrlTest.kt b/okhttp/src/test/java/okhttp3/WebPlatformUrlTest.kt index efe85cfa2072..899836304c8d 100644 --- a/okhttp/src/test/java/okhttp3/WebPlatformUrlTest.kt +++ b/okhttp/src/test/java/okhttp3/WebPlatformUrlTest.kt @@ -42,9 +42,9 @@ class WebPlatformUrlTest { return } - if (!testData.base!!.startsWith("https:") - && !testData.base!!.startsWith("http:") - && testData.base != "about:blank" + if (!testData.base!!.startsWith("https:") && + !testData.base!!.startsWith("http:") && + testData.base != "about:blank" ) { System.err.println("Ignoring unsupported base ${testData.base}") return @@ -66,10 +66,11 @@ class WebPlatformUrlTest { } private fun testHttpUrl(testData: WebPlatformUrlTestData) { - val url = when (testData.base) { - "about:blank" -> testData.input!!.toHttpUrlOrNull() - else -> testData.base!!.toHttpUrl().resolve(testData.input!!) - } + val url = + when (testData.base) { + "about:blank" -> testData.input!!.toHttpUrlOrNull() + else -> testData.base!!.toHttpUrl().resolve(testData.input!!) + } if (testData.expectParseFailure()) { assertThat(url, "Expected URL to fail parsing").isNull() @@ -78,22 +79,26 @@ class WebPlatformUrlTest { assertThat(url, "Expected URL to parse successfully, but was null") .isNotNull() - val effectivePort = when { - url!!.port != defaultPort(url.scheme) -> Integer.toString(url.port) - else -> "" - } - val effectiveQuery = when { - url.encodedQuery != null -> "?" + url.encodedQuery - else -> "" - } - val effectiveFragment = when { - url.encodedFragment != null -> "#" + url.encodedFragment - else -> "" - } - val effectiveHost = when { - url.host.contains(":") -> "[" + url.host + "]" - else -> url.host - } + val effectivePort = + when { + url!!.port != defaultPort(url.scheme) -> Integer.toString(url.port) + else -> "" + } + val effectiveQuery = + when { + url.encodedQuery != null -> "?" + url.encodedQuery + else -> "" + } + val effectiveFragment = + when { + url.encodedFragment != null -> "#" + url.encodedFragment + else -> "" + } + val effectiveHost = + when { + url.host.contains(":") -> "[" + url.host + "]" + else -> url.host + } assertThat(url.scheme, "scheme").isEqualTo(testData.scheme) assertThat(effectiveHost, "host").isEqualTo(testData.host) assertThat(effectivePort, "port").isEqualTo(testData.port) @@ -104,22 +109,24 @@ class WebPlatformUrlTest { companion object { private val HTTP_URL_SCHEMES = listOf("http", "https") - private val KNOWN_FAILURES = listOf( - "Parsing: against ", - "Parsing: against ", - "Parsing: against ", - "Parsing: against ", - "Parsing: against ", - "Parsing: against ", - "Parsing: against ", - "Parsing: against ", - "Parsing: against " - ) + private val KNOWN_FAILURES = + listOf( + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + "Parsing: against ", + ) private fun loadTests(): List { - val resourceAsStream = WebPlatformUrlTest::class.java.getResourceAsStream( - "/web-platform-test-urltestdata.txt" - ) + val resourceAsStream = + WebPlatformUrlTest::class.java.getResourceAsStream( + "/web-platform-test-urltestdata.txt", + ) val source = resourceAsStream.source().buffer() return WebPlatformUrlTestData.load(source) } diff --git a/okhttp/src/test/java/okhttp3/WebPlatformUrlTestData.kt b/okhttp/src/test/java/okhttp3/WebPlatformUrlTestData.kt index 47d72651cb7f..b7dbb007519b 100644 --- a/okhttp/src/test/java/okhttp3/WebPlatformUrlTestData.kt +++ b/okhttp/src/test/java/okhttp3/WebPlatformUrlTestData.kt @@ -45,7 +45,10 @@ class WebPlatformUrlTestData { fun expectParseFailure() = scheme.isEmpty() - private operator fun set(name: String, value: String) { + private operator fun set( + name: String, + value: String, + ) { when (name) { "s" -> scheme = value "u" -> username = value @@ -75,10 +78,11 @@ class WebPlatformUrlTestData { element.input = unescape(parts[i++]) val base = if (i < parts.size) parts[i++] else null - element.base = when { - base == null || base.isEmpty() -> list[list.size - 1].base - else -> unescape(base) - } + element.base = + when { + base == null || base.isEmpty() -> list[list.size - 1].base + else -> unescape(base) + } while (i < parts.size) { val piece = parts[i] diff --git a/okhttp/src/test/java/okhttp3/WholeOperationTimeoutTest.kt b/okhttp/src/test/java/okhttp3/WholeOperationTimeoutTest.kt index 8e72232c818e..fce39aefc2fe 100644 --- a/okhttp/src/test/java/okhttp3/WholeOperationTimeoutTest.kt +++ b/okhttp/src/test/java/okhttp3/WholeOperationTimeoutTest.kt @@ -56,21 +56,24 @@ class WholeOperationTimeoutTest { @Test fun defaultConfigIsNoTimeout() { - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) assertThat(call.timeout().timeoutNanos()).isEqualTo(0) } @Test fun configureClientDefault() { - val request = Request.Builder() - .url(server.url("/")) - .build() - val timeoutClient = client.newBuilder() - .callTimeout(Duration.ofMillis(456)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() + val timeoutClient = + client.newBuilder() + .callTimeout(Duration.ofMillis(456)) + .build() val call = timeoutClient.newCall(request) assertThat(call.timeout().timeoutNanos()) .isEqualTo(TimeUnit.MILLISECONDS.toNanos(456)) @@ -79,10 +82,11 @@ class WholeOperationTimeoutTest { @Test fun timeoutWritingRequest() { server.enqueue(MockResponse()) - val request = Request.Builder() - .url(server.url("/")) - .post(sleepingRequestBody(500)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(sleepingRequestBody(500)) + .build() val call = client.newCall(request) call.timeout().timeout(250, TimeUnit.MILLISECONDS) assertFailsWith { @@ -96,26 +100,35 @@ class WholeOperationTimeoutTest { @Test fun timeoutWritingRequestWithEnqueue() { server.enqueue(MockResponse()) - val request = Request.Builder() - .url(server.url("/")) - .post(sleepingRequestBody(500)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(sleepingRequestBody(500)) + .build() val latch = CountDownLatch(1) val exceptionRef = AtomicReference() val call = client.newCall(request) call.timeout().timeout(250, TimeUnit.MILLISECONDS) - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - exceptionRef.set(e) - latch.countDown() - } + call.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + exceptionRef.set(e) + latch.countDown() + } - @Throws(IOException::class) - override fun onResponse(call: Call, response: Response) { - response.close() - latch.countDown() - } - }) + @Throws(IOException::class) + override fun onResponse( + call: Call, + response: Response, + ) { + response.close() + latch.countDown() + } + }, + ) latch.await() assertThat(call.isCanceled()).isTrue() assertThat(exceptionRef.get()).isNotNull() @@ -126,11 +139,12 @@ class WholeOperationTimeoutTest { server.enqueue( MockResponse.Builder() .headersDelay(500, TimeUnit.MILLISECONDS) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) call.timeout().timeout(250, TimeUnit.MILLISECONDS) assertFailsWith { @@ -146,27 +160,36 @@ class WholeOperationTimeoutTest { server.enqueue( MockResponse.Builder() .headersDelay(500, TimeUnit.MILLISECONDS) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val latch = CountDownLatch(1) val exceptionRef = AtomicReference() val call = client.newCall(request) call.timeout().timeout(250, TimeUnit.MILLISECONDS) - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - exceptionRef.set(e) - latch.countDown() - } + call.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + exceptionRef.set(e) + latch.countDown() + } - @Throws(IOException::class) - override fun onResponse(call: Call, response: Response) { - response.close() - latch.countDown() - } - }) + @Throws(IOException::class) + override fun onResponse( + call: Call, + response: Response, + ) { + response.close() + latch.countDown() + } + }, + ) latch.await() assertThat(call.isCanceled()).isTrue() assertThat(exceptionRef.get()).isNotNull() @@ -177,11 +200,12 @@ class WholeOperationTimeoutTest { server.enqueue( MockResponse.Builder() .body(BIG_ENOUGH_BODY) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) call.timeout().timeout(250, TimeUnit.MILLISECONDS) val response = call.execute() @@ -199,35 +223,44 @@ class WholeOperationTimeoutTest { server.enqueue( MockResponse.Builder() .body(BIG_ENOUGH_BODY) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val latch = CountDownLatch(1) val exceptionRef = AtomicReference() val call = client.newCall(request) call.timeout().timeout(250, TimeUnit.MILLISECONDS) - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - latch.countDown() - } - - @Throws(IOException::class) - override fun onResponse(call: Call, response: Response) { - try { - Thread.sleep(500) - } catch (e: InterruptedException) { - throw AssertionError() - } - assertFailsWith { - response.body.source().readUtf8() - }.also { expected -> - exceptionRef.set(expected) + call.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { latch.countDown() } - } - }) + + @Throws(IOException::class) + override fun onResponse( + call: Call, + response: Response, + ) { + try { + Thread.sleep(500) + } catch (e: InterruptedException) { + throw AssertionError() + } + assertFailsWith { + response.body.source().readUtf8() + }.also { expected -> + exceptionRef.set(expected) + latch.countDown() + } + } + }, + ) latch.await() assertThat(call.isCanceled()).isTrue() assertThat(exceptionRef.get()).isNotNull() @@ -240,40 +273,41 @@ class WholeOperationTimeoutTest { .code(HttpURLConnection.HTTP_MOVED_TEMP) .setHeader("Location", "/b") .headersDelay(100, TimeUnit.MILLISECONDS) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .setHeader("Location", "/c") .headersDelay(100, TimeUnit.MILLISECONDS) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .setHeader("Location", "/d") .headersDelay(100, TimeUnit.MILLISECONDS) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .setHeader("Location", "/e") .headersDelay(100, TimeUnit.MILLISECONDS) - .build() + .build(), ) server.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .setHeader("Location", "/f") .headersDelay(100, TimeUnit.MILLISECONDS) - .build() + .build(), ) server.enqueue(MockResponse()) - val request = Request.Builder() - .url(server.url("/a")) - .build() + val request = + Request.Builder() + .url(server.url("/a")) + .build() val call = client.newCall(request) call.timeout().timeout(250, TimeUnit.MILLISECONDS) assertFailsWith { @@ -291,12 +325,12 @@ class WholeOperationTimeoutTest { MockResponse.Builder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .setHeader("Location", otherServer.url("/")) - .build() + .build(), ) otherServer.enqueue( MockResponse.Builder() .headersDelay(500, TimeUnit.MILLISECONDS) - .build() + .build(), ) val request = Request.Builder().url(server.url("/")).build() val call = client.newCall(request) @@ -317,12 +351,13 @@ class WholeOperationTimeoutTest { MockResponse.Builder() .headersDelay(250, TimeUnit.MILLISECONDS) .body(BIG_ENOUGH_BODY) - .build() + .build(), ) - val request = Request.Builder() - .url(server.url("/")) - .post(sleepingRequestBody(250)) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .post(sleepingRequestBody(250)) + .build() val call = client.newCall(request) call.timeout().timeout(2000, TimeUnit.MILLISECONDS) val response = call.execute() diff --git a/okhttp/src/test/java/okhttp3/internal/HostnamesTest.kt b/okhttp/src/test/java/okhttp3/internal/HostnamesTest.kt index 1ec31a0528c6..ba4be116f889 100644 --- a/okhttp/src/test/java/okhttp3/internal/HostnamesTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/HostnamesTest.kt @@ -57,31 +57,42 @@ class HostnamesTest { @Test fun inet4AddressToAscii() { - assertThat(inet4AddressToAscii( - byteArrayOf(0, 0, 0, 0) - )).isEqualTo("0.0.0.0") - - assertThat(inet4AddressToAscii( - byteArrayOf(1, 2, 3, 4) - )).isEqualTo("1.2.3.4") - - assertThat(inet4AddressToAscii( - byteArrayOf(127, 0, 0, 1) - )).isEqualTo("127.0.0.1") - - assertThat(inet4AddressToAscii( - byteArrayOf(192.toByte(), 168.toByte(), 0, 1) - )).isEqualTo("192.168.0.1") - - assertThat(inet4AddressToAscii( - byteArrayOf(252.toByte(), 253.toByte(), 254.toByte(), 255.toByte()) - )).isEqualTo("252.253.254.255") - - assertThat(inet4AddressToAscii( - byteArrayOf(255.toByte(), 255.toByte(), 255.toByte(), 255.toByte()) - )).isEqualTo("255.255.255.255") + assertThat( + inet4AddressToAscii( + byteArrayOf(0, 0, 0, 0), + ), + ).isEqualTo("0.0.0.0") + + assertThat( + inet4AddressToAscii( + byteArrayOf(1, 2, 3, 4), + ), + ).isEqualTo("1.2.3.4") + + assertThat( + inet4AddressToAscii( + byteArrayOf(127, 0, 0, 1), + ), + ).isEqualTo("127.0.0.1") + + assertThat( + inet4AddressToAscii( + byteArrayOf(192.toByte(), 168.toByte(), 0, 1), + ), + ).isEqualTo("192.168.0.1") + + assertThat( + inet4AddressToAscii( + byteArrayOf(252.toByte(), 253.toByte(), 254.toByte(), 255.toByte()), + ), + ).isEqualTo("252.253.254.255") + + assertThat( + inet4AddressToAscii( + byteArrayOf(255.toByte(), 255.toByte(), 255.toByte(), 255.toByte()), + ), + ).isEqualTo("255.255.255.255") } - private fun decodeIpv6(input: String): ByteArray? = - decodeIpv6(input, 0, input.length) + private fun decodeIpv6(input: String): ByteArray? = decodeIpv6(input, 0, input.length) } diff --git a/okhttp/src/test/java/okhttp3/internal/RecordingAuthenticator.kt b/okhttp/src/test/java/okhttp3/internal/RecordingAuthenticator.kt index e13ec5beca39..0a26077cfce5 100644 --- a/okhttp/src/test/java/okhttp3/internal/RecordingAuthenticator.kt +++ b/okhttp/src/test/java/okhttp3/internal/RecordingAuthenticator.kt @@ -19,17 +19,19 @@ import java.net.Authenticator import java.net.PasswordAuthentication class RecordingAuthenticator( - private val authentication: PasswordAuthentication? = PasswordAuthentication( - "username", - "password".toCharArray() - ) + private val authentication: PasswordAuthentication? = + PasswordAuthentication( + "username", + "password".toCharArray(), + ), ) : Authenticator() { val calls = mutableListOf() override fun getPasswordAuthentication(): PasswordAuthentication? { - calls.add("host=$requestingHost port=$requestingPort site=${requestingSite.hostName} " + - "url=$requestingURL type=$requestorType prompt=$requestingPrompt " + - "protocol=$requestingProtocol scheme=$requestingScheme" + calls.add( + "host=$requestingHost port=$requestingPort site=${requestingSite.hostName} " + + "url=$requestingURL type=$requestorType prompt=$requestingPrompt " + + "protocol=$requestingProtocol scheme=$requestingScheme", ) return authentication } diff --git a/okhttp/src/test/java/okhttp3/internal/UtilTest.kt b/okhttp/src/test/java/okhttp3/internal/UtilTest.kt index 8c1c41e27088..8c4d7b56b8eb 100644 --- a/okhttp/src/test/java/okhttp3/internal/UtilTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/UtilTest.kt @@ -32,57 +32,69 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows class UtilTest { - @Test - fun socketIsHealthy() { - val localhost = InetAddress.getLoopbackAddress() - val serverSocket = ServerSocket(0, 1, localhost) + @Test + fun socketIsHealthy() { + val localhost = InetAddress.getLoopbackAddress() + val serverSocket = ServerSocket(0, 1, localhost) - val socket = Socket() - socket.connect(serverSocket.localSocketAddress) - val socketSource = socket.source().buffer() + val socket = Socket() + socket.connect(serverSocket.localSocketAddress) + val socketSource = socket.source().buffer() - assertThat(socket.isHealthy(socketSource)).isTrue() + assertThat(socket.isHealthy(socketSource)).isTrue() - serverSocket.close() - assertThat(socket.isHealthy(socketSource)).isFalse() - } + serverSocket.close() + assertThat(socket.isHealthy(socketSource)).isFalse() + } - @Test - fun testDurationTimeUnit() { - assertThat(checkDuration("timeout", 0, TimeUnit.MILLISECONDS)).isEqualTo(0) - assertThat(checkDuration("timeout", 1, TimeUnit.MILLISECONDS)).isEqualTo(1) + @Test + fun testDurationTimeUnit() { + assertThat(checkDuration("timeout", 0, TimeUnit.MILLISECONDS)).isEqualTo(0) + assertThat(checkDuration("timeout", 1, TimeUnit.MILLISECONDS)).isEqualTo(1) - assertThat(assertThrows { - checkDuration("timeout", -1, TimeUnit.MILLISECONDS) - }).hasMessage("timeout < 0") - assertThat(assertThrows { - checkDuration("timeout", 1, TimeUnit.NANOSECONDS) - }).hasMessage("timeout too small") - assertThat(assertThrows { - checkDuration( - "timeout", - 1L + Int.MAX_VALUE.toLong(), - TimeUnit.MILLISECONDS - ) - }).hasMessage("timeout too large") - } + assertThat( + assertThrows { + checkDuration("timeout", -1, TimeUnit.MILLISECONDS) + }, + ).hasMessage("timeout < 0") + assertThat( + assertThrows { + checkDuration("timeout", 1, TimeUnit.NANOSECONDS) + }, + ).hasMessage("timeout too small") + assertThat( + assertThrows { + checkDuration( + "timeout", + 1L + Int.MAX_VALUE.toLong(), + TimeUnit.MILLISECONDS, + ) + }, + ).hasMessage("timeout too large") + } - @Test - fun testDurationDuration() { - assertThat(checkDuration("timeout", 0.milliseconds)).isEqualTo(0) - assertThat(checkDuration("timeout", 1.milliseconds)).isEqualTo(1) + @Test + fun testDurationDuration() { + assertThat(checkDuration("timeout", 0.milliseconds)).isEqualTo(0) + assertThat(checkDuration("timeout", 1.milliseconds)).isEqualTo(1) - assertThat(assertThrows { - checkDuration("timeout", (-1).milliseconds) - }).hasMessage("timeout < 0") - assertThat(assertThrows { - checkDuration("timeout", 1.nanoseconds) - }).hasMessage("timeout too small") - assertThat(assertThrows { - checkDuration( - "timeout", - (1L + Int.MAX_VALUE).milliseconds - ) - }).hasMessage("timeout too large") - } + assertThat( + assertThrows { + checkDuration("timeout", (-1).milliseconds) + }, + ).hasMessage("timeout < 0") + assertThat( + assertThrows { + checkDuration("timeout", 1.nanoseconds) + }, + ).hasMessage("timeout too small") + assertThat( + assertThrows { + checkDuration( + "timeout", + (1L + Int.MAX_VALUE).milliseconds, + ) + }, + ).hasMessage("timeout too large") + } } diff --git a/okhttp/src/test/java/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt b/okhttp/src/test/java/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt index 92ecfea29e8b..6fdeceba4b19 100644 --- a/okhttp/src/test/java/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt @@ -34,10 +34,11 @@ class JavaNetAuthenticatorTest { private var authenticator = JavaNetAuthenticator() private val fakeDns = FakeDns() private val recordingAuthenticator = RecordingAuthenticator() - private val factory = TestValueFactory() - .apply { - dns = fakeDns - } + private val factory = + TestValueFactory() + .apply { + dns = fakeDns + } @BeforeEach fun setup() { @@ -56,10 +57,12 @@ class JavaNetAuthenticatorTest { val route = factory.newRoute() - val request = Request.Builder() + val request = + Request.Builder() .url("https://server/robots.txt") .build() - val response = Response.Builder() + val response = + Response.Builder() .request(request) .code(401) .header("WWW-Authenticate", "Basic realm=\"User Visible Realm\"") @@ -69,17 +72,20 @@ class JavaNetAuthenticatorTest { val authRequest = authenticator.authenticate(route, response) assertEquals( - "Basic ${RecordingAuthenticator.BASE_64_CREDENTIALS}", authRequest!!.header("Authorization") + "Basic ${RecordingAuthenticator.BASE_64_CREDENTIALS}", + authRequest!!.header("Authorization"), ) } @Test fun noSupportForNonBasicAuth() { - val request = Request.Builder() + val request = + Request.Builder() .url("https://server/robots.txt") .build() - val response = Response.Builder() + val response = + Response.Builder() .request(request) .code(401) .header("WWW-Authenticate", "UnsupportedScheme realm=\"User Visible Realm\"") diff --git a/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt b/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt index 2ee326caf488..2a0d537b8129 100644 --- a/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt @@ -21,10 +21,12 @@ import assertk.assertions.isFalse import assertk.assertions.isNull import assertk.assertions.isSameAs import assertk.assertions.isTrue +import assertk.fail import java.io.File import java.io.FileNotFoundException import java.io.IOException import java.util.ArrayDeque +import kotlin.test.assertFailsWith import okhttp3.SimpleProvider import okhttp3.TestUtil import okhttp3.internal.cache.DiskLruCache.Editor @@ -41,18 +43,17 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assumptions import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Timeout -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.io.TempDir import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ArgumentsSource -class FileSystemParamProvider: SimpleProvider() { - override fun arguments() = listOf( - FakeFileSystem().apply { emulateUnix() } to false, - FileSystem.SYSTEM to TestUtil.windows, - FakeFileSystem().apply { emulateWindows() } to true - ) +class FileSystemParamProvider : SimpleProvider() { + override fun arguments() = + listOf( + FakeFileSystem().apply { emulateUnix() } to false, + FileSystem.SYSTEM to TestUtil.windows, + FakeFileSystem().apply { emulateWindows() } to true, + ) } @Timeout(60) @@ -60,6 +61,7 @@ class FileSystemParamProvider: SimpleProvider() { class DiskLruCacheTest { private lateinit var filesystem: FaultyFileSystem private var windows: Boolean = false + @TempDir lateinit var cacheDirFile: File lateinit var cacheDir: Path private val appVersion = 100 @@ -75,13 +77,17 @@ class DiskLruCacheTest { } private fun createNewCacheWithSize(maxSize: Int) { - cache = DiskLruCache(filesystem, cacheDir, appVersion, 2, maxSize.toLong(), taskRunner).also { - toClose.add(it) - } + cache = + DiskLruCache(filesystem, cacheDir, appVersion, 2, maxSize.toLong(), taskRunner).also { + toClose.add(it) + } synchronized(cache) { cache.initialize() } } - fun setUp(baseFilesystem: FileSystem, windows: Boolean) { + fun setUp( + baseFilesystem: FileSystem, + windows: Boolean, + ) { this.cacheDir = if (baseFilesystem is FakeFileSystem) "/cache".toPath() else cacheDirFile.path.toPath() this.filesystem = FaultyFileSystem(baseFilesystem) @@ -127,9 +133,10 @@ class DiskLruCacheTest { // Simulate a severe Filesystem failure on the first initialization. filesystem.setFaultyDelete(cacheDir / "k1.0.tmp", true) filesystem.setFaultyDelete(cacheDir, true) - cache = DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { - toClose.add(it) - } + cache = + DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { + toClose.add(it) + } assertFailsWith { cache["k1"] } @@ -177,8 +184,10 @@ class DiskLruCacheTest { assertThat(expected.message).isEqualTo("keys must match regex [a-z0-9_-]{1,120}: \"$key\"") } assertFailsWith { - key = ("this_is_way_too_long_this_is_way_too_long_this_is_way_too_long_" + - "this_is_way_too_long_this_is_way_too_long_this_is_way_too_long") + key = ( + "this_is_way_too_long_this_is_way_too_long_this_is_way_too_long_" + + "this_is_way_too_long_this_is_way_too_long_this_is_way_too_long" + ) cache.edit(key) }.also { expected -> assertThat(expected.message).isEqualTo("keys must match regex [a-z0-9_-]{1,120}: \"$key\"") @@ -187,8 +196,10 @@ class DiskLruCacheTest { // Test valid cases. // Exactly 120. - key = ("0123456789012345678901234567890123456789012345678901234567890123456789" + - "01234567890123456789012345678901234567890123456789") + key = ( + "0123456789012345678901234567890123456789012345678901234567890123456789" + + "01234567890123456789012345678901234567890123456789" + ) cache.edit(key)!!.abort() // Contains all valid characters. key = "abcdefghijklmnopqrstuvwxyz_0123456789" @@ -509,7 +520,8 @@ class DiskLruCacheTest { |100 |2 | - |CLEAN k1 1 1""".trimMargin() + |CLEAN k1 1 1 + """.trimMargin(), ) } createNewCache() @@ -1057,7 +1069,8 @@ class DiskLruCacheTest { // Cause the rebuild action to fail. filesystem.setFaultyRename( - cacheDir / DiskLruCache.JOURNAL_FILE_BACKUP, true + cacheDir / DiskLruCache.JOURNAL_FILE_BACKUP, + true, ) taskFaker.runNextTask() @@ -1121,9 +1134,10 @@ class DiskLruCacheTest { setUp(parameters.first, parameters.second) cache.close() val dir = (cacheDir / "testOpenCreatesDirectoryIfNecessary").also { filesystem.createDirectories(it) } - cache = DiskLruCache(filesystem, dir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { - toClose.add(it) - } + cache = + DiskLruCache(filesystem, dir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { + toClose.add(it) + } set("a", "a", "a") assertThat(filesystem.exists(dir / "a.0")).isTrue() assertThat(filesystem.exists(dir / "a.1")).isTrue() @@ -1514,9 +1528,10 @@ class DiskLruCacheTest { fun isClosed_uninitializedCache(parameters: Pair) { setUp(parameters.first, parameters.second) // Create an uninitialized cache. - cache = DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { - toClose.add(it) - } + cache = + DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { + toClose.add(it) + } assertThat(cache.isClosed()).isFalse() cache.close() assertThat(cache.isClosed()).isTrue() @@ -1539,9 +1554,10 @@ class DiskLruCacheTest { // Confirm that the fault didn't corrupt entries stored before the fault was introduced. cache.close() - cache = DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { - toClose.add(it) - } + cache = + DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { + toClose.add(it) + } assertValue("a", "a", "a") assertValue("b", "b", "b") assertAbsent("c") @@ -1572,9 +1588,10 @@ class DiskLruCacheTest { // Confirm that the fault didn't corrupt entries stored before the fault was introduced. cache.close() - cache = DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { - toClose.add(it) - } + cache = + DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { + toClose.add(it) + } assertValue("a", "a", "a") assertValue("b", "b", "b") assertAbsent("c") @@ -1601,9 +1618,10 @@ class DiskLruCacheTest { // Confirm that the fault didn't corrupt entries stored before the fault was introduced. cache.close() - cache = DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { - toClose.add(it) - } + cache = + DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { + toClose.add(it) + } assertValue("a", "a", "a") assertValue("b", "b", "b") assertAbsent("c") @@ -1624,9 +1642,10 @@ class DiskLruCacheTest { // Confirm that the entry was still removed. filesystem.setFaultyWrite(journalFile, false) cache.close() - cache = DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { - toClose.add(it) - } + cache = + DiskLruCache(filesystem, cacheDir, appVersion, 2, Int.MAX_VALUE.toLong(), taskRunner).also { + toClose.add(it) + } assertAbsent("a") assertValue("b", "b", "b") } @@ -2163,14 +2182,18 @@ class DiskLruCacheTest { private fun assertJournalEquals(vararg expectedBodyLines: String) { assertThat(readJournalLines()).isEqualTo( - listOf(DiskLruCache.MAGIC, DiskLruCache.VERSION_1, "100", "2", "") + expectedBodyLines + listOf(DiskLruCache.MAGIC, DiskLruCache.VERSION_1, "100", "2", "") + expectedBodyLines, ) } private fun createJournal(vararg bodyLines: String) { createJournalWithHeader( DiskLruCache.MAGIC, - DiskLruCache.VERSION_1, "100", "2", "", *bodyLines + DiskLruCache.VERSION_1, + "100", + "2", + "", + *bodyLines, ) } @@ -2180,7 +2203,7 @@ class DiskLruCacheTest { appVersion: String, valueCount: String, blank: String, - vararg bodyLines: String + vararg bodyLines: String, ) { filesystem.write(journalFile) { writeUtf8( @@ -2190,7 +2213,8 @@ class DiskLruCacheTest { |$appVersion |$valueCount |$blank - |""".trimMargin() + | + """.trimMargin(), ) for (line in bodyLines) { writeUtf8(line) @@ -2210,9 +2234,15 @@ class DiskLruCacheTest { return result } - private fun getCleanFile(key: String, index: Int) = cacheDir / "$key.$index" + private fun getCleanFile( + key: String, + index: Int, + ) = cacheDir / "$key.$index" - private fun getDirtyFile(key: String, index: Int) = cacheDir / "$key.$index.tmp" + private fun getDirtyFile( + key: String, + index: Int, + ) = cacheDir / "$key.$index.tmp" private fun readFile(file: Path): String { return filesystem.read(file) { @@ -2230,7 +2260,10 @@ class DiskLruCacheTest { } } - fun writeFile(file: Path, content: String) { + fun writeFile( + file: Path, + content: String, + ) { file.parent?.let { filesystem.createDirectories(it) } @@ -2260,7 +2293,11 @@ class DiskLruCacheTest { assertThat(filesystem.exists(cacheDir / "dir1")).isFalse() } - private operator fun set(key: String, value0: String, value1: String) { + private operator fun set( + key: String, + value0: String, + value1: String, + ) { val editor = cache.edit(key)!! editor.setString(0, value0) editor.setString(1, value1) @@ -2279,7 +2316,11 @@ class DiskLruCacheTest { assertThat(filesystem.exists(getDirtyFile(key, 1))).isFalse() } - private fun assertValue(key: String, value0: String, value1: String) { + private fun assertValue( + key: String, + value0: String, + value1: String, + ) { cache[key]!!.use { it.assertValue(0, value0) it.assertValue(1, value1) @@ -2288,7 +2329,10 @@ class DiskLruCacheTest { } } - private fun Snapshot.assertValue(index: Int, value: String) { + private fun Snapshot.assertValue( + index: Int, + value: String, + ) { getSource(index).use { source -> assertThat(sourceAsString(source)).isEqualTo(value) assertThat(getLength(index)).isEqualTo(value.length.toLong()) @@ -2315,7 +2359,10 @@ class DiskLruCacheTest { } } - private fun Editor.setString(index: Int, value: String) { + private fun Editor.setString( + index: Int, + value: String, + ) { newSink(index).buffer().use { writer -> writer.writeUtf8(value) } diff --git a/okhttp/src/test/java/okhttp3/internal/cache2/FileOperatorTest.kt b/okhttp/src/test/java/okhttp3/internal/cache2/FileOperatorTest.kt index 32eceb4c3517..ef18c3b155d4 100644 --- a/okhttp/src/test/java/okhttp3/internal/cache2/FileOperatorTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/cache2/FileOperatorTest.kt @@ -20,6 +20,7 @@ import assertk.assertions.isEqualTo import java.io.File import java.io.RandomAccessFile import java.util.Random +import kotlin.test.assertFailsWith import okio.Buffer import okio.ByteString import okio.ByteString.Companion.encodeUtf8 @@ -27,8 +28,6 @@ import okio.buffer import okio.sink import okio.source import org.junit.jupiter.api.AfterEach -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.io.TempDir @@ -53,9 +52,10 @@ class FileOperatorTest { @Test fun read() { write("Hello, World".encodeUtf8()) - val operator = FileOperator( - randomAccessFile!!.getChannel() - ) + val operator = + FileOperator( + randomAccessFile!!.getChannel(), + ) val buffer = Buffer() operator.read(0, buffer, 5) assertThat(buffer.readUtf8()).isEqualTo("Hello") @@ -65,9 +65,10 @@ class FileOperatorTest { @Test fun write() { - val operator = FileOperator( - randomAccessFile!!.getChannel() - ) + val operator = + FileOperator( + randomAccessFile!!.getChannel(), + ) val buffer1 = Buffer().writeUtf8("Hello, World") operator.write(0, buffer1, 5) assertThat(buffer1.readUtf8()).isEqualTo(", World") @@ -79,9 +80,10 @@ class FileOperatorTest { @Test fun readAndWrite() { - val operator = FileOperator( - randomAccessFile!!.getChannel() - ) + val operator = + FileOperator( + randomAccessFile!!.getChannel(), + ) write("woman god creates dinosaurs destroys. ".encodeUtf8()) val buffer = Buffer() operator.read(6, buffer, 21) @@ -103,24 +105,27 @@ class FileOperatorTest { operator.read(4, buffer, 19) operator.write(80, buffer, buffer.size) assertThat(snapshot()).isEqualTo( - ("" - + "god creates dinosaurs. " - + "god destroys dinosaurs. " - + "god creates man. " - + "man destroys god. " - + "man creates dinosaurs. " - ).encodeUtf8() + ( + "" + + "god creates dinosaurs. " + + "god destroys dinosaurs. " + + "god creates man. " + + "man destroys god. " + + "man creates dinosaurs. " + ).encodeUtf8(), ) } @Test fun multipleOperatorsShareOneFile() { - val operatorA = FileOperator( - randomAccessFile!!.getChannel() - ) - val operatorB = FileOperator( - randomAccessFile!!.getChannel() - ) + val operatorA = + FileOperator( + randomAccessFile!!.getChannel(), + ) + val operatorB = + FileOperator( + randomAccessFile!!.getChannel(), + ) val bufferA = Buffer() val bufferB = Buffer() bufferA.writeUtf8("Dodgson!\n") @@ -141,9 +146,10 @@ class FileOperatorTest { fun largeRead() { val data = randomByteString(1000000) write(data) - val operator = FileOperator( - randomAccessFile!!.getChannel() - ) + val operator = + FileOperator( + randomAccessFile!!.getChannel(), + ) val buffer = Buffer() operator.read(0, buffer, data.size.toLong()) assertThat(buffer.readByteString()).isEqualTo(data) @@ -152,9 +158,10 @@ class FileOperatorTest { @Test fun largeWrite() { val data = randomByteString(1000000) - val operator = FileOperator( - randomAccessFile!!.getChannel() - ) + val operator = + FileOperator( + randomAccessFile!!.getChannel(), + ) val buffer = Buffer().write(data) operator.write(0, buffer, data.size.toLong()) assertThat(snapshot()).isEqualTo(data) @@ -162,9 +169,10 @@ class FileOperatorTest { @Test fun readBounds() { - val operator = FileOperator( - randomAccessFile!!.getChannel() - ) + val operator = + FileOperator( + randomAccessFile!!.getChannel(), + ) val buffer = Buffer() assertFailsWith { operator.read(0, buffer, -1L) @@ -173,9 +181,10 @@ class FileOperatorTest { @Test fun writeBounds() { - val operator = FileOperator( - randomAccessFile!!.getChannel() - ) + val operator = + FileOperator( + randomAccessFile!!.getChannel(), + ) val buffer = Buffer().writeUtf8("abc") assertFailsWith { operator.write(0, buffer, -1L) diff --git a/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt b/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt index 38c533916fba..597b6c43832c 100644 --- a/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt @@ -219,8 +219,11 @@ class RelayTest { } private fun assertFile( - prefix: ByteString, upstreamSize: Long, metadataSize: Int, upstream: String?, - metadata: ByteString? + prefix: ByteString, + upstreamSize: Long, + metadataSize: Int, + upstream: String?, + metadata: ByteString?, ) { val source = file.source().buffer() assertThat(source.readByteString(prefix.size.toLong())).isEqualTo(prefix) diff --git a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskLoggerTest.kt b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskLoggerTest.kt index 0f6a00331353..8fe384b3a472 100644 --- a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskLoggerTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskLoggerTest.kt @@ -20,8 +20,8 @@ import assertk.assertions.isEqualTo import org.junit.jupiter.api.Test class TaskLoggerTest { + @Suppress("ktlint") @Test fun formatTime() { - /* ktlint-disable */ assertThat(formatDuration(-3_499_999_999L)).isEqualTo(" -3 s ") assertThat(formatDuration(-3_000_000_000L)).isEqualTo(" -3 s ") assertThat(formatDuration(-2_500_000_000L)).isEqualTo(" -3 s ") @@ -65,6 +65,5 @@ class TaskLoggerTest { assertThat(formatDuration( 999L)).isEqualTo(" 1 µs") assertThat(formatDuration( 500L)).isEqualTo(" 1 µs") assertThat(formatDuration( 499L)).isEqualTo(" 0 µs") - /* ktlint-enable */ } } diff --git a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt index aa1c38f78fa7..562c2691ad40 100644 --- a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt @@ -39,16 +39,18 @@ import org.junit.jupiter.api.Test class TaskRunnerRealBackendTest { private val log = LinkedBlockingDeque() - private val loggingUncaughtExceptionHandler = UncaughtExceptionHandler { _, throwable -> - log.put("uncaught exception: $throwable") - } + private val loggingUncaughtExceptionHandler = + UncaughtExceptionHandler { _, throwable -> + log.put("uncaught exception: $throwable") + } - private val threadFactory = ThreadFactory { runnable -> - Thread(runnable, "TaskRunnerRealBackendTest").apply { - isDaemon = true - uncaughtExceptionHandler = loggingUncaughtExceptionHandler + private val threadFactory = + ThreadFactory { runnable -> + Thread(runnable, "TaskRunnerRealBackendTest").apply { + isDaemon = true + uncaughtExceptionHandler = loggingUncaughtExceptionHandler + } } - } private val backend = TaskRunner.RealBackend(threadFactory) private val taskRunner = TaskRunner(backend) diff --git a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt index 4c42dd707d37..5f343b5632c7 100644 --- a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt @@ -22,17 +22,17 @@ import assertk.assertions.isEmpty import assertk.assertions.isEqualTo import assertk.assertions.isSameAs import java.util.concurrent.RejectedExecutionException +import kotlin.test.assertFailsWith import okhttp3.TestLogHandler import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension -import assertk.fail -import kotlin.test.assertFailsWith class TaskRunnerTest { private val taskFaker = TaskFaker() - @RegisterExtension @JvmField val testLogHandler = TestLogHandler(taskFaker.logger) + @RegisterExtension @JvmField + val testLogHandler = TestLogHandler(taskFaker.logger) private val taskRunner = taskFaker.taskRunner private val log = mutableListOf() @@ -62,9 +62,9 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } @@ -93,31 +93,33 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 run again after 50 µs: task", - "FINE: Q10000 finished run in 0 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 run again after 150 µs: task", - "FINE: Q10000 finished run in 0 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 run again after 50 µs: task", + "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 run again after 150 µs: task", + "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } /** Repeat with a delay of 200 but schedule with a delay of 50. The schedule wins. */ @Test fun executeScheduledEarlierReplacesRepeatedLater() { - val task = object : Task("task") { - val schedules = mutableListOf(50.µs) - val delays = mutableListOf(200.µs, -1) - override fun runOnce(): Long { - log += "run@${taskFaker.nanoTime}" - if (schedules.isNotEmpty()) { - redQueue.schedule(this, schedules.removeAt(0)) + val task = + object : Task("task") { + val schedules = mutableListOf(50.µs) + val delays = mutableListOf(200.µs, -1) + + override fun runOnce(): Long { + log += "run@${taskFaker.nanoTime}" + if (schedules.isNotEmpty()) { + redQueue.schedule(this, schedules.removeAt(0)) + } + return delays.removeAt(0) } - return delays.removeAt(0) } - } redQueue.schedule(task, 100.µs) taskFaker.advanceUntil(0.µs) @@ -132,29 +134,31 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 scheduled after 50 µs: task", - "FINE: Q10000 already scheduled : task", - "FINE: Q10000 finished run in 0 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 scheduled after 50 µs: task", + "FINE: Q10000 already scheduled : task", + "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } /** Schedule with a delay of 200 but repeat with a delay of 50. The repeat wins. */ @Test fun executeRepeatedEarlierReplacesScheduledLater() { - val task = object : Task("task") { - val schedules = mutableListOf(200.µs) - val delays = mutableListOf(50.µs, -1L) - override fun runOnce(): Long { - log += "run@${taskFaker.nanoTime}" - if (schedules.isNotEmpty()) { - redQueue.schedule(this, schedules.removeAt(0)) + val task = + object : Task("task") { + val schedules = mutableListOf(200.µs) + val delays = mutableListOf(50.µs, -1L) + + override fun runOnce(): Long { + log += "run@${taskFaker.nanoTime}" + if (schedules.isNotEmpty()) { + redQueue.schedule(this, schedules.removeAt(0)) + } + return delays.removeAt(0) } - return delays.removeAt(0) } - } redQueue.schedule(task, 100.µs) taskFaker.advanceUntil(0.µs) @@ -169,13 +173,13 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 scheduled after 200 µs: task", - "FINE: Q10000 run again after 50 µs: task", - "FINE: Q10000 finished run in 0 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 scheduled after 200 µs: task", + "FINE: Q10000 run again after 50 µs: task", + "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } @@ -195,18 +199,21 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 canceled : task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 canceled : task", ) } @Test fun cancelReturnsFalseDoesNotCancel() { - redQueue.schedule(object : Task("task", cancelable = false) { - override fun runOnce(): Long { - log += "run@${taskFaker.nanoTime}" - return -1L - } - }, 100.µs) + redQueue.schedule( + object : Task("task", cancelable = false) { + override fun runOnce(): Long { + log += "run@${taskFaker.nanoTime}" + return -1L + } + }, + 100.µs, + ) taskFaker.advanceUntil(0.µs) assertThat(log).isEmpty() @@ -222,9 +229,9 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } @@ -244,9 +251,9 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } @@ -265,21 +272,25 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } @Test fun cancelWhileExecutingDoesNotStopUncancelableTask() { - redQueue.schedule(object : Task("task", cancelable = false) { - val delays = mutableListOf(50.µs, -1L) - override fun runOnce(): Long { - log += "run@${taskFaker.nanoTime}" - redQueue.cancelAll() - return delays.removeAt(0) - } - }, 100.µs) + redQueue.schedule( + object : Task("task", cancelable = false) { + val delays = mutableListOf(50.µs, -1L) + + override fun runOnce(): Long { + log += "run@${taskFaker.nanoTime}" + redQueue.cancelAll() + return delays.removeAt(0) + } + }, + 100.µs, + ) taskFaker.advanceUntil(0.µs) assertThat(log).isEmpty() @@ -293,12 +304,12 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 run again after 50 µs: task", - "FINE: Q10000 finished run in 0 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 run again after 50 µs: task", + "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } @@ -318,18 +329,21 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 canceled : task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 canceled : task", ) } @Test fun interruptingCoordinatorAttemptsToCancelsAndFails() { - redQueue.schedule(object : Task("task", cancelable = false) { - override fun runOnce(): Long { - log += "run@${taskFaker.nanoTime}" - return -1L - } - }, 100.µs) + redQueue.schedule( + object : Task("task", cancelable = false) { + override fun runOnce(): Long { + log += "run@${taskFaker.nanoTime}" + return -1L + } + }, + 100.µs, + ) taskFaker.advanceUntil(0.µs) assertThat(log).isEmpty() @@ -345,9 +359,9 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } @@ -370,23 +384,23 @@ class TaskRunnerTest { taskFaker.advanceUntil(100.µs) assertThat(log).containsExactly( - "one:run@100000 parallel=false", - "two:run@100000 parallel=false", - "three:run@100000 parallel=false" + "one:run@100000 parallel=false", + "two:run@100000 parallel=false", + "three:run@100000 parallel=false", ) taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task one", - "FINE: Q10000 scheduled after 100 µs: task two", - "FINE: Q10000 scheduled after 100 µs: task three", - "FINE: Q10000 starting : task one", - "FINE: Q10000 finished run in 0 µs: task one", - "FINE: Q10000 starting : task two", - "FINE: Q10000 finished run in 0 µs: task two", - "FINE: Q10000 starting : task three", - "FINE: Q10000 finished run in 0 µs: task three" + "FINE: Q10000 scheduled after 100 µs: task one", + "FINE: Q10000 scheduled after 100 µs: task two", + "FINE: Q10000 scheduled after 100 µs: task three", + "FINE: Q10000 starting : task one", + "FINE: Q10000 finished run in 0 µs: task one", + "FINE: Q10000 starting : task two", + "FINE: Q10000 finished run in 0 µs: task two", + "FINE: Q10000 starting : task three", + "FINE: Q10000 finished run in 0 µs: task three", ) } @@ -409,23 +423,23 @@ class TaskRunnerTest { taskFaker.advanceUntil(100.µs) assertThat(log).containsExactlyInAnyOrder( - "one:run@100000 parallel=true", - "two:run@100000 parallel=true", - "three:run@100000 parallel=true" + "one:run@100000 parallel=true", + "two:run@100000 parallel=true", + "three:run@100000 parallel=true", ) taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactlyInAnyOrder( - "FINE: Q10000 scheduled after 100 µs: task one", - "FINE: Q10001 scheduled after 100 µs: task two", - "FINE: Q10002 scheduled after 100 µs: task three", - "FINE: Q10000 starting : task one", - "FINE: Q10000 finished run in 0 µs: task one", - "FINE: Q10001 starting : task two", - "FINE: Q10001 finished run in 0 µs: task two", - "FINE: Q10002 starting : task three", - "FINE: Q10002 finished run in 0 µs: task three" + "FINE: Q10000 scheduled after 100 µs: task one", + "FINE: Q10001 scheduled after 100 µs: task two", + "FINE: Q10002 scheduled after 100 µs: task three", + "FINE: Q10000 starting : task one", + "FINE: Q10000 finished run in 0 µs: task one", + "FINE: Q10001 starting : task two", + "FINE: Q10001 finished run in 0 µs: task two", + "FINE: Q10002 starting : task three", + "FINE: Q10002 finished run in 0 µs: task three", ) } @@ -442,8 +456,8 @@ class TaskRunnerTest { assertThat(redQueue.scheduledTasks.toString()).isEqualTo("[task one, task two]") assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task one", - "FINE: Q10000 scheduled after 200 µs: task two" + "FINE: Q10000 scheduled after 100 µs: task one", + "FINE: Q10000 scheduled after 200 µs: task two", ) } @@ -452,16 +466,18 @@ class TaskRunnerTest { * cumbersome to implement properly because the active task might be a cancel. */ @Test fun scheduledTasksDoesNotIncludeRunningTask() { - val task = object : Task("task one") { - val schedules = mutableListOf(200.µs) - override fun runOnce(): Long { - if (schedules.isNotEmpty()) { - redQueue.schedule(this, schedules.removeAt(0)) // Add it at the end also. + val task = + object : Task("task one") { + val schedules = mutableListOf(200.µs) + + override fun runOnce(): Long { + if (schedules.isNotEmpty()) { + redQueue.schedule(this, schedules.removeAt(0)) // Add it at the end also. + } + log += "scheduledTasks=${redQueue.scheduledTasks}" + return -1L } - log += "scheduledTasks=${redQueue.scheduledTasks}" - return -1L } - } redQueue.schedule(task, 100.µs) redQueue.execute("task two", 200.µs) { @@ -470,34 +486,34 @@ class TaskRunnerTest { taskFaker.advanceUntil(100.µs) assertThat(log).containsExactly( - "scheduledTasks=[task two, task one]" + "scheduledTasks=[task two, task one]", ) taskFaker.advanceUntil(200.µs) assertThat(log).containsExactly( - "scheduledTasks=[task two, task one]", - "scheduledTasks=[task one]" + "scheduledTasks=[task two, task one]", + "scheduledTasks=[task one]", ) taskFaker.advanceUntil(300.µs) assertThat(log).containsExactly( - "scheduledTasks=[task two, task one]", - "scheduledTasks=[task one]", - "scheduledTasks=[]" + "scheduledTasks=[task two, task one]", + "scheduledTasks=[task one]", + "scheduledTasks=[]", ) taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task one", - "FINE: Q10000 scheduled after 200 µs: task two", - "FINE: Q10000 starting : task one", - "FINE: Q10000 scheduled after 200 µs: task one", - "FINE: Q10000 finished run in 0 µs: task one", - "FINE: Q10000 starting : task two", - "FINE: Q10000 finished run in 0 µs: task two", - "FINE: Q10000 starting : task one", - "FINE: Q10000 finished run in 0 µs: task one" + "FINE: Q10000 scheduled after 100 µs: task one", + "FINE: Q10000 scheduled after 200 µs: task two", + "FINE: Q10000 starting : task one", + "FINE: Q10000 scheduled after 200 µs: task one", + "FINE: Q10000 finished run in 0 µs: task one", + "FINE: Q10000 starting : task two", + "FINE: Q10000 finished run in 0 µs: task two", + "FINE: Q10000 starting : task one", + "FINE: Q10000 finished run in 0 µs: task one", ) } @@ -527,12 +543,12 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task one", - "FINE: Q10001 scheduled after 200 µs: task two", - "FINE: Q10000 starting : task one", - "FINE: Q10000 finished run in 0 µs: task one", - "FINE: Q10001 starting : task two", - "FINE: Q10001 finished run in 0 µs: task two" + "FINE: Q10000 scheduled after 100 µs: task one", + "FINE: Q10001 scheduled after 200 µs: task two", + "FINE: Q10000 starting : task one", + "FINE: Q10000 finished run in 0 µs: task one", + "FINE: Q10001 starting : task two", + "FINE: Q10001 finished run in 0 µs: task two", ) } @@ -547,9 +563,9 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 0 µs: lucky task", - "FINE: Q10000 starting : lucky task", - "FINE: Q10000 finished run in 0 µs: lucky task" + "FINE: Q10000 scheduled after 0 µs: lucky task", + "FINE: Q10000 starting : lucky task", + "FINE: Q10000 finished run in 0 µs: lucky task", ) } @@ -569,18 +585,21 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 canceled : task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 canceled : task", ) } @Test fun shutdownFailsToCancelsScheduledTasks() { - redQueue.schedule(object : Task("task", false) { - override fun runOnce(): Long { - log += "run@${taskFaker.nanoTime}" - return 50.µs - } - }, 100.µs) + redQueue.schedule( + object : Task("task", false) { + override fun runOnce(): Long { + log += "run@${taskFaker.nanoTime}" + return 50.µs + } + }, + 100.µs, + ) taskFaker.advanceUntil(0.µs) assertThat(log).isEmpty() @@ -596,9 +615,9 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 scheduled after 100 µs: task", - "FINE: Q10000 starting : task", - "FINE: Q10000 finished run in 0 µs: task" + "FINE: Q10000 scheduled after 100 µs: task", + "FINE: Q10000 starting : task", + "FINE: Q10000 finished run in 0 µs: task", ) } @@ -612,7 +631,7 @@ class TaskRunnerTest { taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 schedule canceled (queue is shutdown): task" + "FINE: Q10000 schedule canceled (queue is shutdown): task", ) } @@ -620,17 +639,20 @@ class TaskRunnerTest { redQueue.shutdown() assertFailsWith { - redQueue.schedule(object : Task("task", cancelable = false) { - override fun runOnce(): Long { - return -1L - } - }, 100.µs) + redQueue.schedule( + object : Task("task", cancelable = false) { + override fun runOnce(): Long { + return -1L + } + }, + 100.µs, + ) } taskFaker.assertNoMoreTasks() assertThat(testLogHandler.takeAll()).containsExactly( - "FINE: Q10000 schedule failed (queue is shutdown): task" + "FINE: Q10000 schedule failed (queue is shutdown): task", ) } diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index 4a42b700abba..6c5697dc3f3f 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -79,9 +79,10 @@ class ConnectionPoolTest { val pool = factory.newConnectionPool() val poolApi = ConnectionPool(pool) val c1 = factory.newConnection(pool, routeA1, 50L) - val client = OkHttpClient.Builder() - .connectionPool(poolApi) - .build() + val client = + OkHttpClient.Builder() + .connectionPool(poolApi) + .build() val call = client.newCall(Request(addressA.url)) as RealCall call.enterNetworkInterceptorExchange(call.request(), true, factory.newChain(call)) synchronized(c1) { call.acquireConnectionNoEvents(c1) } @@ -133,9 +134,10 @@ class ConnectionPoolTest { } @Test fun oldestConnectionsEvictedIfIdleLimitExceeded() { - val pool = factory.newConnectionPool( - maxIdleConnections = 2 - ) + val pool = + factory.newConnectionPool( + maxIdleConnections = 2, + ) val c1 = factory.newConnection(pool, routeA1, 50L) val c2 = factory.newConnection(pool, routeB1, 75L) @@ -171,10 +173,11 @@ class ConnectionPoolTest { @Test fun interruptStopsThread() { val realTaskRunner = TaskRunner.INSTANCE - val pool = factory.newConnectionPool( - taskRunner = TaskRunner.INSTANCE, - maxIdleConnections = 2 - ) + val pool = + factory.newConnectionPool( + taskRunner = TaskRunner.INSTANCE, + maxIdleConnections = 2, + ) factory.newConnection(pool, routeA1) assertThat(realTaskRunner.activeQueues()).isNotEmpty() Thread.sleep(100) @@ -190,10 +193,14 @@ class ConnectionPoolTest { } /** Use a helper method so there's no hidden reference remaining on the stack. */ - private fun allocateAndLeakAllocation(pool: ConnectionPool, connection: RealConnection) { - val client = OkHttpClient.Builder() - .connectionPool(pool) - .build() + private fun allocateAndLeakAllocation( + pool: ConnectionPool, + connection: RealConnection, + ) { + val client = + OkHttpClient.Builder() + .connectionPool(pool) + .build() val call = client.newCall(Request(connection.route().address.url)) as RealCall call.enterNetworkInterceptorExchange(call.request(), true, factory.newChain(call)) synchronized(connection) { call.acquireConnectionNoEvents(connection) } diff --git a/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt index d891610e9f8e..e6327295a4af 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt @@ -21,13 +21,12 @@ import assertk.assertions.hasMessage import assertk.assertions.isEqualTo import java.io.IOException import java.net.UnknownServiceException +import kotlin.test.assertFailsWith import okhttp3.FakeRoutePlanner import okhttp3.FakeRoutePlanner.ConnectState.TLS_CONNECTED import okhttp3.internal.concurrent.TaskFaker import okhttp3.testing.Flaky import org.junit.jupiter.api.AfterEach -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.Test import org.junitpioneer.jupiter.RetryingTest @@ -302,7 +301,7 @@ internal class FastFallbackExchangeFinderTest { "plan 0 cancel", "plan 1 TLS connecting...", "plan 1 TLS connected", - "plan 2 TCP connecting..." + "plan 2 TCP connecting...", ) taskFaker.advanceUntil(270.ms) @@ -820,7 +819,7 @@ internal class FastFallbackExchangeFinderTest { taskFaker.runTasks() assertEvents( "plan 0 TCP connected", - "plan 0 cancel" + "plan 0 cancel", ) } diff --git a/okhttp/src/test/java/okhttp3/internal/connection/InetAddressOrderTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/InetAddressOrderTest.kt index 85590a976177..2d07d92f834a 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/InetAddressOrderTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/InetAddressOrderTest.kt @@ -31,17 +31,19 @@ class InetAddressOrderTest { val ipv6_fc = Inet6Address.getByName("::fc") @Test fun prioritiseIpv6Example() { - val result = reorderForHappyEyeballs( - listOf( - ipv4_10_0_0_6, - ipv4_10_0_0_1, - ipv4_10_0_0_4, - ipv6_ab, ipv6_fc + val result = + reorderForHappyEyeballs( + listOf( + ipv4_10_0_0_6, + ipv4_10_0_0_1, + ipv4_10_0_0_4, + ipv6_ab, + ipv6_fc, + ), ) - ) assertThat(result).isEqualTo( - listOf(ipv6_ab, ipv4_10_0_0_6, ipv6_fc, ipv4_10_0_0_1, ipv4_10_0_0_4) + listOf(ipv6_ab, ipv4_10_0_0_6, ipv6_fc, ipv4_10_0_0_1, ipv4_10_0_0_4), ) } @@ -49,21 +51,22 @@ class InetAddressOrderTest { val result = reorderForHappyEyeballs(listOf(ipv6_ab, ipv6_fc)) assertThat(result).isEqualTo( - listOf(ipv6_ab, ipv6_fc) + listOf(ipv6_ab, ipv6_fc), ) } @Test fun ipv4Only() { - val result = reorderForHappyEyeballs( - listOf( - ipv4_10_0_0_6, - ipv4_10_0_0_1, - ipv4_10_0_0_4 + val result = + reorderForHappyEyeballs( + listOf( + ipv4_10_0_0_6, + ipv4_10_0_0_1, + ipv4_10_0_0_4, + ), ) - ) assertThat(result).isEqualTo( - listOf(ipv4_10_0_0_6, ipv4_10_0_0_1, ipv4_10_0_0_4) + listOf(ipv4_10_0_0_6, ipv4_10_0_0_1, ipv4_10_0_0_4), ) } @@ -71,7 +74,7 @@ class InetAddressOrderTest { val result = reorderForHappyEyeballs(listOf(ipv6_ab)) assertThat(result).isEqualTo( - listOf(ipv6_ab) + listOf(ipv6_ab), ) } @@ -79,7 +82,7 @@ class InetAddressOrderTest { val result = reorderForHappyEyeballs(listOf(ipv4_10_0_0_6)) assertThat(result).isEqualTo( - listOf(ipv4_10_0_0_6) + listOf(ipv4_10_0_0_6), ) } @@ -87,7 +90,7 @@ class InetAddressOrderTest { val result = reorderForHappyEyeballs(listOf(ipv4_10_0_0_6, ipv6_ab)) assertThat(result).isEqualTo( - listOf(ipv6_ab, ipv4_10_0_0_6) + listOf(ipv6_ab, ipv4_10_0_0_6), ) } } diff --git a/okhttp/src/test/java/okhttp3/internal/connection/RetryConnectionTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/RetryConnectionTest.kt index 90647ebe3272..92a6c1f38231 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/RetryConnectionTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/RetryConnectionTest.kt @@ -54,9 +54,10 @@ class RetryConnectionTest { } @Test fun nonRetryableSSLHandshakeException() { - val exception = SSLHandshakeException("Certificate handshake exception").apply { - initCause(CertificateException()) - } + val exception = + SSLHandshakeException("Certificate handshake exception").apply { + initCause(CertificateException()) + } assertThat(retryTlsHandshake(exception)).isFalse() } @@ -65,22 +66,25 @@ class RetryConnectionTest { } @Test fun someFallbacksSupported() { - val sslV3 = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) - .tlsVersions(TlsVersion.SSL_3_0) - .build() + val sslV3 = + ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(TlsVersion.SSL_3_0) + .build() val routePlanner = factory.newRoutePlanner(client) val route = factory.newRoute() val connectionSpecs = listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, sslV3) - val enabledSocketTlsVersions = arrayOf( - TlsVersion.TLS_1_2, - TlsVersion.TLS_1_1, - TlsVersion.TLS_1_0 - ) + val enabledSocketTlsVersions = + arrayOf( + TlsVersion.TLS_1_2, + TlsVersion.TLS_1_1, + TlsVersion.TLS_1_0, + ) var socket = createSocketWithEnabledProtocols(*enabledSocketTlsVersions) // MODERN_TLS is used here. - val attempt0 = routePlanner.planConnectToRoute(route) - .planWithCurrentOrInitialConnectionSpec(connectionSpecs, socket) + val attempt0 = + routePlanner.planConnectToRoute(route) + .planWithCurrentOrInitialConnectionSpec(connectionSpecs, socket) assertThat(attempt0.isTlsFallback).isFalse() connectionSpecs[attempt0.connectionSpecIndex].apply(socket, attempt0.isTlsFallback) assertEnabledProtocols(socket, TlsVersion.TLS_1_2) @@ -106,10 +110,12 @@ class RetryConnectionTest { } } - private fun assertEnabledProtocols(socket: SSLSocket, vararg required: TlsVersion) { + private fun assertEnabledProtocols( + socket: SSLSocket, + vararg required: TlsVersion, + ) { assertThat(socket.enabledProtocols.toList()).containsExactlyInAnyOrder(*javaNames(*required)) } - private fun javaNames(vararg tlsVersions: TlsVersion) = - tlsVersions.map { it.javaName }.toTypedArray() + private fun javaNames(vararg tlsVersions: TlsVersion) = tlsVersions.map { it.javaName }.toTypedArray() } diff --git a/okhttp/src/test/java/okhttp3/internal/connection/RouteSelectorTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/RouteSelectorTest.kt index 3f8851bae6b5..8bd37d39b236 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/RouteSelectorTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/RouteSelectorTest.kt @@ -57,22 +57,24 @@ class RouteSelectorTest { private val proxySelector = RecordingProxySelector() private val uriHost = "hosta" private val uriPort = 1003 - private val factory = TestValueFactory().apply { - this.dns = this@RouteSelectorTest.dns - this.proxySelector = this@RouteSelectorTest.proxySelector - this.uriHost = this@RouteSelectorTest.uriHost - this.uriPort = this@RouteSelectorTest.uriPort - } + private val factory = + TestValueFactory().apply { + this.dns = this@RouteSelectorTest.dns + this.proxySelector = this@RouteSelectorTest.proxySelector + this.uriHost = this@RouteSelectorTest.uriHost + this.uriPort = this@RouteSelectorTest.uriPort + } private lateinit var call: Call private val routeDatabase = RouteDatabase() @BeforeEach fun setUp() { - call = clientTestRule.newClient().newCall( - Request.Builder() - .url("https://$uriHost:$uriPort/") - .build() - ) + call = + clientTestRule.newClient().newCall( + Request.Builder() + .url("https://$uriHost:$uriPort/") + .build(), + ) } @AfterEach fun tearDown() { @@ -119,9 +121,10 @@ class RouteSelectorTest { } @Test fun explicitProxyTriesThatProxysAddressesOnly() { - val address = factory.newAddress( - proxy = proxyA, - ) + val address = + factory.newAddress( + proxy = proxyA, + ) val routeSelector = newRouteSelector(address) assertThat(routeSelector.hasNext()).isTrue() dns[PROXY_A_HOST] = dns.allocate(2) @@ -135,9 +138,10 @@ class RouteSelectorTest { } @Test fun explicitDirectProxy() { - val address = factory.newAddress( - proxy = Proxy.NO_PROXY, - ) + val address = + factory.newAddress( + proxy = Proxy.NO_PROXY, + ) val routeSelector = newRouteSelector(address) assertThat(routeSelector.hasNext()).isTrue() dns[uriHost] = dns.allocate(2) @@ -158,10 +162,11 @@ class RouteSelectorTest { // The string '>' is okay in a hostname in HttpUrl, which does very light hostname validation. // It is not okay in URI, and so it's stripped and we get a URI with a null host. val bogusHostname = ">" - val address = factory.newAddress( - uriHost = bogusHostname, - uriPort = uriPort, - ) + val address = + factory.newAddress( + uriHost = bogusHostname, + uriPort = uriPort, + ) val routeSelector = newRouteSelector(address) assertThat(routeSelector.hasNext()).isTrue() dns[bogusHostname] = dns.allocate(1) @@ -174,20 +179,26 @@ class RouteSelectorTest { } @Test fun proxySelectorReturnsNull() { - val nullProxySelector: ProxySelector = object : ProxySelector() { - override fun select(uri: URI): List? { - assertThat(uri.host).isEqualTo(uriHost) - return null + val nullProxySelector: ProxySelector = + object : ProxySelector() { + override fun select(uri: URI): List? { + assertThat(uri.host).isEqualTo(uriHost) + return null + } + + override fun connectFailed( + uri: URI, + socketAddress: SocketAddress, + e: IOException, + ) { + throw AssertionError() + } } - override fun connectFailed(uri: URI, socketAddress: SocketAddress, e: IOException) { - throw AssertionError() - } - } - - val address = factory.newAddress( - proxySelector = nullProxySelector - ) + val address = + factory.newAddress( + proxySelector = nullProxySelector, + ) val routeSelector = newRouteSelector(address) assertThat(routeSelector.hasNext()).isTrue() dns[uriHost] = dns.allocate(1) @@ -385,13 +396,15 @@ class RouteSelectorTest { } @Test fun addressesNotSortedWhenFastFallbackIsOff() { - val address = factory.newAddress( - proxy = Proxy.NO_PROXY - ) - val routeSelector = newRouteSelector( - address = address, - fastFallback = false, - ) + val address = + factory.newAddress( + proxy = Proxy.NO_PROXY, + ) + val routeSelector = + newRouteSelector( + address = address, + fastFallback = false, + ) assertThat(routeSelector.hasNext()).isTrue() val (ipv4_1, ipv4_2) = dns.allocate(2) val (ipv6_1, ipv6_2) = dns.allocateIpv6(2) @@ -407,13 +420,15 @@ class RouteSelectorTest { } @Test fun addressesSortedWhenFastFallbackIsOn() { - val address = factory.newAddress( - proxy = Proxy.NO_PROXY - ) - val routeSelector = newRouteSelector( - address = address, - fastFallback = true, - ) + val address = + factory.newAddress( + proxy = Proxy.NO_PROXY, + ) + val routeSelector = + newRouteSelector( + address = address, + fastFallback = true, + ) assertThat(routeSelector.hasNext()).isTrue() val (ipv4_1, ipv4_2) = dns.allocate(2) val (ipv6_1, ipv6_2) = dns.allocateIpv6(2) @@ -440,78 +455,81 @@ class RouteSelectorTest { assertThat(socketAddress.socketHost).isEqualTo("127.0.0.1") socketAddress = InetSocketAddress(InetAddress.getByAddress(byteArrayOf(127, 0, 0, 1)), 1234) assertThat(socketAddress.socketHost).isEqualTo("127.0.0.1") - socketAddress = InetSocketAddress( - InetAddress.getByAddress("foobar", byteArrayOf(127, 0, 0, 1)), - 1234 - ) + socketAddress = + InetSocketAddress( + InetAddress.getByAddress("foobar", byteArrayOf(127, 0, 0, 1)), + 1234, + ) assertThat(socketAddress.socketHost).isEqualTo("127.0.0.1") } @Test fun routeToString() { - val ipv4Address = InetAddress.getByAddress( - byteArrayOf(1, 2, 3, 4) - ) + val ipv4Address = + InetAddress.getByAddress( + byteArrayOf(1, 2, 3, 4), + ) assertThat( Route( factory.newAddress(uriHost = "1.2.3.4", uriPort = 1003), Proxy.NO_PROXY, - InetSocketAddress(ipv4Address, 1003) - ).toString() + InetSocketAddress(ipv4Address, 1003), + ).toString(), ).isEqualTo("1.2.3.4:1003") assertThat( Route( factory.newAddress(uriHost = "example.com", uriPort = 1003), Proxy.NO_PROXY, - InetSocketAddress(ipv4Address, 1003) - ).toString() + InetSocketAddress(ipv4Address, 1003), + ).toString(), ).isEqualTo("example.com at 1.2.3.4:1003") assertThat( Route( factory.newAddress(uriHost = "example.com", uriPort = 1003), Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved("proxy.example.com", 1003)), - InetSocketAddress(ipv4Address, 1003) - ).toString() + InetSocketAddress(ipv4Address, 1003), + ).toString(), ).isEqualTo("example.com via proxy 1.2.3.4:1003") assertThat( Route( factory.newAddress(uriHost = "example.com", uriPort = 1003), Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved("proxy.example.com", 1003)), - InetSocketAddress(ipv4Address, 5678) - ).toString() + InetSocketAddress(ipv4Address, 5678), + ).toString(), ).isEqualTo("example.com:1003 via proxy 1.2.3.4:5678") } @Test fun routeToStringIpv6() { - val ipv6Address = InetAddress.getByAddress( - byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1) - ) + val ipv6Address = + InetAddress.getByAddress( + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), + ) assertThat( Route( factory.newAddress(uriHost = "::1", uriPort = 1003), Proxy.NO_PROXY, - InetSocketAddress(ipv6Address, uriPort) - ).toString() + InetSocketAddress(ipv6Address, uriPort), + ).toString(), ).isEqualTo("[::1]:1003") assertThat( Route( factory.newAddress(uriHost = "example.com", uriPort = 1003), Proxy.NO_PROXY, - InetSocketAddress(ipv6Address, uriPort) - ).toString() + InetSocketAddress(ipv6Address, uriPort), + ).toString(), ).isEqualTo("example.com at [::1]:1003") assertThat( Route( factory.newAddress(uriHost = "example.com", uriPort = 1003), Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved("proxy.example.com", 1003)), - InetSocketAddress(ipv6Address, 5678) - ).toString() + InetSocketAddress(ipv6Address, 5678), + ).toString(), ).isEqualTo("example.com:1003 via proxy [::1]:5678") assertThat( Route( factory.newAddress(uriHost = "::2", uriPort = 1003), Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved("proxy.example.com", 1003)), - InetSocketAddress(ipv6Address, 5678) - ).toString() + InetSocketAddress(ipv6Address, 5678), + ).toString(), ).isEqualTo("[::2]:1003 via proxy [::1]:5678") } @@ -520,7 +538,7 @@ class RouteSelectorTest { address: Address, proxy: Proxy, socketAddress: InetAddress, - socketPort: Int + socketPort: Int, ) { assertThat(route.address).isEqualTo(address) assertThat(route.proxy).isEqualTo(proxy) @@ -546,16 +564,18 @@ class RouteSelectorTest { companion object { private const val PROXY_A_PORT = 1001 private const val PROXY_A_HOST = "proxya" - private val proxyA = Proxy( - Proxy.Type.HTTP, - InetSocketAddress.createUnresolved(PROXY_A_HOST, PROXY_A_PORT) - ) + private val proxyA = + Proxy( + Proxy.Type.HTTP, + InetSocketAddress.createUnresolved(PROXY_A_HOST, PROXY_A_PORT), + ) private const val PROXY_B_PORT = 1002 private const val PROXY_B_HOST = "proxyb" - private val proxyB = Proxy( - Proxy.Type.HTTP, - InetSocketAddress.createUnresolved(PROXY_B_HOST, PROXY_B_PORT) - ) + private val proxyB = + Proxy( + Proxy.Type.HTTP, + InetSocketAddress.createUnresolved(PROXY_B_HOST, PROXY_B_PORT), + ) } } diff --git a/okhttp/src/test/java/okhttp3/internal/http/CancelTest.kt b/okhttp/src/test/java/okhttp3/internal/http/CancelTest.kt index bba84453a1d4..c2bc327aca53 100644 --- a/okhttp/src/test/java/okhttp3/internal/http/CancelTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http/CancelTest.kt @@ -70,7 +70,8 @@ import org.junit.jupiter.params.provider.ArgumentsSource @Timeout(30) @Tag("Slow") class CancelTest { - @JvmField @RegisterExtension val platform = PlatformRule() + @JvmField @RegisterExtension + val platform = PlatformRule() lateinit var cancelMode: CancelMode lateinit var connectionType: ConnectionType @@ -79,16 +80,17 @@ class CancelTest { enum class CancelMode { CANCEL, - INTERRUPT + INTERRUPT, } enum class ConnectionType { H2, HTTPS, - HTTP + HTTP, } - @JvmField @RegisterExtension val clientTestRule = OkHttpClientTestRule() + @JvmField @RegisterExtension + val clientTestRule = OkHttpClientTestRule() val handshakeCertificates = platform.localhostHandshakeCertificates() @@ -110,9 +112,8 @@ class CancelTest { server = MockWebServer() server.serverSocketFactory = object : DelegatingServerSocketFactory(ServerSocketFactory.getDefault()) { - @Throws(IOException::class) override fun configureServerSocket( - serverSocket: ServerSocket - ): ServerSocket { + @Throws(IOException::class) + override fun configureServerSocket(serverSocket: ServerSocket): ServerSocket { serverSocket.receiveBufferSize = SOCKET_BUFFER_SIZE return serverSocket } @@ -122,21 +123,26 @@ class CancelTest { } server.start() - client = clientTestRule.newClientBuilder() - .socketFactory(object : DelegatingSocketFactory(SocketFactory.getDefault()) { - @Throws(IOException::class) - override fun configureSocket(socket: Socket): Socket { - socket.sendBufferSize = SOCKET_BUFFER_SIZE - socket.receiveBufferSize = SOCKET_BUFFER_SIZE - return socket - } - }) + client = + clientTestRule.newClientBuilder() + .socketFactory( + object : DelegatingSocketFactory(SocketFactory.getDefault()) { + @Throws(IOException::class) + override fun configureSocket(socket: Socket): Socket { + socket.sendBufferSize = SOCKET_BUFFER_SIZE + socket.receiveBufferSize = SOCKET_BUFFER_SIZE + return socket + } + }, + ) .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, ) .eventListener(listener) .apply { - if (connectionType == HTTPS) { protocols(listOf(HTTP_1_1)) } + if (connectionType == HTTPS) { + protocols(listOf(HTTP_1_1)) + } } .build() threadToCancel = Thread.currentThread() @@ -147,27 +153,30 @@ class CancelTest { fun cancelWritingRequestBody(mode: Pair) { setUp(mode) server.enqueue(MockResponse()) - val call = client.newCall( - Request( - url = server.url("/"), - body = object : RequestBody() { - override fun contentType(): MediaType? { - return null - } + val call = + client.newCall( + Request( + url = server.url("/"), + body = + object : RequestBody() { + override fun contentType(): MediaType? { + return null + } - @Throws( - IOException::class - ) override fun writeTo(sink: BufferedSink) { - for (i in 0..9) { - sink.writeByte(0) - sink.flush() - sleep(100) - } - fail("Expected connection to be closed") - } - }, + @Throws( + IOException::class, + ) + override fun writeTo(sink: BufferedSink) { + for (i in 0..9) { + sink.writeByte(0) + sink.flush() + sleep(100) + } + fail("Expected connection to be closed") + } + }, + ), ) - ) cancelLater(call, 500) assertFailsWith { call.execute() @@ -185,10 +194,10 @@ class CancelTest { MockResponse.Builder() .body( Buffer() - .write(ByteArray(responseBodySize)) + .write(ByteArray(responseBodySize)), ) .throttleBody(64 * 1024, 125, MILLISECONDS) // 500 Kbps - .build() + .build(), ) val call = client.newCall(Request(server.url("/"))) val response = call.execute() @@ -214,10 +223,10 @@ class CancelTest { MockResponse.Builder() .body( Buffer() - .write(ByteArray(responseBodySize)) + .write(ByteArray(responseBodySize)), ) .throttleBody(64 * 1024, 125, MILLISECONDS) // 500 Kbps - .build() + .build(), ) server.enqueue(MockResponse(body = ".")) @@ -255,27 +264,28 @@ class CancelTest { } val events2 = listener.eventSequence.filter { isConnectionEvent(it) }.map { it.name } - val expectedEvents2 = mutableListOf().apply { - add("CallStart") - if (connectionType != H2) { - addAll(listOf("ConnectStart", "ConnectEnd")) + val expectedEvents2 = + mutableListOf().apply { + add("CallStart") + if (connectionType != H2) { + addAll(listOf("ConnectStart", "ConnectEnd")) + } + addAll(listOf("ConnectionAcquired", "ConnectionReleased", "CallEnd")) } - addAll(listOf("ConnectionAcquired", "ConnectionReleased", "CallEnd")) - } assertThat(events2).isEqualTo(expectedEvents2) } private fun isConnectionEvent(it: CallEvent?) = it is CallStart || - it is CallEnd || - it is ConnectStart || - it is ConnectEnd || - it is ConnectionAcquired || - it is ConnectionReleased || - it is Canceled || - it is RequestFailed || - it is ResponseFailed + it is CallEnd || + it is ConnectStart || + it is ConnectEnd || + it is ConnectionAcquired || + it is ConnectionReleased || + it is Canceled || + it is RequestFailed || + it is ResponseFailed private fun sleep(delayMillis: Int) { try { @@ -287,7 +297,7 @@ class CancelTest { private fun cancelLater( call: Call, - delayMillis: Int + delayMillis: Int, ): CountDownLatch { val latch = CountDownLatch(1) Thread { @@ -308,8 +318,14 @@ class CancelTest { } } -class CancelModelParamProvider: SimpleProvider() { - override fun arguments() = CancelTest.CancelMode.values().flatMap { c -> CancelTest.ConnectionType.values().map { x -> Pair( - c, x - ) } } +class CancelModelParamProvider : SimpleProvider() { + override fun arguments() = + CancelTest.CancelMode.values().flatMap { c -> + CancelTest.ConnectionType.values().map { x -> + Pair( + c, + x, + ) + } + } } diff --git a/okhttp/src/test/java/okhttp3/internal/http/ExternalHttp2Example.kt b/okhttp/src/test/java/okhttp3/internal/http/ExternalHttp2Example.kt index 59c82688fe84..3767fac7f8e2 100644 --- a/okhttp/src/test/java/okhttp3/internal/http/ExternalHttp2Example.kt +++ b/okhttp/src/test/java/okhttp3/internal/http/ExternalHttp2Example.kt @@ -22,14 +22,16 @@ import okhttp3.Request object ExternalHttp2Example { @JvmStatic fun main(args: Array) { - val client = OkHttpClient.Builder() - .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)) - .build() - val call = client.newCall( - Request.Builder() - .url("https://www.google.ca/") + val client = + OkHttpClient.Builder() + .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)) .build() - ) + val call = + client.newCall( + Request.Builder() + .url("https://www.google.ca/") + .build(), + ) val response = call.execute() try { println(response.code) diff --git a/okhttp/src/test/java/okhttp3/internal/http/HttpDateTest.kt b/okhttp/src/test/java/okhttp3/internal/http/HttpDateTest.kt index affa995ba976..2452c3fb0ed2 100644 --- a/okhttp/src/test/java/okhttp3/internal/http/HttpDateTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http/HttpDateTest.kt @@ -25,7 +25,6 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class HttpDateTest { - private lateinit var originalDefault: TimeZone @BeforeEach @@ -42,7 +41,8 @@ class HttpDateTest { TimeZone.setDefault(originalDefault) } - @Test @Throws(Exception::class) + @Test + @Throws(Exception::class) fun parseStandardFormats() { // RFC 822, updated by RFC 1123 with GMT. assertThat("Thu, 01 Jan 1970 00:00:00 GMT".toHttpDateOrNull()!!.time).isEqualTo(0L) @@ -57,13 +57,15 @@ class HttpDateTest { assertThat("Fri Jun 6 12:30:30 2014".toHttpDateOrNull()!!.time).isEqualTo(1402057830000L) } - @Test @Throws(Exception::class) + @Test + @Throws(Exception::class) fun format() { assertThat(Date(0L).toHttpDateString()).isEqualTo("Thu, 01 Jan 1970 00:00:00 GMT") assertThat(Date(1402057830000L).toHttpDateString()).isEqualTo("Fri, 06 Jun 2014 12:30:30 GMT") } - @Test @Throws(Exception::class) + @Test + @Throws(Exception::class) fun parseNonStandardStrings() { // RFC 822, updated by RFC 1123 with any TZ assertThat("Thu, 01 Jan 1970 00:00:00 GMT-01:00".toHttpDateOrNull()!!.time).isEqualTo(3600000L) @@ -81,12 +83,12 @@ class HttpDateTest { // RFC 850, obsoleted by RFC 1036 with any TZ. assertThat("Thursday, 01-Jan-1970 00:00:00 GMT-01:00".toHttpDateOrNull()!!.time) - .isEqualTo(3600000L) + .isEqualTo(3600000L) assertThat("Thursday, 01-Jan-1970 00:00:00 PST".toHttpDateOrNull()!!.time) - .isEqualTo(28800000L) + .isEqualTo(28800000L) // Ignore trailing junk assertThat("Thursday, 01-Jan-1970 00:00:00 PST JUNK".toHttpDateOrNull()!!.time) - .isEqualTo(28800000L) + .isEqualTo(28800000L) // ANSI C's asctime() format // This format ignores the timezone entirely even if it is present and uses GMT. diff --git a/okhttp/src/test/java/okhttp3/internal/http/StatusLineTest.kt b/okhttp/src/test/java/okhttp3/internal/http/StatusLineTest.kt index 40bf8b5934b1..a34fa2ee1791 100644 --- a/okhttp/src/test/java/okhttp3/internal/http/StatusLineTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http/StatusLineTest.kt @@ -18,10 +18,9 @@ package okhttp3.internal.http import assertk.assertThat import assertk.assertions.isEqualTo import java.net.ProtocolException +import kotlin.test.assertFailsWith import okhttp3.Protocol import okhttp3.internal.http.StatusLine.Companion.parse -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.Test class StatusLineTest { diff --git a/okhttp/src/test/java/okhttp3/internal/http/ThreadInterruptTest.kt b/okhttp/src/test/java/okhttp3/internal/http/ThreadInterruptTest.kt index 28275ed7a435..65f89f721f7f 100644 --- a/okhttp/src/test/java/okhttp3/internal/http/ThreadInterruptTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http/ThreadInterruptTest.kt @@ -15,11 +15,13 @@ */ package okhttp3.internal.http +import assertk.fail import java.io.IOException import java.net.ServerSocket import java.net.Socket import java.net.SocketException import java.util.concurrent.TimeUnit +import kotlin.test.assertFailsWith import okhttp3.DelegatingServerSocketFactory import okhttp3.DelegatingSocketFactory import okhttp3.OkHttpClient @@ -32,8 +34,6 @@ import okhttp3.testing.PlatformRule import okio.Buffer import okio.BufferedSink import org.junit.jupiter.api.AfterEach -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test @@ -54,23 +54,27 @@ class ThreadInterruptTest { // Sockets on some platforms can have large buffers that mean writes do not block when // required. These socket factories explicitly set the buffer sizes on sockets created. server = MockWebServer() - server.serverSocketFactory = object : DelegatingServerSocketFactory(getDefault()) { - @Throws(SocketException::class) - override fun configureServerSocket(serverSocket: ServerSocket): ServerSocket { - serverSocket.setReceiveBufferSize(SOCKET_BUFFER_SIZE) - return serverSocket - } - } - client = clientTestRule.newClientBuilder() - .socketFactory(object : DelegatingSocketFactory(getDefault()) { - @Throws(IOException::class) - override fun configureSocket(socket: Socket): Socket { - socket.setSendBufferSize(SOCKET_BUFFER_SIZE) - socket.setReceiveBufferSize(SOCKET_BUFFER_SIZE) - return socket + server.serverSocketFactory = + object : DelegatingServerSocketFactory(getDefault()) { + @Throws(SocketException::class) + override fun configureServerSocket(serverSocket: ServerSocket): ServerSocket { + serverSocket.setReceiveBufferSize(SOCKET_BUFFER_SIZE) + return serverSocket } - }) - .build() + } + client = + clientTestRule.newClientBuilder() + .socketFactory( + object : DelegatingSocketFactory(getDefault()) { + @Throws(IOException::class) + override fun configureSocket(socket: Socket): Socket { + socket.setSendBufferSize(SOCKET_BUFFER_SIZE) + socket.setReceiveBufferSize(SOCKET_BUFFER_SIZE) + return socket + } + }, + ) + .build() } @AfterEach @@ -82,23 +86,26 @@ class ThreadInterruptTest { fun interruptWritingRequestBody() { server.enqueue(MockResponse()) server.start() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .post(object : RequestBody() { - override fun contentType() = null + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .post( + object : RequestBody() { + override fun contentType() = null - override fun writeTo(sink: BufferedSink) { - for (i in 0..9) { - sink.writeByte(0) - sink.flush() - sleep(100) - } - fail("Expected connection to be closed") - } - }) - .build() - ) + override fun writeTo(sink: BufferedSink) { + for (i in 0..9) { + sink.writeByte(0) + sink.flush() + sleep(100) + } + fail("Expected connection to be closed") + } + }, + ) + .build(), + ) interruptLater(500) assertFailsWith { call.execute() @@ -111,14 +118,15 @@ class ThreadInterruptTest { server.enqueue( MockResponse() .setBody(Buffer().write(ByteArray(responseBodySize))) - .throttleBody((64 * 1024).toLong(), 125, TimeUnit.MILLISECONDS) + .throttleBody((64 * 1024).toLong(), 125, TimeUnit.MILLISECONDS), ) // 500 Kbps server.start() - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response = call.execute() interruptLater(500) val responseBody = response.body.byteStream() @@ -140,10 +148,11 @@ class ThreadInterruptTest { private fun interruptLater(delayMillis: Int) { val toInterrupt = Thread.currentThread() - val interruptingCow = Thread { - sleep(delayMillis) - toInterrupt.interrupt() - } + val interruptingCow = + Thread { + sleep(delayMillis) + toInterrupt.interrupt() + } interruptingCow.start() } diff --git a/okhttp/src/test/java/okhttp3/internal/http2/BaseTestHandler.kt b/okhttp/src/test/java/okhttp3/internal/http2/BaseTestHandler.kt index 5f3e88fc6164..4c70d410767d 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/BaseTestHandler.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/BaseTestHandler.kt @@ -15,9 +15,9 @@ */ package okhttp3.internal.http2 +import assertk.fail import okio.BufferedSource import okio.ByteString -import assertk.fail internal open class BaseTestHandler : Http2Reader.Handler { override fun data( diff --git a/okhttp/src/test/java/okhttp3/internal/http2/FrameLogTest.kt b/okhttp/src/test/java/okhttp3/internal/http2/FrameLogTest.kt index b1ab90e63812..8223735cf494 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/FrameLogTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/FrameLogTest.kt @@ -169,7 +169,7 @@ class FrameLogTest { "00111100", "00111101", "00111110", - "00111111" + "00111111", ) } } diff --git a/okhttp/src/test/java/okhttp3/internal/http2/HpackTest.kt b/okhttp/src/test/java/okhttp3/internal/http2/HpackTest.kt index a0d3472c2845..0240f5a1caef 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/HpackTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/HpackTest.kt @@ -19,7 +19,6 @@ import assertk.assertThat import assertk.assertions.containsExactly import assertk.assertions.isEqualTo import assertk.assertions.isNull -import assertk.fail import java.io.IOException import java.util.Arrays import kotlin.test.assertFailsWith @@ -76,18 +75,22 @@ class HpackTest { hpackReader!!.readHeaders() assertThat(hpackReader!!.headerCount).isEqualTo(0) assertThat(hpackReader!!.getAndResetHeaderList()).isEqualTo( - headerEntries("custom-key", "custom-header") + headerEntries("custom-key", "custom-header"), ) } /** Oldest entries are evicted to support newer ones. */ @Test fun writerEviction() { - val headerBlock = headerEntries( - "custom-foo", "custom-header", - "custom-bar", "custom-header", - "custom-baz", "custom-header" - ) + val headerBlock = + headerEntries( + "custom-foo", + "custom-header", + "custom-bar", + "custom-header", + "custom-baz", + "custom-header", + ) bytesIn.writeByte(0x40) // Literal indexed bytesIn.writeByte(0x0a) // Literal name (len = 10) bytesIn.writeUtf8("custom-foo") @@ -120,11 +123,15 @@ class HpackTest { @Test fun readerEviction() { - val headerBlock = headerEntries( - "custom-foo", "custom-header", - "custom-bar", "custom-header", - "custom-baz", "custom-header" - ) + val headerBlock = + headerEntries( + "custom-foo", + "custom-header", + "custom-bar", + "custom-header", + "custom-baz", + "custom-header", + ) // Set to only support 110 bytes (enough for 2 headers). bytesIn.writeByte(0x3F) // Dynamic table size update (size = 110). @@ -211,7 +218,7 @@ class HpackTest { val entry = hpackReader!!.dynamicTable[readerHeaderTableLength() - 1]!! checkEntry(entry, "custom-key", "custom-header", 55) assertThat(hpackReader!!.getAndResetHeaderList()).isEqualTo( - headerEntries("custom-key", "custom-header") + headerEntries("custom-key", "custom-header"), ) } @@ -254,7 +261,7 @@ class HpackTest { hpackReader!!.readHeaders() assertThat(hpackReader!!.headerCount).isEqualTo(0) assertThat(hpackReader!!.getAndResetHeaderList()).isEqualTo( - headerEntries(":path", "/sample/path") + headerEntries(":path", "/sample/path"), ) } @@ -302,10 +309,13 @@ class HpackTest { @Test fun theSameHeaderAfterOneIncrementalIndexed() { - val headerBlock = headerEntries( - "custom-key", "custom-header", - "custom-key", "custom-header" - ) + val headerBlock = + headerEntries( + "custom-key", + "custom-header", + "custom-key", + "custom-header", + ) bytesIn.writeByte(0x40) // Never indexed bytesIn.writeByte(0x0a) // Literal name (len = 10) bytesIn.writeUtf8("custom-key") @@ -331,7 +341,7 @@ class HpackTest { assertThat(hpackReader!!.dynamicTableByteCount).isEqualTo(0) assertThat(hpackReader!!.dynamicTable[readerHeaderTableLength() - 1]).isNull() assertThat(hpackReader!!.getAndResetHeaderList()).isEqualTo( - headerEntries(":method", "GET") + headerEntries(":method", "GET"), ) } @@ -421,7 +431,7 @@ class HpackTest { // Not buffered in header table. assertThat(hpackReader!!.headerCount).isEqualTo(0) assertThat(hpackReader!!.getAndResetHeaderList()).isEqualTo( - headerEntries(":method", "GET") + headerEntries(":method", "GET"), ) } @@ -448,7 +458,8 @@ class HpackTest { bytesIn.writeUtf8("Basic2") hpackReader!!.readHeaders() assertThat(hpackReader!!.getAndResetHeaderList()).containsExactly( - Header("custom-foo", "Basic"), Header("custom-foo", "Basic2") + Header("custom-foo", "Basic"), + Header("custom-foo", "Basic2"), ) } @@ -513,11 +524,15 @@ class HpackTest { // Decoded header list: assertThat(hpackReader!!.getAndResetHeaderList()).isEqualTo( headerEntries( - ":method", "GET", - ":scheme", "http", - ":path", "/", - ":authority", "www.example.com" - ) + ":method", + "GET", + ":scheme", + "http", + ":path", + "/", + ":authority", + "www.example.com", + ), ) } @@ -557,8 +572,8 @@ class HpackTest { ":scheme", "http", ":path", "/", ":authority", "www.example.com", - "cache-control", "no-cache" - ) + "cache-control", "no-cache", + ), ) } @@ -603,8 +618,8 @@ class HpackTest { ":scheme", "https", ":path", "/index.html", ":authority", "www.example.com", - "custom-key", "custom-value" - ) + "custom-key", "custom-value", + ), ) } @@ -651,11 +666,15 @@ class HpackTest { // Decoded header list: assertThat(hpackReader!!.getAndResetHeaderList()).isEqualTo( headerEntries( - ":method", "GET", - ":scheme", "http", - ":path", "/", - ":authority", "www.example.com" - ) + ":method", + "GET", + ":scheme", + "http", + ":path", + "/", + ":authority", + "www.example.com", + ), ) } @@ -696,8 +715,8 @@ class HpackTest { ":scheme", "http", ":path", "/", ":authority", "www.example.com", - "cache-control", "no-cache" - ) + "cache-control", "no-cache", + ), ) } @@ -744,8 +763,8 @@ class HpackTest { ":scheme", "https", ":path", "/index.html", ":authority", "www.example.com", - "custom-key", "custom-value" - ) + "custom-key", "custom-value", + ), ) } @@ -824,12 +843,12 @@ class HpackTest { 3, 'B'.code, 'a'.code, - 'R'.code - ) + 'R'.code, + ), ).readHeaders() }.also { expected -> assertThat(expected.message).isEqualTo( - "PROTOCOL_ERROR response malformed: mixed case name: Foo" + "PROTOCOL_ERROR response malformed: mixed case name: Foo", ) } } @@ -849,14 +868,14 @@ class HpackTest { assertBytes( // Dynamic table size update (size = 2048). 0x3F, 0xE1, 0xF, - 0x40, 3, 'f'.code, 'o'.code, 'o'.code, 3, 'b'.code, 'a'.code, 'r'.code + 0x40, 3, 'f'.code, 'o'.code, 'o'.code, 3, 'b'.code, 'a'.code, 'r'.code, ) hpackWriter!!.resizeHeaderTable(8192) hpackWriter!!.writeHeaders(listOf(Header("bar", "foo"))) assertBytes( // Dynamic table size update (size = 8192). 0x3F, 0xE1, 0x3F, - 0x40, 3, 'b'.code, 'a'.code, 'r'.code, 3, 'f'.code, 'o'.code, 'o'.code + 0x40, 3, 'b'.code, 'a'.code, 'r'.code, 3, 'f'.code, 'o'.code, 'o'.code, ) // No more dynamic table updates should be emitted. @@ -880,7 +899,7 @@ class HpackTest { assertBytes( // Dynamic table size update (size = 16384). 0x3F, 0xE1, 0x7F, - 0x40, 3, 'f'.code, 'o'.code, 'o'.code, 3, 'b'.code, 'a'.code, 'r'.code + 0x40, 3, 'f'.code, 'o'.code, 'o'.code, 3, 'b'.code, 'a'.code, 'r'.code, ) } @@ -892,7 +911,7 @@ class HpackTest { assertBytes( // Dynamic size update (size = 0). 0x20, - 0x40, 3, 'f'.code, 'o'.code, 'o'.code, 3, 'b'.code, 'a'.code, 'r'.code + 0x40, 3, 'f'.code, 'o'.code, 'o'.code, 3, 'b'.code, 'a'.code, 'r'.code, ) } @@ -909,16 +928,19 @@ class HpackTest { 0x20, // Dynamic size update (size = 2048). 0x3F, 0xE1, 0xF, - 0x40, 3, 'f'.code, 'o'.code, 'o'.code, 3, 'b'.code, 'a'.code, 'r'.code + 0x40, 3, 'f'.code, 'o'.code, 'o'.code, 3, 'b'.code, 'a'.code, 'r'.code, ) } @Test fun dynamicTableEvictionWhenSizeLowered() { - val headerBlock = headerEntries( - "custom-key1", "custom-header", - "custom-key2", "custom-header" - ) + val headerBlock = + headerEntries( + "custom-key1", + "custom-header", + "custom-key2", + "custom-header", + ) hpackWriter!!.writeHeaders(headerBlock) assertThat(hpackWriter!!.headerCount).isEqualTo(2) hpackWriter!!.resizeHeaderTable(56) @@ -929,10 +951,13 @@ class HpackTest { @Test fun noEvictionOnDynamicTableSizeIncrease() { - val headerBlock = headerEntries( - "custom-key1", "custom-header", - "custom-key2", "custom-header" - ) + val headerBlock = + headerEntries( + "custom-key1", + "custom-header", + "custom-key2", + "custom-header", + ) hpackWriter!!.writeHeaders(headerBlock) assertThat(hpackWriter!!.headerCount).isEqualTo(2) hpackWriter!!.resizeHeaderTable(8192) @@ -949,16 +974,17 @@ class HpackTest { fun huffmanEncode() { hpackWriter = Hpack.Writer(4096, true, bytesOut) hpackWriter!!.writeHeaders(headerEntries("foo", "bar")) - val expected = Buffer() - .writeByte(0x40) // Literal header, new name. - .writeByte(0x82) // String literal is Huffman encoded (len = 2). - .writeByte(0x94) // 'foo' Huffman encoded. - .writeByte(0xE7) - .writeByte(3) // String literal not Huffman encoded (len = 3). - .writeByte('b'.code) - .writeByte('a'.code) - .writeByte('r'.code) - .readByteString() + val expected = + Buffer() + .writeByte(0x40) // Literal header, new name. + .writeByte(0x82) // String literal is Huffman encoded (len = 2). + .writeByte(0x94) // 'foo' Huffman encoded. + .writeByte(0xE7) + .writeByte(3) // String literal not Huffman encoded (len = 3). + .writeByte('b'.code) + .writeByte('a'.code) + .writeByte('r'.code) + .readByteString() val actual = bytesOut.readByteString() assertThat(actual).isEqualTo(expected) } @@ -1014,7 +1040,7 @@ class HpackTest { 'a'.code, 'd'.code, 'e'.code, - 'r'.code + 'r'.code, ) assertThat(hpackWriter!!.headerCount).isEqualTo(1) hpackWriter!!.writeHeaders(headerEntries("custom-key", "custom-header")) @@ -1081,7 +1107,12 @@ class HpackTest { return Buffer().write(intArrayToByteArray(bytes)) } - private fun checkEntry(entry: Header, name: String, value: String, size: Int) { + private fun checkEntry( + entry: Header, + name: String, + value: String, + size: Int, + ) { assertThat(entry.name.utf8()).isEqualTo(name) assertThat(entry.value.utf8()).isEqualTo(value) assertThat(entry.hpackSize).isEqualTo(size) diff --git a/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt b/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt index e458cc02aa32..faeb3f041104 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt @@ -391,16 +391,18 @@ class Http2ConnectionTest { peer.acceptFrame() // ACK peer.acceptFrame() // SYN_STREAM peer.sendFrame().headers(false, 3, headerEntries("a", "android")) - val expectedRequestHeaders = listOf( - Header(Header.TARGET_METHOD, "GET"), - Header(Header.TARGET_SCHEME, "https"), - Header(Header.TARGET_AUTHORITY, "squareup.com"), - Header(Header.TARGET_PATH, "/cached") - ) + val expectedRequestHeaders = + listOf( + Header(Header.TARGET_METHOD, "GET"), + Header(Header.TARGET_SCHEME, "https"), + Header(Header.TARGET_AUTHORITY, "squareup.com"), + Header(Header.TARGET_PATH, "/cached"), + ) peer.sendFrame().pushPromise(3, 2, expectedRequestHeaders) - val expectedResponseHeaders = listOf( - Header(Header.RESPONSE_STATUS, "200") - ) + val expectedResponseHeaders = + listOf( + Header(Header.RESPONSE_STATUS, "200"), + ) peer.sendFrame().headers(true, 2, expectedResponseHeaders) peer.sendFrame().data(true, 3, data(0), 0) peer.play() @@ -444,20 +446,22 @@ class Http2ConnectionTest { .pushPromise( streamId = 3, promisedStreamId = 2, - requestHeaders = listOf( - Header(Header.TARGET_METHOD, "GET"), - Header(Header.TARGET_SCHEME, "https"), - Header(Header.TARGET_AUTHORITY, "squareup.com"), - Header(Header.TARGET_PATH, "/cached") - ) + requestHeaders = + listOf( + Header(Header.TARGET_METHOD, "GET"), + Header(Header.TARGET_SCHEME, "https"), + Header(Header.TARGET_AUTHORITY, "squareup.com"), + Header(Header.TARGET_PATH, "/cached"), + ), ) peer.sendFrame() .headers( outFinished = true, streamId = 2, - headerBlock = listOf( - Header(Header.RESPONSE_STATUS, "200") - ) + headerBlock = + listOf( + Header(Header.RESPONSE_STATUS, "200"), + ), ) peer.acceptFrame() // RST_STREAM peer.play() @@ -485,10 +489,11 @@ class Http2ConnectionTest { peer.play() val longString = repeat('a', Http2.INITIAL_MAX_FRAME_SIZE + 1) val socket = peer.openSocket() - val connection = Http2Connection.Builder(true, TaskRunner.INSTANCE) - .socket(socket) - .pushObserver(IGNORE) - .build() + val connection = + Http2Connection.Builder(true, TaskRunner.INSTANCE) + .socket(socket) + .pushObserver(IGNORE) + .build() connection.start(sendConnectionPreface = false) socket.shutdownOutput() assertFailsWith { @@ -948,16 +953,20 @@ class Http2ConnectionTest { // Play it back. val maxConcurrentStreamsUpdated = CountDownLatch(1) val maxConcurrentStreams = AtomicInteger() - val listener: Http2Connection.Listener = object : Http2Connection.Listener() { - override fun onStream(stream: Http2Stream) { - throw AssertionError() - } - - override fun onSettings(connection: Http2Connection, settings: Settings) { - maxConcurrentStreams.set(settings.getMaxConcurrentStreams()) - maxConcurrentStreamsUpdated.countDown() + val listener: Http2Connection.Listener = + object : Http2Connection.Listener() { + override fun onStream(stream: Http2Stream) { + throw AssertionError() + } + + override fun onSettings( + connection: Http2Connection, + settings: Settings, + ) { + maxConcurrentStreams.set(settings.getMaxConcurrentStreams()) + maxConcurrentStreamsUpdated.countDown() + } } - } val connection = connect(peer, IGNORE, listener) synchronized(connection) { assertThat(connection.peerSettings.getMaxConcurrentStreams()).isEqualTo(10) @@ -1464,7 +1473,7 @@ class Http2ConnectionTest { } val elapsedNanos = System.nanoTime() - startNanos awaitWatchdogIdle() - /* 200ms delta */ + // 200ms delta assertThat(TimeUnit.NANOSECONDS.toMillis(elapsedNanos).toDouble()) .isCloseTo(500.0, 200.0) assertThat(connection.openStreamCount()).isEqualTo(0) @@ -1505,7 +1514,8 @@ class Http2ConnectionTest { } val elapsedNanos = System.nanoTime() - startNanos awaitWatchdogIdle() - /* 200ms delta */assertThat(TimeUnit.NANOSECONDS.toMillis(elapsedNanos).toDouble()) + // 200ms delta + assertThat(TimeUnit.NANOSECONDS.toMillis(elapsedNanos).toDouble()) .isCloseTo(500.0, 200.0) assertThat(connection.openStreamCount()).isEqualTo(0) @@ -1556,7 +1566,8 @@ class Http2ConnectionTest { } val elapsedNanos = System.nanoTime() - startNanos awaitWatchdogIdle() - /* 200ms delta */assertThat(TimeUnit.NANOSECONDS.toMillis(elapsedNanos).toDouble()) + // 200ms delta + assertThat(TimeUnit.NANOSECONDS.toMillis(elapsedNanos).toDouble()) .isCloseTo(500.0, 200.0) assertThat(connection.openStreamCount()).isEqualTo(0) @@ -1599,7 +1610,8 @@ class Http2ConnectionTest { } val elapsedNanos = System.nanoTime() - startNanos awaitWatchdogIdle() - /* 200ms delta */assertThat(TimeUnit.NANOSECONDS.toMillis(elapsedNanos).toDouble()) + // 200ms delta + assertThat(TimeUnit.NANOSECONDS.toMillis(elapsedNanos).toDouble()) .isCloseTo(500.0, 200.0) assertThat(connection.openStreamCount()).isEqualTo(0) @@ -1871,9 +1883,10 @@ class Http2ConnectionTest { peer.sendFrame().headers(false, 3, headerEntries("a", "android")) peer.acceptFrame() // GOAWAY peer.play() - val connection = Http2Connection.Builder(true, TaskRunner.INSTANCE) - .socket(peer.openSocket()) - .build() + val connection = + Http2Connection.Builder(true, TaskRunner.INSTANCE) + .socket(peer.openSocket()) + .build() connection.start(sendConnectionPreface = false) val stream = connection.newStream(headerEntries("b", "banana"), false) assertFailsWith { @@ -1895,10 +1908,11 @@ class Http2ConnectionTest { peer.play() val taskRunner = taskFaker.taskRunner val socket = peer.openSocket() - val connection = Http2Connection.Builder(true, taskRunner) - .socket(socket) - .pushObserver(IGNORE) - .build() + val connection = + Http2Connection.Builder(true, taskRunner) + .socket(socket) + .pushObserver(IGNORE) + .build() connection.start(sendConnectionPreface = false) val queues = taskRunner.activeQueues() assertThat(queues).hasSize(1) @@ -1906,7 +1920,10 @@ class Http2ConnectionTest { private fun data(byteCount: Int): Buffer = Buffer().write(ByteArray(byteCount)) - private fun assertStreamData(expected: String?, source: Source?) { + private fun assertStreamData( + expected: String?, + source: Source?, + ) { val actual = source!!.buffer().readUtf8() assertThat(actual).isEqualTo(expected) } @@ -1918,11 +1935,12 @@ class Http2ConnectionTest { */ private fun awaitWatchdogIdle() { val latch = CountDownLatch(1) - val watchdogJob: AsyncTimeout = object : AsyncTimeout() { - override fun timedOut() { - latch.countDown() + val watchdogJob: AsyncTimeout = + object : AsyncTimeout() { + override fun timedOut() { + latch.countDown() + } } - } watchdogJob.deadlineNanoTime(System.nanoTime()) // Due immediately! watchdogJob.enter() latch.await() @@ -1930,7 +1948,7 @@ class Http2ConnectionTest { private fun connectWithSettings( client: Boolean, - settings: Settings? + settings: Settings?, ): Http2Connection { peer.setClient(client) peer.sendFrame().settings(settings!!) @@ -1943,13 +1961,14 @@ class Http2ConnectionTest { private fun connect( peer: MockHttp2Peer, pushObserver: PushObserver = IGNORE, - listener: Http2Connection.Listener = Http2Connection.Listener.REFUSE_INCOMING_STREAMS + listener: Http2Connection.Listener = Http2Connection.Listener.REFUSE_INCOMING_STREAMS, ): Http2Connection { - val connection = Http2Connection.Builder(true, TaskRunner.INSTANCE) - .socket(peer.openSocket()) - .pushObserver(pushObserver) - .listener(listener) - .build() + val connection = + Http2Connection.Builder(true, TaskRunner.INSTANCE) + .socket(peer.openSocket()) + .pushObserver(pushObserver) + .listener(listener) + .build() connection.start(sendConnectionPreface = false) // verify the peer received the ACK @@ -1970,7 +1989,10 @@ class Http2ConnectionTest { return events.removeAt(0) } - @Synchronized override fun onRequest(streamId: Int, requestHeaders: List
): Boolean { + @Synchronized override fun onRequest( + streamId: Int, + requestHeaders: List
, + ): Boolean { assertThat(streamId).isEqualTo(2) events.add(requestHeaders) notifyAll() @@ -1978,7 +2000,9 @@ class Http2ConnectionTest { } @Synchronized override fun onHeaders( - streamId: Int, responseHeaders: List
, last: Boolean + streamId: Int, + responseHeaders: List
, + last: Boolean, ): Boolean { assertThat(streamId).isEqualTo(2) assertThat(last).isTrue() @@ -1988,39 +2012,58 @@ class Http2ConnectionTest { } @Synchronized override fun onData( - streamId: Int, source: BufferedSource, byteCount: Int, last: Boolean + streamId: Int, + source: BufferedSource, + byteCount: Int, + last: Boolean, ): Boolean { events.add(AssertionError("onData")) notifyAll() return false } - @Synchronized override fun onReset(streamId: Int, errorCode: ErrorCode) { + @Synchronized override fun onReset( + streamId: Int, + errorCode: ErrorCode, + ) { events.add(AssertionError("onReset")) notifyAll() } } companion object { - fun roundUp(num: Int, divisor: Int): Int = (num + divisor - 1) / divisor - - val IGNORE = object : PushObserver { - override fun onRequest(streamId: Int, requestHeaders: List
) = false - - override fun onHeaders( - streamId: Int, - responseHeaders: List
, - last: Boolean - ) = false - - override fun onData( - streamId: Int, source: BufferedSource, byteCount: Int, last: Boolean - ): Boolean { - source.skip(byteCount.toLong()) - return false + fun roundUp( + num: Int, + divisor: Int, + ): Int = (num + divisor - 1) / divisor + + val IGNORE = + object : PushObserver { + override fun onRequest( + streamId: Int, + requestHeaders: List
, + ) = false + + override fun onHeaders( + streamId: Int, + responseHeaders: List
, + last: Boolean, + ) = false + + override fun onData( + streamId: Int, + source: BufferedSource, + byteCount: Int, + last: Boolean, + ): Boolean { + source.skip(byteCount.toLong()) + return false + } + + override fun onReset( + streamId: Int, + errorCode: ErrorCode, + ) {} } - - override fun onReset(streamId: Int, errorCode: ErrorCode) {} - } } } diff --git a/okhttp/src/test/java/okhttp3/internal/http2/Http2Test.kt b/okhttp/src/test/java/okhttp3/internal/http2/Http2Test.kt index 4a05a6f07143..89442a5292b5 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/Http2Test.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/Http2Test.kt @@ -23,6 +23,7 @@ import java.io.IOException import java.util.Arrays import java.util.concurrent.atomic.AtomicInteger import kotlin.math.pow +import kotlin.test.assertFailsWith import okhttp3.TestUtil.headerEntries import okhttp3.internal.EMPTY_BYTE_ARRAY import okhttp3.internal.http2.Http2.FLAG_COMPRESSED @@ -40,8 +41,6 @@ import okio.ByteString.Companion.decodeHex import okio.ByteString.Companion.encodeUtf8 import okio.GzipSink import okio.buffer -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.Test class Http2Test { @@ -69,17 +68,22 @@ class Http2Test { // Check writer sends the same bytes. assertThat(sendHeaderFrames(true, sentHeaders)).isEqualTo(frame) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun headers( - inFinished: Boolean, streamId: Int, - associatedStreamId: Int, headerBlock: List
- ) { - assertThat(inFinished).isTrue() - assertThat(streamId).isEqualTo(expectedStreamId) - assertThat(associatedStreamId).isEqualTo(-1) - assertThat(headerBlock).isEqualTo(sentHeaders) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun headers( + inFinished: Boolean, + streamId: Int, + associatedStreamId: Int, + headerBlock: List
, + ) { + assertThat(inFinished).isTrue() + assertThat(streamId).isEqualTo(expectedStreamId) + assertThat(associatedStreamId).isEqualTo(-1) + assertThat(headerBlock).isEqualTo(sentHeaders) + } + }, + ) } @Test fun headersWithPriority() { @@ -92,28 +96,33 @@ class Http2Test { frame.writeInt(0) // Independent stream. frame.writeByte(255) // Heaviest weight, zero-indexed. frame.writeAll(headerBytes) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun priority( - streamId: Int, streamDependency: Int, weight: Int, - exclusive: Boolean - ) { - assertThat(streamDependency).isEqualTo(0) - assertThat(weight).isEqualTo(256) - assertThat(exclusive).isFalse() - } + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun priority( + streamId: Int, + streamDependency: Int, + weight: Int, + exclusive: Boolean, + ) { + assertThat(streamDependency).isEqualTo(0) + assertThat(weight).isEqualTo(256) + assertThat(exclusive).isFalse() + } - override fun headers( - inFinished: Boolean, - streamId: Int, - associatedStreamId: Int, - headerBlock: List
- ) { - assertThat(inFinished).isFalse() - assertThat(streamId).isEqualTo(expectedStreamId) - assertThat(associatedStreamId).isEqualTo(-1) - assertThat(headerBlock).isEqualTo(sentHeaders) - } - }) + override fun headers( + inFinished: Boolean, + streamId: Int, + associatedStreamId: Int, + headerBlock: List
, + ) { + assertThat(inFinished).isFalse() + assertThat(streamId).isEqualTo(expectedStreamId) + assertThat(associatedStreamId).isEqualTo(-1) + assertThat(headerBlock).isEqualTo(sentHeaders) + } + }, + ) } /** Headers are compressed, then framed. */ @@ -139,27 +148,33 @@ class Http2Test { assertThat(sendHeaderFrames(false, sentHeaders)).isEqualTo(frame) // Reading the above frames should result in a concatenated headerBlock. - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun headers( - inFinished: Boolean, streamId: Int, - associatedStreamId: Int, headerBlock: List
- ) { - assertThat(inFinished).isFalse() - assertThat(streamId).isEqualTo(expectedStreamId) - assertThat(associatedStreamId).isEqualTo(-1) - assertThat(headerBlock).isEqualTo(sentHeaders) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun headers( + inFinished: Boolean, + streamId: Int, + associatedStreamId: Int, + headerBlock: List
, + ) { + assertThat(inFinished).isFalse() + assertThat(streamId).isEqualTo(expectedStreamId) + assertThat(associatedStreamId).isEqualTo(-1) + assertThat(headerBlock).isEqualTo(sentHeaders) + } + }, + ) } @Test fun pushPromise() { val expectedPromisedStreamId = 11 - val pushPromise = listOf( - Header(Header.TARGET_METHOD, "GET"), - Header(Header.TARGET_SCHEME, "https"), - Header(Header.TARGET_AUTHORITY, "squareup.com"), - Header(Header.TARGET_PATH, "/") - ) + val pushPromise = + listOf( + Header(Header.TARGET_METHOD, "GET"), + Header(Header.TARGET_SCHEME, "https"), + Header(Header.TARGET_AUTHORITY, "squareup.com"), + Header(Header.TARGET_PATH, "/"), + ) // Write the push promise frame, specifying the associated stream ID. val headerBytes = literalHeaders(pushPromise) @@ -170,19 +185,22 @@ class Http2Test { frame.writeInt(expectedPromisedStreamId and 0x7fffffff) frame.writeAll(headerBytes) assertThat(sendPushPromiseFrames(expectedPromisedStreamId, pushPromise)).isEqualTo( - frame + frame, + ) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun pushPromise( + streamId: Int, + promisedStreamId: Int, + requestHeaders: List
, + ) { + assertThat(streamId).isEqualTo(expectedStreamId) + assertThat(promisedStreamId).isEqualTo(expectedPromisedStreamId) + assertThat(requestHeaders).isEqualTo(pushPromise) + } + }, ) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun pushPromise( - streamId: Int, - promisedStreamId: Int, - requestHeaders: List
- ) { - assertThat(streamId).isEqualTo(expectedStreamId) - assertThat(promisedStreamId).isEqualTo(expectedPromisedStreamId) - assertThat(requestHeaders).isEqualTo(pushPromise) - } - }) } /** Headers are compressed, then framed. */ @@ -208,21 +226,24 @@ class Http2Test { frame.writeInt(expectedStreamId and 0x7fffffff) frame.writeAll(headerBlock) assertThat(sendPushPromiseFrames(expectedPromisedStreamId, pushPromise)).isEqualTo( - frame + frame, ) // Reading the above frames should result in a concatenated headerBlock. - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun pushPromise( - streamId: Int, - promisedStreamId: Int, - requestHeaders: List
- ) { - assertThat(streamId).isEqualTo(expectedStreamId) - assertThat(promisedStreamId).isEqualTo(expectedPromisedStreamId) - assertThat(requestHeaders).isEqualTo(pushPromise) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun pushPromise( + streamId: Int, + promisedStreamId: Int, + requestHeaders: List
, + ) { + assertThat(streamId).isEqualTo(expectedStreamId) + assertThat(promisedStreamId).isEqualTo(expectedPromisedStreamId) + assertThat(requestHeaders).isEqualTo(pushPromise) + } + }, + ) } @Test fun readRstStreamFrame() { @@ -231,12 +252,18 @@ class Http2Test { frame.writeByte(FLAG_NONE) frame.writeInt(expectedStreamId and 0x7fffffff) frame.writeInt(ErrorCode.PROTOCOL_ERROR.httpCode) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun rstStream(streamId: Int, errorCode: ErrorCode) { - assertThat(streamId).isEqualTo(expectedStreamId) - assertThat(errorCode).isEqualTo(ErrorCode.PROTOCOL_ERROR) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun rstStream( + streamId: Int, + errorCode: ErrorCode, + ) { + assertThat(streamId).isEqualTo(expectedStreamId) + assertThat(errorCode).isEqualTo(ErrorCode.PROTOCOL_ERROR) + } + }, + ) } @Test fun readSettingsFrame() { @@ -249,14 +276,20 @@ class Http2Test { frame.writeInt(reducedTableSizeBytes) frame.writeShort(2) // SETTINGS_ENABLE_PUSH frame.writeInt(0) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun settings(clearPrevious: Boolean, settings: Settings) { - // No clearPrevious in HTTP/2. - assertThat(clearPrevious).isFalse() - assertThat(settings.headerTableSize).isEqualTo(reducedTableSizeBytes) - assertThat(settings.getEnablePush(true)).isFalse() - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun settings( + clearPrevious: Boolean, + settings: Settings, + ) { + // No clearPrevious in HTTP/2. + assertThat(clearPrevious).isFalse() + assertThat(settings.headerTableSize).isEqualTo(reducedTableSizeBytes) + assertThat(settings.getEnablePush(true)).isFalse() + } + }, + ) } @Test fun readSettingsFrameInvalidPushValue() { @@ -281,11 +314,17 @@ class Http2Test { frame.writeShort(7) // old number for SETTINGS_INITIAL_WINDOW_SIZE frame.writeInt(1) val settingValue = AtomicInteger() - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun settings(clearPrevious: Boolean, settings: Settings) { - settingValue.set(settings[7]) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun settings( + clearPrevious: Boolean, + settings: Settings, + ) { + settingValue.set(settings[7]) + } + }, + ) assertThat(1).isEqualTo(settingValue.toInt()) } @@ -296,11 +335,17 @@ class Http2Test { frame.writeInt(0) // Settings are always on the connection stream 0. frame.write("f000".decodeHex()) // Id reserved for experimental use. frame.writeInt(1) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun settings(clearPrevious: Boolean, settings: Settings) { - // no-op - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun settings( + clearPrevious: Boolean, + settings: Settings, + ) { + // no-op + } + }, + ) } @Test fun readSettingsFrameNegativeWindowSize() { @@ -314,7 +359,7 @@ class Http2Test { reader.nextFrame(requireSettings = false, BaseTestHandler()) }.also { expected -> assertThat(expected.message).isEqualTo( - "PROTOCOL_ERROR SETTINGS_INITIAL_WINDOW_SIZE > 2^31 - 1" + "PROTOCOL_ERROR SETTINGS_INITIAL_WINDOW_SIZE > 2^31 - 1", ) } } @@ -330,7 +375,7 @@ class Http2Test { reader.nextFrame(requireSettings = false, BaseTestHandler()) }.also { expected -> assertThat(expected.message).isEqualTo( - "PROTOCOL_ERROR SETTINGS_MAX_FRAME_SIZE: -2147483648" + "PROTOCOL_ERROR SETTINGS_MAX_FRAME_SIZE: -2147483648", ) } } @@ -375,13 +420,20 @@ class Http2Test { // Check writer sends the same bytes. assertThat(sendPingFrame(true, expectedPayload1, expectedPayload2)).isEqualTo(frame) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun ping(ack: Boolean, payload1: Int, payload2: Int) { - assertThat(ack).isTrue() - assertThat(payload1).isEqualTo(expectedPayload1) - assertThat(payload2).isEqualTo(expectedPayload2) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun ping( + ack: Boolean, + payload1: Int, + payload2: Int, + ) { + assertThat(ack).isTrue() + assertThat(payload1).isEqualTo(expectedPayload1) + assertThat(payload2).isEqualTo(expectedPayload2) + } + }, + ) } @Test fun maxLengthDataFrame() { @@ -395,17 +447,25 @@ class Http2Test { // Check writer sends the same bytes. assertThat(sendDataFrame(Buffer().write(expectedData))).isEqualTo(frame) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun data(inFinished: Boolean, streamId: Int, source: BufferedSource, length: Int) { - assertThat(inFinished).isFalse() - assertThat(streamId).isEqualTo(expectedStreamId) - assertThat(length).isEqualTo(Http2.INITIAL_MAX_FRAME_SIZE) - val data = source.readByteString(length.toLong()) - for (b in data.toByteArray()) { - assertThat(b).isEqualTo(2.toByte()) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun data( + inFinished: Boolean, + streamId: Int, + source: BufferedSource, + length: Int, + ) { + assertThat(inFinished).isFalse() + assertThat(streamId).isEqualTo(expectedStreamId) + assertThat(length).isEqualTo(Http2.INITIAL_MAX_FRAME_SIZE) + val data = source.readByteString(length.toLong()) + for (b in data.toByteArray()) { + assertThat(b).isEqualTo(2.toByte()) + } } - } - }) + }, + ) } @Test fun dataFrameNotAssociateWithStream() { @@ -547,12 +607,18 @@ class Http2Test { // Check writer sends the same bytes. assertThat(windowUpdate(expectedWindowSizeIncrement)).isEqualTo(frame) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun windowUpdate(streamId: Int, windowSizeIncrement: Long) { - assertThat(streamId).isEqualTo(expectedStreamId) - assertThat(windowSizeIncrement).isEqualTo(expectedWindowSizeIncrement) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun windowUpdate( + streamId: Int, + windowSizeIncrement: Long, + ) { + assertThat(streamId).isEqualTo(expectedStreamId) + assertThat(windowSizeIncrement).isEqualTo(expectedWindowSizeIncrement) + } + }, + ) } @Test fun badWindowSizeIncrement() { @@ -582,15 +648,20 @@ class Http2Test { // Check writer sends the same bytes. assertThat(sendGoAway(expectedStreamId, expectedError, EMPTY_BYTE_ARRAY)) .isEqualTo(frame) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun goAway( - lastGoodStreamId: Int, errorCode: ErrorCode, debugData: ByteString - ) { - assertThat(lastGoodStreamId).isEqualTo(expectedStreamId) - assertThat(errorCode).isEqualTo(expectedError) - assertThat(debugData.size).isEqualTo(0) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun goAway( + lastGoodStreamId: Int, + errorCode: ErrorCode, + debugData: ByteString, + ) { + assertThat(lastGoodStreamId).isEqualTo(expectedStreamId) + assertThat(errorCode).isEqualTo(expectedError) + assertThat(debugData.size).isEqualTo(0) + } + }, + ) } @Test fun goAwayWithDebugDataRoundTrip() { @@ -608,15 +679,20 @@ class Http2Test { // Check writer sends the same bytes. assertThat(sendGoAway(0, expectedError, expectedData.toByteArray())).isEqualTo(frame) - reader.nextFrame(requireSettings = false, object : BaseTestHandler() { - override fun goAway( - lastGoodStreamId: Int, errorCode: ErrorCode, debugData: ByteString - ) { - assertThat(lastGoodStreamId).isEqualTo(0) - assertThat(errorCode).isEqualTo(expectedError) - assertThat(debugData).isEqualTo(expectedData) - } - }) + reader.nextFrame( + requireSettings = false, + object : BaseTestHandler() { + override fun goAway( + lastGoodStreamId: Int, + errorCode: ErrorCode, + debugData: ByteString, + ) { + assertThat(lastGoodStreamId).isEqualTo(0) + assertThat(errorCode).isEqualTo(expectedError) + assertThat(debugData).isEqualTo(expectedData) + } + }, + ) } @Test fun frameSizeError() { @@ -656,7 +732,7 @@ class Http2Test { private fun sendHeaderFrames( outFinished: Boolean, - headers: List
+ headers: List
, ): Buffer { val out = Buffer() Http2Writer(out, true).headers(outFinished, expectedStreamId, headers) @@ -665,7 +741,7 @@ class Http2Test { private fun sendPushPromiseFrames( streamId: Int, - headers: List
+ headers: List
, ): Buffer { val out = Buffer() Http2Writer(out, true).pushPromise(expectedStreamId, streamId, headers) @@ -675,7 +751,7 @@ class Http2Test { private fun sendPingFrame( ack: Boolean, payload1: Int, - payload2: Int + payload2: Int, ): Buffer { val out = Buffer() Http2Writer(out, true).ping(ack, payload1, payload2) @@ -685,7 +761,7 @@ class Http2Test { private fun sendGoAway( lastGoodStreamId: Int, errorCode: ErrorCode, - debugData: ByteArray + debugData: ByteArray, ): Buffer { val out = Buffer() Http2Writer(out, true).goAway(lastGoodStreamId, errorCode, debugData) @@ -710,7 +786,7 @@ class Http2Test { inFinished: Boolean, streamId: Int, associatedStreamId: Int, - headerBlock: List
+ headerBlock: List
, ) { assertThat(inFinished).isFalse() assertThat(streamId).isEqualTo(expectedStreamId) @@ -722,7 +798,12 @@ class Http2Test { private fun assertData(): Http2Reader.Handler { return object : BaseTestHandler() { - override fun data(inFinished: Boolean, streamId: Int, source: BufferedSource, length: Int) { + override fun data( + inFinished: Boolean, + streamId: Int, + source: BufferedSource, + length: Int, + ) { assertThat(inFinished).isFalse() assertThat(streamId).isEqualTo(expectedStreamId) assertThat(length).isEqualTo(1123) @@ -754,7 +835,10 @@ class Http2Test { return headerEntries(*nameValues) } - private fun writeMedium(sink: BufferedSink, i: Int) { + private fun writeMedium( + sink: BufferedSink, + i: Int, + ) { sink.writeByte(i ushr 16 and 0xff) sink.writeByte(i ushr 8 and 0xff) sink.writeByte(i and 0xff) diff --git a/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt b/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt index 3390ed743ca5..2b788c07580f 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt @@ -21,7 +21,6 @@ import assertk.assertions.hasMessage import assertk.assertions.isCloseTo import assertk.assertions.isEqualTo import assertk.assertions.isFalse -import assertk.assertions.isIn import assertk.assertions.isNull import assertk.assertions.isTrue import assertk.fail @@ -88,7 +87,6 @@ import okio.Buffer import okio.BufferedSink import okio.GzipSink import okio.buffer -import org.bouncycastle.tls.TlsFatalAlert import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertArrayEquals import org.junit.jupiter.api.Assumptions.assumeTrue @@ -138,27 +136,32 @@ class HttpOverHttp2Test { return clientTestRule } - fun setUp(protocol: Protocol, server: MockWebServer) { + fun setUp( + protocol: Protocol, + server: MockWebServer, + ) { this.server = server this.protocol = protocol platform.assumeNotOpenJSSE() if (protocol === Protocol.HTTP_2) { platform.assumeHttp2Support() server.useHttps(handshakeCertificates.sslSocketFactory()) - client = clientTestRule.newClientBuilder() - .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)) - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), - handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + clientTestRule.newClientBuilder() + .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)) + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() scheme = "https" } else { server.protocols = listOf(Protocol.H2_PRIOR_KNOWLEDGE) - client = clientTestRule.newClientBuilder() - .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) - .build() + client = + clientTestRule.newClientBuilder() + .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) + .build() scheme = "http" } cache = Cache(tempDir, Int.MAX_VALUE.toLong()) @@ -170,7 +173,10 @@ class HttpOverHttp2Test { @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun get(protocol: Protocol, mockWebServer: MockWebServer) { + fun get( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(body = "ABCDE")) val call = client.newCall(Request(server.url("/foo"))) @@ -181,17 +187,22 @@ class HttpOverHttp2Test { assertThat(response.protocol).isEqualTo(protocol) val request = server.takeRequest() assertThat(request.requestLine).isEqualTo("GET /foo HTTP/1.1") - assertThat(request.headers[":scheme"]).isEqualTo(scheme) - assertThat(request.headers[":authority"]).isEqualTo("${server.hostName}:${server.port}") + assertThat(request.headers[":scheme"]).isEqualTo(scheme) + assertThat(request.headers[":authority"]).isEqualTo("${server.hostName}:${server.port}") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun get204Response(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun get204Response( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - val responseWithoutBody = MockResponse.Builder() - .status("HTTP/1.1 204") - .removeHeader("Content-Length") - .build() + val responseWithoutBody = + MockResponse.Builder() + .status("HTTP/1.1 204") + .removeHeader("Content-Length") + .build() server.enqueue(responseWithoutBody) val call = client.newCall(Request(server.url("/foo"))) val response = call.execute() @@ -207,20 +218,26 @@ class HttpOverHttp2Test { assertThat(request.requestLine).isEqualTo("GET /foo HTTP/1.1") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun head(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun head( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - val mockResponse = MockResponse.Builder() - .setHeader("Content-Length", 5) - .status("HTTP/1.1 200") - .build() - server.enqueue(mockResponse) - val call = client.newCall( - Request.Builder() - .head() - .url(server.url("/foo")) + val mockResponse = + MockResponse.Builder() + .setHeader("Content-Length", 5) + .status("HTTP/1.1 200") .build() - ) + server.enqueue(mockResponse) + val call = + client.newCall( + Request.Builder() + .head() + .url(server.url("/foo")) + .build(), + ) val response = call.execute() // Body contains nothing. @@ -233,8 +250,12 @@ class HttpOverHttp2Test { assertThat(request.requestLine).isEqualTo("HEAD /foo HTTP/1.1") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun emptyResponse(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun emptyResponse( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse()) val call = client.newCall(Request(server.url("/foo"))) @@ -243,50 +264,62 @@ class HttpOverHttp2Test { response.body.close() } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun noDefaultContentLengthOnStreamingPost(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun noDefaultContentLengthOnStreamingPost( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) val postBytes = "FGHIJ".toByteArray() server.enqueue(MockResponse(body = "ABCDE")) - val call = client.newCall( - Request( - url = server.url("/foo"), - body = object : RequestBody() { - override fun contentType(): MediaType = "text/plain; charset=utf-8".toMediaType() - - override fun writeTo(sink: BufferedSink) { - sink.write(postBytes) - } - }, + val call = + client.newCall( + Request( + url = server.url("/foo"), + body = + object : RequestBody() { + override fun contentType(): MediaType = "text/plain; charset=utf-8".toMediaType() + + override fun writeTo(sink: BufferedSink) { + sink.write(postBytes) + } + }, + ), ) - ) val response = call.execute() assertThat(response.body.string()).isEqualTo("ABCDE") val request = server.takeRequest() assertThat(request.requestLine).isEqualTo("POST /foo HTTP/1.1") assertArrayEquals(postBytes, request.body.readByteArray()) - assertThat(request.headers["Content-Length"]).isNull() + assertThat(request.headers["Content-Length"]).isNull() } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun userSuppliedContentLengthHeader(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun userSuppliedContentLengthHeader( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) val postBytes = "FGHIJ".toByteArray() server.enqueue(MockResponse(body = "ABCDE")) - val call = client.newCall( - Request( - url = server.url("/foo"), - body = object : RequestBody() { - override fun contentType(): MediaType = "text/plain; charset=utf-8".toMediaType() - - override fun contentLength(): Long = postBytes.size.toLong() - - override fun writeTo(sink: BufferedSink) { - sink.write(postBytes) - } - }, + val call = + client.newCall( + Request( + url = server.url("/foo"), + body = + object : RequestBody() { + override fun contentType(): MediaType = "text/plain; charset=utf-8".toMediaType() + + override fun contentLength(): Long = postBytes.size.toLong() + + override fun writeTo(sink: BufferedSink) { + sink.write(postBytes) + } + }, + ), ) - ) val response = call.execute() assertThat(response.body.string()).isEqualTo("ABCDE") val request = server.takeRequest() @@ -295,29 +328,33 @@ class HttpOverHttp2Test { assertThat(request.headers["Content-Length"]!!.toInt()).isEqualTo(postBytes.size) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun closeAfterFlush( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) val postBytes = "FGHIJ".toByteArray() server.enqueue(MockResponse(body = "ABCDE")) - val call = client.newCall( - Request( - url = server.url("/foo"), - body = object : RequestBody() { - override fun contentType(): MediaType = "text/plain; charset=utf-8".toMediaType() - - override fun contentLength(): Long = postBytes.size.toLong() - - override fun writeTo(sink: BufferedSink) { - sink.write(postBytes) // push bytes into the stream's buffer - sink.flush() // Http2Connection.writeData subject to write window - sink.close() // Http2Connection.writeData empty frame - } - }, + val call = + client.newCall( + Request( + url = server.url("/foo"), + body = + object : RequestBody() { + override fun contentType(): MediaType = "text/plain; charset=utf-8".toMediaType() + + override fun contentLength(): Long = postBytes.size.toLong() + + override fun writeTo(sink: BufferedSink) { + sink.write(postBytes) // push bytes into the stream's buffer + sink.flush() // Http2Connection.writeData subject to write window + sink.close() // Http2Connection.writeData empty frame + } + }, + ), ) - ) val response = call.execute() assertThat(response.body.string()).isEqualTo("ABCDE") val request = server.takeRequest() @@ -326,8 +363,12 @@ class HttpOverHttp2Test { assertThat(request.headers["Content-Length"]!!.toInt()).isEqualTo(postBytes.size) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun connectionReuse(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun connectionReuse( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(body = "ABCDEF")) server.enqueue(MockResponse(body = "GHIJKL")) @@ -345,16 +386,20 @@ class HttpOverHttp2Test { response2.close() } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun connectionWindowUpdateAfterCanceling(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun connectionWindowUpdateAfterCanceling( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse.Builder() .body(Buffer().write(ByteArray(Http2Connection.OKHTTP_CLIENT_WINDOW_SIZE + 1))) - .build() + .build(), ) server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) val call1 = client.newCall(Request(server.url("/"))) val response1 = call1.execute() @@ -365,7 +410,7 @@ class HttpOverHttp2Test { call1.cancel() assertThat( response1.body.source().discard(1, TimeUnit.SECONDS), - "Call should not have completed successfully." + "Call should not have completed successfully.", ).isFalse() val call2 = client.newCall(Request(server.url("/"))) val response2 = call2.execute() @@ -384,20 +429,24 @@ class HttpOverHttp2Test { } } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun connectionWindowUpdateOnClose(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun connectionWindowUpdateOnClose( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse.Builder() .body(Buffer().write(ByteArray(Http2Connection.OKHTTP_CLIENT_WINDOW_SIZE + 1))) - .build() + .build(), ) server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) // Enqueue an additional response that show if we burnt a good prior response. server.enqueue( - MockResponse(body = "XXX") + MockResponse(body = "XXX"), ) val call1 = client.newCall(Request(server.url("/"))) val response1 = call1.execute() @@ -412,24 +461,26 @@ class HttpOverHttp2Test { assertThat(response2.body.string()).isEqualTo("abc") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun concurrentRequestWithEmptyFlowControlWindow( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse.Builder() .body(Buffer().write(ByteArray(Http2Connection.OKHTTP_CLIENT_WINDOW_SIZE))) - .build() + .build(), ) server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) val call1 = client.newCall(Request(server.url("/"))) val response1 = call1.execute() waitForDataFrames(Http2Connection.OKHTTP_CLIENT_WINDOW_SIZE) assertThat(response1.body.contentLength()).isEqualTo( - Http2Connection.OKHTTP_CLIENT_WINDOW_SIZE.toLong() + Http2Connection.OKHTTP_CLIENT_WINDOW_SIZE.toLong(), ) val read = response1.body.source().read(ByteArray(8192)) assertThat(read).isEqualTo(8192) @@ -447,9 +498,13 @@ class HttpOverHttp2Test { } /** https://github.com/square/okhttp/issues/373 */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) @Disabled - fun synchronousRequest(protocol: Protocol, mockWebServer: MockWebServer) { + fun synchronousRequest( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(body = "A")) server.enqueue(MockResponse(body = "A")) @@ -462,56 +517,69 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun gzippedResponseBody(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun gzippedResponseBody( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse.Builder() .addHeader("Content-Encoding: gzip") .body(gzip("ABCABCABC")) - .build() + .build(), ) val call = client.newCall(Request(server.url("/r1"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("ABCABCABC") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun authenticate(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun authenticate( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse( code = HttpURLConnection.HTTP_UNAUTHORIZED, headers = headersOf("www-authenticate", "Basic realm=\"protected area\""), body = "Please authenticate.", - ) + ), ) server.enqueue( - MockResponse(body = "Successful auth!") + MockResponse(body = "Successful auth!"), ) val credential = basic("username", "password") - client = client.newBuilder() - .authenticator(RecordingOkAuthenticator(credential, "Basic")) - .build() + client = + client.newBuilder() + .authenticator(RecordingOkAuthenticator(credential, "Basic")) + .build() val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("Successful auth!") val denied = server.takeRequest() - assertThat(denied.headers["Authorization"]).isNull() + assertThat(denied.headers["Authorization"]).isNull() val accepted = server.takeRequest() assertThat(accepted.requestLine).isEqualTo("GET / HTTP/1.1") - assertThat(accepted.headers["Authorization"]).isEqualTo(credential) + assertThat(accepted.headers["Authorization"]).isEqualTo(credential) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun redirect(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun redirect( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse( code = HttpURLConnection.HTTP_MOVED_TEMP, headers = headersOf("Location", "/foo"), body = "This page has moved!", - ) + ), ) server.enqueue(MockResponse(body = "This is the new location!")) val call = client.newCall(Request(server.url("/"))) @@ -523,8 +591,12 @@ class HttpOverHttp2Test { assertThat(request2.path).isEqualTo("/foo") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun readAfterLastByte(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun readAfterLastByte( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(body = "ABC")) val call = client.newCall(Request(server.url("/"))) @@ -538,14 +610,19 @@ class HttpOverHttp2Test { inputStream.close() } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun readResponseHeaderTimeout(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun readResponseHeaderTimeout( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(socketPolicy = NoResponse)) server.enqueue(MockResponse(body = "A")) - client = client.newBuilder() - .readTimeout(Duration.ofSeconds(1)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofSeconds(1)) + .build() // Make a call expecting a timeout reading the response headers. val call1 = client.newCall(Request(server.url("/"))) @@ -570,8 +647,12 @@ class HttpOverHttp2Test { * case, we take a 4KiB body and throttle it to 1KiB/second. We set the read timeout to two * seconds. If our implementation is acting correctly, it will not throw, as it is progressing. */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun readTimeoutMoreGranularThanBodySize(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun readTimeoutMoreGranularThanBodySize( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) val body = CharArray(4096) // 4KiB to read. Arrays.fill(body, 'y') @@ -579,11 +660,12 @@ class HttpOverHttp2Test { MockResponse.Builder() .body(String(body)) .throttleBody(1024, 1, TimeUnit.SECONDS) // Slow connection 1KiB/second. - .build() + .build(), ) - client = client.newBuilder() - .readTimeout(Duration.ofSeconds(2)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofSeconds(2)) + .build() val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo(String(body)) @@ -595,22 +677,27 @@ class HttpOverHttp2Test { * second. If our implementation is acting correctly, it will throw, as a byte doesn't arrive in * time. */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun readTimeoutOnSlowConnection(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun readTimeoutOnSlowConnection( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) val body = repeat('y', 2048) server.enqueue( MockResponse.Builder() .body(body) .throttleBody(1024, 1, TimeUnit.SECONDS) - .build() + .build(), ) // Slow connection 1KiB/second. server.enqueue( - MockResponse(body = body) + MockResponse(body = body), ) - client = client.newBuilder() - .readTimeout(Duration.ofMillis(500)) // Half a second to read something. - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofMillis(500)) // Half a second to read something. + .build() // Make a call expecting a timeout reading the response body. val call1 = client.newCall(Request(server.url("/"))) @@ -631,33 +718,41 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun connectionTimeout(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun connectionTimeout( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse.Builder() .body("A") .bodyDelay(1, TimeUnit.SECONDS) - .build() + .build(), ) - val client1 = client.newBuilder() - .readTimeout(Duration.ofSeconds(2)) - .build() - val call1 = client1 - .newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) - val client2 = client.newBuilder() - .readTimeout(Duration.ofMillis(200)) - .build() - val call2 = client2 - .newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) + val client1 = + client.newBuilder() + .readTimeout(Duration.ofSeconds(2)) + .build() + val call1 = + client1 + .newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) + val client2 = + client.newBuilder() + .readTimeout(Duration.ofMillis(200)) + .build() + val call2 = + client2 + .newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response1 = call1.execute() assertThat(response1.body.string()).isEqualTo("A") assertFailsWith { @@ -669,17 +764,22 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun responsesAreCached(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun responsesAreCached( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() server.enqueue( MockResponse( headers = headersOf("cache-control", "max-age=60"), body = "A", - ) + ), ) val call1 = client.newCall(Request(server.url("/"))) val response1 = call1.execute() @@ -698,20 +798,25 @@ class HttpOverHttp2Test { assertThat(cache.hitCount()).isEqualTo(2) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun conditionalCache(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun conditionalCache( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() server.enqueue( MockResponse( headers = headersOf("ETag", "v1"), body = "A", - ) + ), ) server.enqueue( - MockResponse(code = HttpURLConnection.HTTP_NOT_MODIFIED) + MockResponse(code = HttpURLConnection.HTTP_NOT_MODIFIED), ) val call1 = client.newCall(Request(server.url("/"))) val response1 = call1.execute() @@ -727,23 +832,28 @@ class HttpOverHttp2Test { assertThat(cache.hitCount()).isEqualTo(1) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun responseCachedWithoutConsumingFullBody(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun responseCachedWithoutConsumingFullBody( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - client = client.newBuilder() - .cache(cache) - .build() + client = + client.newBuilder() + .cache(cache) + .build() server.enqueue( MockResponse( headers = headersOf("cache-control", "max-age=60"), body = "ABCD", - ) + ), ) server.enqueue( MockResponse( headers = headersOf("cache-control", "max-age=60"), body = "EFGH", - ) + ), ) val call1 = client.newCall(Request(server.url("/"))) val response1 = call1.execute() @@ -755,36 +865,47 @@ class HttpOverHttp2Test { response2.body.close() } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun sendRequestCookies(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun sendRequestCookies( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) val cookieJar = RecordingCookieJar() - val requestCookie = Cookie.Builder() - .name("a") - .value("b") - .domain(server.hostName) - .build() + val requestCookie = + Cookie.Builder() + .name("a") + .value("b") + .domain(server.hostName) + .build() cookieJar.enqueueRequestCookies(requestCookie) - client = client.newBuilder() - .cookieJar(cookieJar) - .build() + client = + client.newBuilder() + .cookieJar(cookieJar) + .build() server.enqueue(MockResponse()) val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("") val request = server.takeRequest() - assertThat(request.headers["Cookie"]).isEqualTo("a=b") + assertThat(request.headers["Cookie"]).isEqualTo("a=b") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun receiveResponseCookies(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun receiveResponseCookies( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) val cookieJar = RecordingCookieJar() - client = client.newBuilder() - .cookieJar(cookieJar) - .build() + client = + client.newBuilder() + .cookieJar(cookieJar) + .build() server.enqueue( - MockResponse(headers = headersOf("set-cookie", "a=b")) + MockResponse(headers = headersOf("set-cookie", "a=b")), ) val call = client.newCall(Request(server.url("/"))) val response = call.execute() @@ -792,8 +913,12 @@ class HttpOverHttp2Test { cookieJar.assertResponseCookies("a=b; path=/") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun cancelWithStreamNotCompleted(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun cancelWithStreamNotCompleted( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(body = "abc")) server.enqueue(MockResponse(body = "def")) @@ -814,13 +939,15 @@ class HttpOverHttp2Test { response.close() } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun noRecoveryFromOneRefusedStream( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue(MockResponse(body = "abc")) val call = client.newCall(Request(server.url("/"))) @@ -831,16 +958,19 @@ class HttpOverHttp2Test { } } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun recoverFromRefusedStreamWhenAnotherRouteExists( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) // Two routes! - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) // Two routes! + .build() server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue(MockResponse(body = "abc")) @@ -855,22 +985,25 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun noRecoveryWhenRoutesExhausted( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) // Two routes! - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) // Two routes! + .build() server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) val request = Request(server.url("/")) @@ -884,13 +1017,15 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) // New connection. } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun connectionWithOneRefusedStreamIsPooled( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue(MockResponse(body = "abc")) val request = Request(server.url("/")) @@ -909,16 +1044,18 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun connectionWithTwoRefusedStreamsIsNotPooled( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue(MockResponse(body = "abc")) server.enqueue(MockResponse(body = "def")) @@ -950,17 +1087,21 @@ class HttpOverHttp2Test { * errors. The problem was that the logic that decided whether to reuse a route didn't track * certain HTTP/2 errors. https://github.com/square/okhttp/issues/5547 */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun noRecoveryFromTwoRefusedStreams(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun noRecoveryFromTwoRefusedStreams( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue( - MockResponse(body = "abc") + MockResponse(body = "abc"), ) val call = client.newCall(Request(server.url("/"))) assertFailsWith { @@ -970,17 +1111,21 @@ class HttpOverHttp2Test { } } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun recoverFromOneInternalErrorRequiresNewConnection( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) recoverFromOneHttp2ErrorRequiresNewConnection(ErrorCode.INTERNAL_ERROR) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun recoverFromOneCancelRequiresNewConnection( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) recoverFromOneHttp2ErrorRequiresNewConnection(ErrorCode.CANCEL) @@ -988,12 +1133,13 @@ class HttpOverHttp2Test { private fun recoverFromOneHttp2ErrorRequiresNewConnection(errorCode: ErrorCode?) { server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(errorCode!!.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(errorCode!!.httpCode)), ) server.enqueue(MockResponse(body = "abc")) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("abc") @@ -1004,21 +1150,24 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun recoverFromMultipleRefusedStreamsRequiresNewConnection( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.REFUSED_STREAM.httpCode)), ) server.enqueue(MockResponse(body = "abc")) - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("abc") @@ -1031,32 +1180,39 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun recoverFromCancelReusesConnection(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun recoverFromCancelReusesConnection( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - val responseDequeuedLatches = listOf( - // No synchronization for the last request, which is not canceled: - CountDownLatch(1), - CountDownLatch(0) - ) - val requestCanceledLatches = listOf( - CountDownLatch(1), - CountDownLatch(0) - ) + val responseDequeuedLatches = + listOf( + // No synchronization for the last request, which is not canceled: + CountDownLatch(1), + CountDownLatch(0), + ) + val requestCanceledLatches = + listOf( + CountDownLatch(1), + CountDownLatch(0), + ) val dispatcher = RespondAfterCancelDispatcher(responseDequeuedLatches, requestCanceledLatches) dispatcher.enqueueResponse( MockResponse.Builder() .bodyDelay(10, TimeUnit.SECONDS) .body("abc") - .build() + .build(), ) dispatcher.enqueueResponse( - MockResponse(body = "def") + MockResponse(body = "def"), ) server.dispatcher = dispatcher - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() callAndCancel(0, responseDequeuedLatches[0], requestCanceledLatches[0]) // Make a second request to ensure the connection is reused. @@ -1066,40 +1222,47 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(1) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun recoverFromMultipleCancelReusesConnection(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun recoverFromMultipleCancelReusesConnection( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - val responseDequeuedLatches = Arrays.asList( - CountDownLatch(1), - // No synchronization for the last request, which is not canceled: - CountDownLatch(1), - CountDownLatch(0) - ) - val requestCanceledLatches = Arrays.asList( - CountDownLatch(1), - CountDownLatch(1), - CountDownLatch(0) - ) + val responseDequeuedLatches = + Arrays.asList( + CountDownLatch(1), + // No synchronization for the last request, which is not canceled: + CountDownLatch(1), + CountDownLatch(0), + ) + val requestCanceledLatches = + Arrays.asList( + CountDownLatch(1), + CountDownLatch(1), + CountDownLatch(0), + ) val dispatcher = RespondAfterCancelDispatcher(responseDequeuedLatches, requestCanceledLatches) dispatcher.enqueueResponse( MockResponse.Builder() .bodyDelay(10, TimeUnit.SECONDS) .body("abc") - .build() + .build(), ) dispatcher.enqueueResponse( MockResponse.Builder() .bodyDelay(10, TimeUnit.SECONDS) .body("def") - .build() + .build(), ) dispatcher.enqueueResponse( - MockResponse(body = "ghi") + MockResponse(body = "ghi"), ) server.dispatcher = dispatcher - client = client.newBuilder() - .dns(DoubleInetAddressDns()) - .build() + client = + client.newBuilder() + .dns(DoubleInetAddressDns()) + .build() callAndCancel(0, responseDequeuedLatches[0], requestCanceledLatches[0]) callAndCancel(1, responseDequeuedLatches[1], requestCanceledLatches[1]) @@ -1112,7 +1275,7 @@ class HttpOverHttp2Test { private class RespondAfterCancelDispatcher( private val responseDequeuedLatches: List, - private val requestCanceledLatches: List + private val requestCanceledLatches: List, ) : QueueDispatcher() { private var responseIndex = 0 @@ -1136,19 +1299,27 @@ class HttpOverHttp2Test { private fun callAndCancel( expectedSequenceNumber: Int, responseDequeuedLatch: CountDownLatch?, - requestCanceledLatch: CountDownLatch? + requestCanceledLatch: CountDownLatch?, ) { val call = client.newCall(Request(server.url("/"))) val latch = CountDownLatch(1) - call.enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - latch.countDown() - } + call.enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + latch.countDown() + } - override fun onResponse(call: Call, response: Response) { - fail("") - } - }) + override fun onResponse( + call: Call, + response: Response, + ) { + fail("") + } + }, + ) assertThat(server.takeRequest().sequenceNumber) .isEqualTo(expectedSequenceNumber) responseDequeuedLatch!!.await() @@ -1157,25 +1328,31 @@ class HttpOverHttp2Test { latch.await() } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun noRecoveryFromRefusedStreamWithRetryDisabled( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) noRecoveryFromErrorWithRetryDisabled(ErrorCode.REFUSED_STREAM) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun noRecoveryFromInternalErrorWithRetryDisabled( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) noRecoveryFromErrorWithRetryDisabled(ErrorCode.INTERNAL_ERROR) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun noRecoveryFromCancelWithRetryDisabled( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) noRecoveryFromErrorWithRetryDisabled(ErrorCode.CANCEL) @@ -1183,12 +1360,13 @@ class HttpOverHttp2Test { private fun noRecoveryFromErrorWithRetryDisabled(errorCode: ErrorCode?) { server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(errorCode!!.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(errorCode!!.httpCode)), ) server.enqueue(MockResponse(body = "abc")) - client = client.newBuilder() - .retryOnConnectionFailure(false) - .build() + client = + client.newBuilder() + .retryOnConnectionFailure(false) + .build() val call = client.newCall(Request(server.url("/"))) assertFailsWith { call.execute() @@ -1197,46 +1375,57 @@ class HttpOverHttp2Test { } } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun recoverFromConnectionNoNewStreamsOnFollowUp( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(code = 401)) server.enqueue( - MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.INTERNAL_ERROR.httpCode)) + MockResponse(socketPolicy = ResetStreamAtStart(ErrorCode.INTERNAL_ERROR.httpCode)), ) server.enqueue(MockResponse(body = "DEF")) server.enqueue( MockResponse( code = 301, - headers = headersOf("Location", "/foo") - ) + headers = headersOf("Location", "/foo"), + ), ) server.enqueue(MockResponse(body = "ABC")) val latch = CountDownLatch(1) val responses: BlockingQueue = SynchronousQueue() - val authenticator = okhttp3.Authenticator { route: Route?, response: Response? -> - responses.offer(response!!.body.string()) - try { - latch.await() - } catch (e: InterruptedException) { - throw AssertionError() - } - response.request - } - val blockingAuthClient = client.newBuilder() - .authenticator(authenticator) - .build() - val callback: Callback = object : Callback { - override fun onFailure(call: Call, e: IOException) { - fail("") + val authenticator = + okhttp3.Authenticator { route: Route?, response: Response? -> + responses.offer(response!!.body.string()) + try { + latch.await() + } catch (e: InterruptedException) { + throw AssertionError() + } + response.request } + val blockingAuthClient = + client.newBuilder() + .authenticator(authenticator) + .build() + val callback: Callback = + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + fail("") + } - override fun onResponse(call: Call, response: Response) { - responses.offer(response.body.string()) + override fun onResponse( + call: Call, + response: Response, + ) { + responses.offer(response.body.string()) + } } - } // Make the first request waiting until we get our auth challenge. val request = Request(server.url("/")) @@ -1262,14 +1451,18 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(2) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun nonAsciiResponseHeader(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun nonAsciiResponseHeader( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse.Builder() .addHeaderLenient("Alpha", "α") .addHeaderLenient("β", "Beta") - .build() + .build(), ) val call = client.newCall(Request(server.url("/"))) val response = call.execute() @@ -1278,18 +1471,25 @@ class HttpOverHttp2Test { assertThat(response.header("β")).isEqualTo("Beta") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun serverSendsPushPromise_GET(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun serverSendsPushPromise_GET( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - val pushPromise = PushPromise( - "GET", "/foo/bar", headersOf("foo", "bar"), - MockResponse(body = "bar") - ) + val pushPromise = + PushPromise( + "GET", + "/foo/bar", + headersOf("foo", "bar"), + MockResponse(body = "bar"), + ) server.enqueue( MockResponse.Builder() .body("ABCDE") .addPush(pushPromise) - .build() + .build(), ) val call = client.newCall(Request(server.url("/foo"))) val response = call.execute() @@ -1298,27 +1498,34 @@ class HttpOverHttp2Test { assertThat(response.message).isEqualTo("") val request = server.takeRequest() assertThat(request.requestLine).isEqualTo("GET /foo HTTP/1.1") - assertThat(request.headers[":scheme"]).isEqualTo(scheme) - assertThat(request.headers[":authority"]).isEqualTo( - server.hostName + ":" + server.port + assertThat(request.headers[":scheme"]).isEqualTo(scheme) + assertThat(request.headers[":authority"]).isEqualTo( + server.hostName + ":" + server.port, ) val pushedRequest = server.takeRequest() assertThat(pushedRequest.requestLine).isEqualTo("GET /foo/bar HTTP/1.1") - assertThat(pushedRequest.headers["foo"]).isEqualTo("bar") + assertThat(pushedRequest.headers["foo"]).isEqualTo("bar") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun serverSendsPushPromise_HEAD(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun serverSendsPushPromise_HEAD( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - val pushPromise = PushPromise( - "HEAD", "/foo/bar", headersOf("foo", "bar"), - MockResponse(code = 204) - ) + val pushPromise = + PushPromise( + "HEAD", + "/foo/bar", + headersOf("foo", "bar"), + MockResponse(code = 204), + ) server.enqueue( MockResponse.Builder() .body("ABCDE") .addPush(pushPromise) - .build() + .build(), ) val call = client.newCall(Request(server.url("/foo"))) val response = call.execute() @@ -1327,27 +1534,32 @@ class HttpOverHttp2Test { assertThat(response.message).isEqualTo("") val request = server.takeRequest() assertThat(request.requestLine).isEqualTo("GET /foo HTTP/1.1") - assertThat(request.headers[":scheme"]).isEqualTo(scheme) - assertThat(request.headers[":authority"]).isEqualTo( - server.hostName + ":" + server.port + assertThat(request.headers[":scheme"]).isEqualTo(scheme) + assertThat(request.headers[":authority"]).isEqualTo( + server.hostName + ":" + server.port, ) val pushedRequest = server.takeRequest() assertThat(pushedRequest.requestLine).isEqualTo( - "HEAD /foo/bar HTTP/1.1" + "HEAD /foo/bar HTTP/1.1", ) - assertThat(pushedRequest.headers["foo"]).isEqualTo("bar") + assertThat(pushedRequest.headers["foo"]).isEqualTo("bar") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun noDataFramesSentWithNullRequestBody(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun noDataFramesSentWithNullRequestBody( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(body = "ABC")) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .method("DELETE", null) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .method("DELETE", null) + .build(), + ) val response = call.execute() assertThat(response.body.string()).isEqualTo("ABC") assertThat(response.protocol).isEqualTo(protocol) @@ -1356,16 +1568,21 @@ class HttpOverHttp2Test { .contains("HEADERS END_STREAM|END_HEADERS") } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun emptyDataFrameSentWithEmptyBody(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun emptyDataFrameSentWithEmptyBody( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(body = "ABC")) - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .method("DELETE", EMPTY_REQUEST) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .method("DELETE", EMPTY_REQUEST) + .build(), + ) val response = call.execute() assertThat(response.body.string()).isEqualTo("ABC") assertThat(response.protocol).isEqualTo(protocol) @@ -1381,20 +1598,25 @@ class HttpOverHttp2Test { .isEqualTo(1) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun pingsTransmitted(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun pingsTransmitted( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) // Ping every 500 ms, starting at 500 ms. - client = client.newBuilder() - .pingInterval(Duration.ofMillis(500)) - .build() + client = + client.newBuilder() + .pingInterval(Duration.ofMillis(500)) + .build() // Delay the response to give 1 ping enough time to be sent and replied to. server.enqueue( MockResponse.Builder() .bodyDelay(750, TimeUnit.MILLISECONDS) .body("ABC") - .build() + .build(), ) val call = client.newCall(Request(server.url("/"))) val response = call.execute() @@ -1413,9 +1635,11 @@ class HttpOverHttp2Test { .isEqualTo(1) } - @Flaky @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @Flaky @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun missingPongsFailsConnection( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) if (protocol === Protocol.HTTP_2) { @@ -1424,10 +1648,11 @@ class HttpOverHttp2Test { } // Ping every 500 ms, starting at 500 ms. - client = client.newBuilder() - .readTimeout(Duration.ofSeconds(10)) // Confirm we fail before the read timeout. - .pingInterval(Duration.ofMillis(500)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofSeconds(10)) // Confirm we fail before the read timeout. + .pingInterval(Duration.ofMillis(500)) + .build() // Set up the server to ignore the socket. It won't respond to pings! server.enqueue(MockResponse(socketPolicy = StallSocketAtStart)) @@ -1439,7 +1664,7 @@ class HttpOverHttp2Test { call.execute() }.also { expected -> assertThat(expected.message).isEqualTo( - "stream was reset: PROTOCOL_ERROR" + "stream was reset: PROTOCOL_ERROR", ) } val elapsedUntilFailure = System.nanoTime() - executeAtNanos @@ -1454,20 +1679,25 @@ class HttpOverHttp2Test { .isEqualTo(0) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun streamTimeoutDegradesConnectionAfterNoPong(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun streamTimeoutDegradesConnectionAfterNoPong( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) assumeNotWindows() - client = client.newBuilder() - .readTimeout(Duration.ofMillis(500)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofMillis(500)) + .build() // Stalling the socket will cause TWO requests to time out! server.enqueue(MockResponse(socketPolicy = StallSocketAtStart)) // The 3rd request should be sent to a fresh connection. server.enqueue( - MockResponse(body = "fresh connection") + MockResponse(body = "fresh connection"), ) // The first call times out. @@ -1492,22 +1722,27 @@ class HttpOverHttp2Test { val call3 = client.newCall(Request(server.url("/"))) call3.execute().use { response -> assertThat( - response.body.string() + response.body.string(), ).isEqualTo("fresh connection") } } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun oneStreamTimeoutDoesNotBreakConnection(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun oneStreamTimeoutDoesNotBreakConnection( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - client = client.newBuilder() - .readTimeout(Duration.ofMillis(500)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ofMillis(500)) + .build() server.enqueue( MockResponse.Builder() .bodyDelay(1000, TimeUnit.MILLISECONDS) .body("a") - .build() + .build(), ) server.enqueue(MockResponse(body = "b")) server.enqueue(MockResponse(body = "c")) @@ -1524,7 +1759,7 @@ class HttpOverHttp2Test { val call2 = client.newCall(Request(server.url("/"))) call2.execute().use { response -> assertThat( - response.body.string() + response.body.string(), ).isEqualTo("b") } @@ -1533,7 +1768,7 @@ class HttpOverHttp2Test { val call3 = client.newCall(Request(server.url("/"))) call3.execute().use { response -> assertThat( - response.body.string() + response.body.string(), ).isEqualTo("c") } @@ -1543,7 +1778,10 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(2) } - private fun firstFrame(logs: List, type: String): String? { + private fun firstFrame( + logs: List, + type: String, + ): String? { for (log in logs) { if (type in log) { return log @@ -1552,7 +1790,10 @@ class HttpOverHttp2Test { return null } - private fun countFrames(logs: List, message: String): Int { + private fun countFrames( + logs: List, + message: String, + ): Int { var result = 0 for (log in logs) { if (log == message) { @@ -1566,27 +1807,33 @@ class HttpOverHttp2Test { * Push a setting that permits up to 2 concurrent streams, then make 3 concurrent requests and * confirm that the third concurrent request prepared a new connection. */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun settingsLimitsMaxConcurrentStreams(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun settingsLimitsMaxConcurrentStreams( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) val settings = Settings() settings[Settings.MAX_CONCURRENT_STREAMS] = 2 // Read & write a full request to confirm settings are accepted. - server.enqueue(MockResponse.Builder() - .settings(settings) - .build()) + server.enqueue( + MockResponse.Builder() + .settings(settings) + .build(), + ) val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("") server.enqueue( - MockResponse(body = "ABC") + MockResponse(body = "ABC"), ) server.enqueue( - MockResponse(body = "DEF") + MockResponse(body = "DEF"), ) server.enqueue( - MockResponse(body = "GHI") + MockResponse(body = "GHI"), ) val call1 = client.newCall(Request(server.url("/"))) val response1 = call1.execute() @@ -1607,26 +1854,36 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun connectionNotReusedAfterShutdown(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun connectionNotReusedAfterShutdown( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse( body = "ABC", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue(MockResponse(body = "DEF")) // Enqueue an additional response that show if we burnt a good prior response. server.enqueue( - MockResponse(body = "XXX") + MockResponse(body = "XXX"), ) val connections: MutableList = ArrayList() - val localClient = client.newBuilder().eventListener(object : EventListener() { - override fun connectionAcquired(call: Call, connection: Connection) { - connections.add(connection as RealConnection) - } - }).build() + val localClient = + client.newBuilder().eventListener( + object : EventListener() { + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + connections.add(connection as RealConnection) + } + }, + ).build() val call1 = localClient.newCall(Request(server.url("/"))) val response1 = call1.execute() assertThat(response1.body.string()).isEqualTo("ABC") @@ -1657,39 +1914,48 @@ class HttpOverHttp2Test { * This simulates a race condition where we receive a healthy HTTP/2 connection and just prior to * writing our request, we get a GOAWAY frame from the server. */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun connectionShutdownAfterHealthCheck(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun connectionShutdownAfterHealthCheck( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse( body = "ABC", socketPolicy = DisconnectAtEnd, - ) + ), ) server.enqueue(MockResponse(body = "DEF")) - val client2 = client.newBuilder() - .addNetworkInterceptor(object : Interceptor { - var executedCall = false - override fun intercept(chain: Interceptor.Chain): Response { - if (!executedCall) { - // At this point, we have a healthy HTTP/2 connection. This call will trigger the - // server to send a GOAWAY frame, leaving the connection in a shutdown state. - executedCall = true - val call = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() - ) - val response = call.execute() - assertThat(response.body.string()).isEqualTo("ABC") - // Wait until the GOAWAY has been processed. - val connection = chain.connection() as RealConnection? - while (connection!!.isHealthy(false)); - } - return chain.proceed(chain.request()) - } - }) - .build() + val client2 = + client.newBuilder() + .addNetworkInterceptor( + object : Interceptor { + var executedCall = false + + override fun intercept(chain: Interceptor.Chain): Response { + if (!executedCall) { + // At this point, we have a healthy HTTP/2 connection. This call will trigger the + // server to send a GOAWAY frame, leaving the connection in a shutdown state. + executedCall = true + val call = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) + val response = call.execute() + assertThat(response.body.string()).isEqualTo("ABC") + // Wait until the GOAWAY has been processed. + val connection = chain.connection() as RealConnection? + while (connection!!.isHealthy(false)); + } + return chain.proceed(chain.request()) + } + }, + ) + .build() val call = client2.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("DEF") @@ -1697,40 +1963,51 @@ class HttpOverHttp2Test { assertThat(server.takeRequest().sequenceNumber).isEqualTo(0) } - @Flaky @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun responseHeadersAfterGoaway(protocol: Protocol, mockWebServer: MockWebServer) { + @Flaky @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun responseHeadersAfterGoaway( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse.Builder() .headersDelay(1, TimeUnit.SECONDS) .body("ABC") - .build() + .build(), ) server.enqueue( MockResponse( body = "DEF", socketPolicy = DisconnectAtEnd, - ) + ), ) val latch = CountDownLatch(2) val errors = ArrayList() val bodies: BlockingQueue = LinkedBlockingQueue() - val callback: Callback = object : Callback { - override fun onResponse(call: Call, response: Response) { - bodies.add(response.body.string()) - latch.countDown() - } + val callback: Callback = + object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + bodies.add(response.body.string()) + latch.countDown() + } - override fun onFailure(call: Call, e: IOException) { - errors.add(e) - latch.countDown() + override fun onFailure( + call: Call, + e: IOException, + ) { + errors.add(e) + latch.countDown() + } } - } client.newCall(Request.Builder().url(server.url("/")).build()).enqueue( - callback + callback, ) client.newCall(Request.Builder().url(server.url("/")).build()).enqueue( - callback + callback, ) latch.await() assertThat(bodies.remove()).isEqualTo("DEF") @@ -1754,8 +2031,12 @@ class HttpOverHttp2Test { * * This test uses proxy tunnels to get a hook while a connection is being established. */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun concurrentHttp2ConnectionsDeduplicated(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun concurrentHttp2ConnectionsDeduplicated( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) assumeTrue(protocol === Protocol.HTTP_2) server.useHttps(handshakeCertificates.sslSocketFactory()) @@ -1766,38 +2047,41 @@ class HttpOverHttp2Test { queueDispatcher.enqueueResponse(MockResponse(body = "call1 response")) // We use a re-entrant dispatcher to initiate one HTTPS connection while the other is in flight. - server.dispatcher = object : Dispatcher() { - var requestCount = 0 - - override fun dispatch(request: RecordedRequest): MockResponse { - val result = queueDispatcher.dispatch(request) - requestCount++ - if (requestCount == 1) { - // Before handling call1's CONNECT we do all of call2. This part re-entrant! - try { - val call2 = client.newCall( - Request.Builder() - .url("https://android.com/call2") - .build() - ) - val response2 = call2.execute() - assertThat(response2.body.string()).isEqualTo("call2 response") - } catch (e: IOException) { - throw RuntimeException(e) + server.dispatcher = + object : Dispatcher() { + var requestCount = 0 + + override fun dispatch(request: RecordedRequest): MockResponse { + val result = queueDispatcher.dispatch(request) + requestCount++ + if (requestCount == 1) { + // Before handling call1's CONNECT we do all of call2. This part re-entrant! + try { + val call2 = + client.newCall( + Request.Builder() + .url("https://android.com/call2") + .build(), + ) + val response2 = call2.execute() + assertThat(response2.body.string()).isEqualTo("call2 response") + } catch (e: IOException) { + throw RuntimeException(e) + } } + return result } - return result - } - override fun peek(): MockResponse = queueDispatcher.peek() + override fun peek(): MockResponse = queueDispatcher.peek() - override fun shutdown() { - queueDispatcher.shutdown() + override fun shutdown() { + queueDispatcher.shutdown() + } } - } - client = client.newBuilder() - .proxy(server.toProxyAddress()) - .build() + client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .build() val call1 = client.newCall(Request("https://android.com/call1".toHttpUrl())) val response2 = call1.execute() assertThat(response2.body.string()).isEqualTo("call1 response") @@ -1819,23 +2103,31 @@ class HttpOverHttp2Test { } /** https://github.com/square/okhttp/issues/3103 */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun domainFronting(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun domainFronting( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) - client = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain? -> - val request = chain!!.request().newBuilder() - .header("Host", "privateobject.com") - .build() - chain.proceed(request) - }) - .build() + client = + client.newBuilder() + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain? -> + val request = + chain!!.request().newBuilder() + .header("Host", "privateobject.com") + .build() + chain.proceed(request) + }, + ) + .build() server.enqueue(MockResponse()) val call = client.newCall(Request(server.url("/"))) val response = call.execute() assertThat(response.body.string()).isEqualTo("") val recordedRequest = server.takeRequest() - assertThat(recordedRequest.headers[":authority"]).isEqualTo("privateobject.com") + assertThat(recordedRequest.headers[":authority"]).isEqualTo("privateobject.com") } private fun gzip(bytes: String): Buffer { @@ -1848,15 +2140,16 @@ class HttpOverHttp2Test { internal inner class AsyncRequest( val path: String, - val countDownLatch: CountDownLatch + val countDownLatch: CountDownLatch, ) : Runnable { override fun run() { try { - val call = client.newCall( - Request.Builder() - .url(server.url(path)) - .build() - ) + val call = + client.newCall( + Request.Builder() + .url(server.url(path)) + .build(), + ) val response = call.execute() assertThat(response.body.string()).isEqualTo("A") countDownLatch.countDown() @@ -1867,60 +2160,83 @@ class HttpOverHttp2Test { } /** https://github.com/square/okhttp/issues/4875 */ - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun shutdownAfterLateCoalescing(protocol: Protocol, mockWebServer: MockWebServer) { + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) + fun shutdownAfterLateCoalescing( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) val latch = CountDownLatch(2) - val callback: Callback = object : Callback { - override fun onResponse(call: Call, response: Response) { - fail("") - } + val callback: Callback = + object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + fail("") + } - override fun onFailure(call: Call, e: IOException) { - latch.countDown() + override fun onFailure( + call: Call, + e: IOException, + ) { + latch.countDown() + } } - } client = - client.newBuilder().eventListenerFactory(clientTestRule.wrap(object : EventListener() { - var callCount = 0 - override fun connectionAcquired(call: Call, connection: Connection) { - try { - if (callCount++ == 1) { - server.shutdown() + client.newBuilder().eventListenerFactory( + clientTestRule.wrap( + object : EventListener() { + var callCount = 0 + + override fun connectionAcquired( + call: Call, + connection: Connection, + ) { + try { + if (callCount++ == 1) { + server.shutdown() + } + } catch (e: IOException) { + fail("") + } } - } catch (e: IOException) { - fail("") - } - } - })).build() + }, + ), + ).build() client.newCall(Request.Builder().url(server.url("")).build()).enqueue( - callback + callback, ) client.newCall(Request.Builder().url(server.url("")).build()).enqueue( - callback + callback, ) latch.await() } - @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) + @ParameterizedTest + @ArgumentsSource(ProtocolParamProvider::class) fun cancelWhileWritingRequestBodySendsCancelToServer( - protocol: Protocol, mockWebServer: MockWebServer + protocol: Protocol, + mockWebServer: MockWebServer, ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse()) val callReference = AtomicReference() - val call = client.newCall( - Request( - url = server.url("/"), - body = object : RequestBody() { - override fun contentType() = "text/plain; charset=utf-8".toMediaType() - - override fun writeTo(sink: BufferedSink) { - callReference.get()!!.cancel() - } - }, + val call = + client.newCall( + Request( + url = server.url("/"), + body = + object : RequestBody() { + override fun contentType() = "text/plain; charset=utf-8".toMediaType() + + override fun writeTo(sink: BufferedSink) { + callReference.get()!!.cancel() + } + }, + ), ) - ) callReference.set(call) assertFailsWith { call.execute() @@ -1933,20 +2249,25 @@ class HttpOverHttp2Test { @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun http2WithProxy(protocol: Protocol, mockWebServer: MockWebServer) { + fun http2WithProxy( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "ABCDE")) - val client = client.newBuilder() - .proxy(server.toProxyAddress()) - .build() + val client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .build() val url = server.url("/").resolve("//android.com/foo")!! - val port = when (url.scheme) { - "https" -> 443 - "http" -> 80 - else -> error("unexpected scheme") - } + val port = + when (url.scheme) { + "https" -> 443 + "http" -> 80 + else -> error("unexpected scheme") + } val call = client.newCall(Request(url)) val response = call.execute() @@ -1960,35 +2281,40 @@ class HttpOverHttp2Test { val request = server.takeRequest() assertThat(request.requestLine).isEqualTo("GET /foo HTTP/1.1") - assertThat(request.headers[":scheme"]).isEqualTo(scheme) - assertThat(request.headers[":authority"]).isEqualTo("android.com") + assertThat(request.headers[":scheme"]).isEqualTo(scheme) + assertThat(request.headers[":authority"]).isEqualTo("android.com") } /** Respond to a proxy authorization challenge. */ @ParameterizedTest @ArgumentsSource(ProtocolParamProvider::class) - fun proxyAuthenticateOnConnect(protocol: Protocol, mockWebServer: MockWebServer) { + fun proxyAuthenticateOnConnect( + protocol: Protocol, + mockWebServer: MockWebServer, + ) { setUp(protocol, mockWebServer) server.enqueue( MockResponse( code = 407, headers = headersOf("Proxy-Authenticate", "Basic realm=\"localhost\""), inTunnel = true, - ) + ), ) server.enqueue(MockResponse(inTunnel = true)) server.enqueue(MockResponse(body = "response body")) - val client = client.newBuilder() - .proxy(server.toProxyAddress()) - .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) - .build() + val client = + client.newBuilder() + .proxy(server.toProxyAddress()) + .proxyAuthenticator(RecordingOkAuthenticator("password", "Basic")) + .build() val url = server.url("/").resolve("//android.com/foo")!! - val port = when (url.scheme) { - "https" -> 443 - "http" -> 80 - else -> error("unexpected scheme") - } + val port = + when (url.scheme) { + "https" -> 443 + "http" -> 80 + else -> error("unexpected scheme") + } val request = Request(url) val response = client.newCall(request).execute() @@ -1996,14 +2322,14 @@ class HttpOverHttp2Test { val connect1 = server.takeRequest() assertThat(connect1.requestLine).isEqualTo("CONNECT android.com:$port HTTP/1.1") - assertThat(connect1.headers["Proxy-Authorization"]).isNull() + assertThat(connect1.headers["Proxy-Authorization"]).isNull() val connect2 = server.takeRequest() assertThat(connect2.requestLine).isEqualTo("CONNECT android.com:$port HTTP/1.1") - assertThat(connect2.headers["Proxy-Authorization"]).isEqualTo("password") + assertThat(connect2.headers["Proxy-Authorization"]).isEqualTo("password") val get = server.takeRequest() assertThat(get.requestLine).isEqualTo("GET /foo HTTP/1.1") - assertThat(get.headers["Proxy-Authorization"]).isNull() + assertThat(get.headers["Proxy-Authorization"]).isNull() } } diff --git a/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt b/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt index db661bcf5bee..aa7c8cbebd2c 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt @@ -169,26 +169,41 @@ class MockHttp2Peer : Closeable { private class OutFrame( val sequence: Int, val start: Long, - val truncated: Boolean + val truncated: Boolean, ) class InFrame(val sequence: Int, val reader: Http2Reader) : Http2Reader.Handler { @JvmField var type = -1 var clearPrevious = false + @JvmField var outFinished = false + @JvmField var inFinished = false + @JvmField var streamId = 0 + @JvmField var associatedStreamId = 0 + @JvmField var errorCode: ErrorCode? = null + @JvmField var windowSizeIncrement: Long = 0 + @JvmField var headerBlock: List
? = null + @JvmField var data: ByteArray? = null + @JvmField var settings: Settings? = null + @JvmField var ack = false + @JvmField var payload1 = 0 + @JvmField var payload2 = 0 - override fun settings(clearPrevious: Boolean, settings: Settings) { + override fun settings( + clearPrevious: Boolean, + settings: Settings, + ) { check(type == -1) this.type = Http2.TYPE_SETTINGS this.clearPrevious = clearPrevious @@ -202,8 +217,10 @@ class MockHttp2Peer : Closeable { } override fun headers( - inFinished: Boolean, streamId: Int, - associatedStreamId: Int, headerBlock: List
+ inFinished: Boolean, + streamId: Int, + associatedStreamId: Int, + headerBlock: List
, ) { check(type == -1) this.type = Http2.TYPE_HEADERS @@ -217,7 +234,7 @@ class MockHttp2Peer : Closeable { inFinished: Boolean, streamId: Int, source: BufferedSource, - length: Int + length: Int, ) { check(type == -1) this.type = Http2.TYPE_DATA @@ -226,14 +243,21 @@ class MockHttp2Peer : Closeable { this.data = source.readByteString(length.toLong()).toByteArray() } - override fun rstStream(streamId: Int, errorCode: ErrorCode) { + override fun rstStream( + streamId: Int, + errorCode: ErrorCode, + ) { check(type == -1) this.type = Http2.TYPE_RST_STREAM this.streamId = streamId this.errorCode = errorCode } - override fun ping(ack: Boolean, payload1: Int, payload2: Int) { + override fun ping( + ack: Boolean, + payload1: Int, + payload2: Int, + ) { check(type == -1) type = Http2.TYPE_PING this.ack = ack @@ -241,7 +265,11 @@ class MockHttp2Peer : Closeable { this.payload2 = payload2 } - override fun goAway(lastGoodStreamId: Int, errorCode: ErrorCode, debugData: ByteString) { + override fun goAway( + lastGoodStreamId: Int, + errorCode: ErrorCode, + debugData: ByteString, + ) { check(type == -1) this.type = Http2.TYPE_GOAWAY this.streamId = lastGoodStreamId @@ -249,7 +277,10 @@ class MockHttp2Peer : Closeable { this.data = debugData.toByteArray() } - override fun windowUpdate(streamId: Int, windowSizeIncrement: Long) { + override fun windowUpdate( + streamId: Int, + windowSizeIncrement: Long, + ) { check(type == -1) this.type = Http2.TYPE_WINDOW_UPDATE this.streamId = streamId @@ -257,13 +288,19 @@ class MockHttp2Peer : Closeable { } override fun priority( - streamId: Int, streamDependency: Int, weight: Int, - exclusive: Boolean + streamId: Int, + streamDependency: Int, + weight: Int, + exclusive: Boolean, ) { throw UnsupportedOperationException() } - override fun pushPromise(streamId: Int, associatedStreamId: Int, headerBlock: List
) { + override fun pushPromise( + streamId: Int, + associatedStreamId: Int, + headerBlock: List
, + ) { this.type = Http2.TYPE_PUSH_PROMISE this.streamId = streamId this.associatedStreamId = associatedStreamId @@ -276,7 +313,7 @@ class MockHttp2Peer : Closeable { protocol: ByteString, host: String, port: Int, - maxAge: Long + maxAge: Long, ) { throw UnsupportedOperationException() } diff --git a/okhttp/src/test/java/okhttp3/internal/http2/SettingsTest.kt b/okhttp/src/test/java/okhttp3/internal/http2/SettingsTest.kt index 1c82a2d83a21..1edbec9f34a6 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/SettingsTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/SettingsTest.kt @@ -49,7 +49,7 @@ class SettingsTest { settings[Settings.MAX_HEADER_LIST_SIZE] = 16777215 assertThat(settings.getMaxHeaderListSize(-1)).isEqualTo(16777215) assertThat(settings.initialWindowSize).isEqualTo( - Settings.DEFAULT_INITIAL_WINDOW_SIZE + Settings.DEFAULT_INITIAL_WINDOW_SIZE, ) settings[Settings.INITIAL_WINDOW_SIZE] = 108 assertThat(settings.initialWindowSize).isEqualTo(108) diff --git a/okhttp/src/test/java/okhttp3/internal/idn/IdnStringprep.kt b/okhttp/src/test/java/okhttp3/internal/idn/IdnStringprep.kt index c18bd99deaf7..496ee6e5db77 100644 --- a/okhttp/src/test/java/okhttp3/internal/idn/IdnStringprep.kt +++ b/okhttp/src/test/java/okhttp3/internal/idn/IdnStringprep.kt @@ -66,7 +66,6 @@ class Stringprep( if (first) { firstIsRandalcat = codePoint in randalcatSet - } else if (firstIsRandalcat) { // 'If a string contains any RandALCat character, the string MUST NOT contain any LCat // character.' @@ -75,7 +74,6 @@ class Stringprep( // 'If a string contains any RandALCat character, a RandALCat character MUST be the last // character of the string.' if (validateBuffer.exhausted() && codePoint !in randalcatSet) return null - } else { // 'If a string contains any RandALCat character, a RandALCat character MUST be the first // character of the string' diff --git a/okhttp/src/test/java/okhttp3/internal/idn/IdnaMappingTableTest.kt b/okhttp/src/test/java/okhttp3/internal/idn/IdnaMappingTableTest.kt index 4d6cf6a0c27e..0a4b133d8927 100644 --- a/okhttp/src/test/java/okhttp3/internal/idn/IdnaMappingTableTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/idn/IdnaMappingTableTest.kt @@ -35,16 +35,18 @@ class IdnaMappingTableTest { @BeforeEach fun setUp() { val path = "/okhttp3/internal/idna/IdnaMappingTable.txt".toPath() - val plainTable = FileSystem.RESOURCES.read(path) { - readPlainTextIdnaMappingTable() - } + val plainTable = + FileSystem.RESOURCES.read(path) { + readPlainTextIdnaMappingTable() + } table = plainTable val data = buildIdnaMappingTableData(plainTable) - compactTable = IdnaMappingTable( - sections = data.sections, - ranges = data.ranges, - mappings = data.mappings, - ) + compactTable = + IdnaMappingTable( + sections = data.sections, + ranges = data.ranges, + mappings = data.mappings, + ) } @Test fun regularMappings() { @@ -88,10 +90,11 @@ class IdnaMappingTableTest { // Check the ranges. for (r in 0 until rangesOffsets.size) { val rangePos = rangesOffsets[r] * 4 - val rangeLimit = when { - r + 1 < rangesOffsets.size -> rangesOffsets[r + 1] * 4 - else -> rangesOffsets.size * 4 - } + val rangeLimit = + when { + r + 1 < rangesOffsets.size -> rangesOffsets[r + 1] * 4 + else -> rangesOffsets.size * 4 + } // Confirm this range starts with byte 0. assertThat(compactTable.ranges[rangePos].code).isEqualTo(0) diff --git a/okhttp/src/test/java/okhttp3/internal/idn/PunycodeTest.kt b/okhttp/src/test/java/okhttp3/internal/idn/PunycodeTest.kt index b515d4e9c18c..ea14ea17e2f7 100644 --- a/okhttp/src/test/java/okhttp3/internal/idn/PunycodeTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/idn/PunycodeTest.kt @@ -25,86 +25,86 @@ class PunycodeTest { // (A) Arabic (Egyptian) testEncodeDecode( unicode = "ليهمابتكلموشعربي؟", - punycode = "xn--egbpdaj6bu4bxfgehfvwxn" + punycode = "xn--egbpdaj6bu4bxfgehfvwxn", ) // (B) Chinese (simplified) testEncodeDecode( unicode = "他们为什么不说中文", - punycode = "xn--ihqwcrb4cv8a8dqg056pqjye" + punycode = "xn--ihqwcrb4cv8a8dqg056pqjye", ) // (C) Chinese (traditional) testEncodeDecode( unicode = "他們爲什麽不說中文", - punycode = "xn--ihqwctvzc91f659drss3x8bo0yb" + punycode = "xn--ihqwctvzc91f659drss3x8bo0yb", ) // (D) Czech testEncodeDecode( unicode = "Pročprostěnemluvíčesky", - punycode = "xn--Proprostnemluvesky-uyb24dma41a" + punycode = "xn--Proprostnemluvesky-uyb24dma41a", ) // (E) Hebrew: testEncodeDecode( unicode = "למההםפשוטלאמדבריםעברית", - punycode = "xn--4dbcagdahymbxekheh6e0a7fei0b" + punycode = "xn--4dbcagdahymbxekheh6e0a7fei0b", ) // (F) Hindi (Devanagari) testEncodeDecode( unicode = "यहलोगहिन्दीक्योंनहींबोलसकतेहैं", - punycode = "xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd" + punycode = "xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd", ) // (G) Japanese (kanji and hiragana) testEncodeDecode( unicode = "なぜみんな日本語を話してくれないのか", - punycode = "xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa" + punycode = "xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa", ) // (H) Korean (Hangul syllables) testEncodeDecode( unicode = "세계의모든사람들이한국어를이해한다면얼마나좋을까", - punycode = "xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c" + punycode = "xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c", ) // (I) Russian (Cyrillic) testEncodeDecode( unicode = "почемужеонинеговорятпорусски", - punycode = "xn--b1abfaaepdrnnbgefbadotcwatmq2g4l" + punycode = "xn--b1abfaaepdrnnbgefbadotcwatmq2g4l", ) // (J) Spanish testEncodeDecode( unicode = "PorquénopuedensimplementehablarenEspañol", - punycode = "xn--PorqunopuedensimplementehablarenEspaol-fmd56a" + punycode = "xn--PorqunopuedensimplementehablarenEspaol-fmd56a", ) // (K) Vietnamese testEncodeDecode( unicode = "TạisaohọkhôngthểchỉnóitiếngViệt", - punycode = "xn--TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g" + punycode = "xn--TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g", ) } @Test fun multipleLabels() { testEncodeDecode( unicode = "☃.net", - punycode = "xn--n3h.net" + punycode = "xn--n3h.net", ) testEncodeDecode( unicode = "ålgård.no", - punycode = "xn--lgrd-poac.no" + punycode = "xn--lgrd-poac.no", ) testEncodeDecode( unicode = "個人.香港", - punycode = "xn--gmqw5a.xn--j6w193g" + punycode = "xn--gmqw5a.xn--j6w193g", ) testEncodeDecode( unicode = "упр.срб", - punycode = "xn--o1ach.xn--90a3ac" + punycode = "xn--o1ach.xn--90a3ac", ) } @@ -136,21 +136,21 @@ class PunycodeTest { @Test fun dashInPrefix() { testEncodeDecode( unicode = "klmnöpqrst-uvwxy", - punycode = "xn--klmnpqrst-uvwxy-ctb" + punycode = "xn--klmnpqrst-uvwxy-ctb", ) } @Test fun uppercasePunycode() { testDecodeOnly( unicode = "ليهمابتكلموشعربي؟", - punycode = "XN--EGBPDAJ6BU4BXFGEHFVWXN" + punycode = "XN--EGBPDAJ6BU4BXFGEHFVWXN", ) } @Test fun mixedCasePunycode() { testDecodeOnly( unicode = "ليهمابتكلموشعربي؟", - punycode = "Xn--EgBpDaJ6Bu4bXfGeHfVwXn" + punycode = "Xn--EgBpDaJ6Bu4bXfGeHfVwXn", ) } @@ -174,12 +174,18 @@ class PunycodeTest { assertNull(Punycode.decode("xn--ls8h=")) } - private fun testEncodeDecode(unicode: String, punycode: String) { + private fun testEncodeDecode( + unicode: String, + punycode: String, + ) { assertEquals(unicode, Punycode.decode(punycode)) assertEquals(punycode, Punycode.encode(unicode)) } - private fun testDecodeOnly(unicode: String, punycode: String) { + private fun testDecodeOnly( + unicode: String, + punycode: String, + ) { assertEquals(unicode, Punycode.decode(punycode)) } } diff --git a/okhttp/src/test/java/okhttp3/internal/idn/StringprepReader.kt b/okhttp/src/test/java/okhttp3/internal/idn/StringprepReader.kt index e76957bdb1d8..c85f0b7e10b9 100644 --- a/okhttp/src/test/java/okhttp3/internal/idn/StringprepReader.kt +++ b/okhttp/src/test/java/okhttp3/internal/idn/StringprepReader.kt @@ -35,27 +35,30 @@ class StringprepTablesReader( */ fun readNameprep(base: Path): Stringprep { val unassigned = readCodePointSet(base / "rfc3454.A.1.txt") - val mapping = MappingListCodePointMapping( - mutableMapOf() - .apply { - putAll(readCodePointMapping(base / "rfc3454.B.1.txt").mappings) - putAll(readCodePointMapping(base / "rfc3454.B.2.txt").mappings) - } - ) - val prohibitSet = RangeListCodePointSet( - ranges = mutableListOf() - .apply { - addAll(readCodePointSet(base / "rfc3454.C.1.2.txt").ranges) - addAll(readCodePointSet(base / "rfc3454.C.2.2.txt").ranges) - addAll(readCodePointSet(base / "rfc3454.C.3.txt").ranges) - addAll(readCodePointSet(base / "rfc3454.C.4.txt").ranges) - addAll(readCodePointSet(base / "rfc3454.C.5.txt").ranges) - addAll(readCodePointSet(base / "rfc3454.C.6.txt").ranges) - addAll(readCodePointSet(base / "rfc3454.C.7.txt").ranges) - addAll(readCodePointSet(base / "rfc3454.C.8.txt").ranges) - addAll(readCodePointSet(base / "rfc3454.C.9.txt").ranges) - } - ) + val mapping = + MappingListCodePointMapping( + mutableMapOf() + .apply { + putAll(readCodePointMapping(base / "rfc3454.B.1.txt").mappings) + putAll(readCodePointMapping(base / "rfc3454.B.2.txt").mappings) + }, + ) + val prohibitSet = + RangeListCodePointSet( + ranges = + mutableListOf() + .apply { + addAll(readCodePointSet(base / "rfc3454.C.1.2.txt").ranges) + addAll(readCodePointSet(base / "rfc3454.C.2.2.txt").ranges) + addAll(readCodePointSet(base / "rfc3454.C.3.txt").ranges) + addAll(readCodePointSet(base / "rfc3454.C.4.txt").ranges) + addAll(readCodePointSet(base / "rfc3454.C.5.txt").ranges) + addAll(readCodePointSet(base / "rfc3454.C.6.txt").ranges) + addAll(readCodePointSet(base / "rfc3454.C.7.txt").ranges) + addAll(readCodePointSet(base / "rfc3454.C.8.txt").ranges) + addAll(readCodePointSet(base / "rfc3454.C.9.txt").ranges) + }, + ) val randalcatSet = readCodePointSet(base / "rfc3454.D.1.txt") val lcatSet = readCodePointSet(base / "rfc3454.D.2.txt") return Stringprep( @@ -63,7 +66,7 @@ class StringprepTablesReader( mapping = mapping, prohibitSet = prohibitSet, randalcatSet = randalcatSet, - lcatSet = lcatSet + lcatSet = lcatSet, ) } @@ -102,21 +105,21 @@ class StringprepTablesReader( } } -private val optionsSemicolon = Options.of( - // 0 is ';'. - ";".encodeUtf8(), -) +private val optionsSemicolon = + Options.of( + // 0 is ';'. + ";".encodeUtf8(), + ) -private val optionsSemicolonOrNewlineOrDash = Options.of( - // 0 is ';'. - ";".encodeUtf8(), - - // 1 is '\n'. - "\n".encodeUtf8(), - - // 2 is '-'. - "-".encodeUtf8(), -) +private val optionsSemicolonOrNewlineOrDash = + Options.of( + // 0 is ';'. + ";".encodeUtf8(), + // 1 is '\n'. + "\n".encodeUtf8(), + // 2 is '-'. + "-".encodeUtf8(), + ) internal fun BufferedSource.readCodePointSet(): RangeListCodePointSet { val result = mutableListOf() @@ -124,26 +127,27 @@ internal fun BufferedSource.readCodePointSet(): RangeListCodePointSet { skipWhitespace() val startCodePoint = readHexadecimalUnsignedLong().toInt() skipWhitespace() - val intRange = when (select(optionsSemicolonOrNewlineOrDash)) { - 0 -> { - // ; - skipRestOfLine() - IntRange(startCodePoint, startCodePoint) - } - 1 -> { - // '\n' - IntRange(startCodePoint, startCodePoint) - } - 2 -> { - // '-' - val endCodePoint = readHexadecimalUnsignedLong().toInt() - skipRestOfLine() - IntRange(startCodePoint, endCodePoint) - } - else -> { - throw IOException("expected ';'") + val intRange = + when (select(optionsSemicolonOrNewlineOrDash)) { + 0 -> { + // ; + skipRestOfLine() + IntRange(startCodePoint, startCodePoint) + } + 1 -> { + // '\n' + IntRange(startCodePoint, startCodePoint) + } + 2 -> { + // '-' + val endCodePoint = readHexadecimalUnsignedLong().toInt() + skipRestOfLine() + IntRange(startCodePoint, endCodePoint) + } + else -> { + throw IOException("expected ';'") + } } - } result += intRange } return RangeListCodePointSet(result) @@ -184,13 +188,13 @@ private fun BufferedSource.skipRestOfLine() { } class MappingListCodePointMapping( - val mappings: Map + val mappings: Map, ) : CodePointMapping { override fun get(codePoint: Int) = mappings[codePoint] } class RangeListCodePointSet( val ranges: List, -): CodePointSet { +) : CodePointSet { override fun contains(codePoint: Int) = ranges.any { codePoint in it } } diff --git a/okhttp/src/test/java/okhttp3/internal/idn/StringprepTablesReaderTest.kt b/okhttp/src/test/java/okhttp3/internal/idn/StringprepTablesReaderTest.kt index 25f8c77f1f4d..9c06b0375477 100644 --- a/okhttp/src/test/java/okhttp3/internal/idn/StringprepTablesReaderTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/idn/StringprepTablesReaderTest.kt @@ -42,23 +42,21 @@ class StringprepTablesReaderTest { | 0234-024F | 0000-001F; [CONTROL CHARACTERS] | 007F; DELETE - |""".trimMargin() + | + """.trimMargin(), ) val rangeList = buffer.readCodePointSet() assertEquals( listOf( 0x0221..0x0221, - 0x0234..0x024f, - // [CONTROL CHARACTERS]. 0x0000..0x001f, - // DELETE. 0x007f..0x007f, ), - rangeList.ranges + rangeList.ranges, ) } @@ -69,7 +67,8 @@ class StringprepTablesReaderTest { | 180C; ; Map to nothing | 0041; 0061; Case map | 0390; 03B9 0308 0301; Case map - |""".trimMargin() + | + """.trimMargin(), ) val mappings = buffer.readCodePointMappings() @@ -77,14 +76,12 @@ class StringprepTablesReaderTest { mapOf( // Map to nothing. 0x180c to "", - // Case map. 'A'.code to "a", - // Case map. - 'ΐ'.code to "\u03B9\u0308\u0301" + 'ΐ'.code to "\u03B9\u0308\u0301", ), - mappings.mappings + mappings.mappings, ) } } diff --git a/okhttp/src/test/java/okhttp3/internal/idn/StringprepTest.kt b/okhttp/src/test/java/okhttp3/internal/idn/StringprepTest.kt index c611159f81f8..c2701d2759bb 100644 --- a/okhttp/src/test/java/okhttp3/internal/idn/StringprepTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/idn/StringprepTest.kt @@ -27,13 +27,14 @@ import org.junit.Test class StringprepTest { private val reader = StringprepTablesReader(FileSystem.RESOURCES) private val rfc3491 = reader.readNameprep("/okhttp3/internal/idn".toPath()) - private val stringPrep = Stringprep( - unassigned = RangeListCodePointSet(listOf()), - mapping = rfc3491.mapping, - prohibitSet = rfc3491.prohibitSet, - randalcatSet = rfc3491.randalcatSet, - lcatSet = rfc3491.lcatSet, - ) + private val stringPrep = + Stringprep( + unassigned = RangeListCodePointSet(listOf()), + mapping = rfc3491.mapping, + prohibitSet = rfc3491.prohibitSet, + randalcatSet = rfc3491.randalcatSet, + lcatSet = rfc3491.lcatSet, + ) @Test fun mappedToNothing() { assertThat(stringPrep("a\u00ADz")).isEqualTo("az") diff --git a/okhttp/src/test/java/okhttp3/internal/io/FaultyFileSystem.kt b/okhttp/src/test/java/okhttp3/internal/io/FaultyFileSystem.kt index 712f8b53ddfa..4c1f4a4b79bc 100644 --- a/okhttp/src/test/java/okhttp3/internal/io/FaultyFileSystem.kt +++ b/okhttp/src/test/java/okhttp3/internal/io/FaultyFileSystem.kt @@ -28,7 +28,10 @@ class FaultyFileSystem constructor(delegate: FileSystem?) : ForwardingFileSystem private val deleteFaults: MutableSet = LinkedHashSet() private val renameFaults: MutableSet = LinkedHashSet() - fun setFaultyWrite(file: Path, faulty: Boolean) { + fun setFaultyWrite( + file: Path, + faulty: Boolean, + ) { if (faulty) { writeFaults.add(file) } else { @@ -36,7 +39,10 @@ class FaultyFileSystem constructor(delegate: FileSystem?) : ForwardingFileSystem } } - fun setFaultyDelete(file: Path, faulty: Boolean) { + fun setFaultyDelete( + file: Path, + faulty: Boolean, + ) { if (faulty) { deleteFaults.add(file) } else { @@ -44,7 +50,10 @@ class FaultyFileSystem constructor(delegate: FileSystem?) : ForwardingFileSystem } } - fun setFaultyRename(file: Path, faulty: Boolean) { + fun setFaultyRename( + file: Path, + faulty: Boolean, + ) { if (faulty) { renameFaults.add(file) } else { @@ -53,31 +62,47 @@ class FaultyFileSystem constructor(delegate: FileSystem?) : ForwardingFileSystem } @Throws(IOException::class) - override fun atomicMove(source: Path, target: Path) { + override fun atomicMove( + source: Path, + target: Path, + ) { if (renameFaults.contains(source) || renameFaults.contains(target)) throw IOException("boom!") super.atomicMove(source, target) } @Throws(IOException::class) - override fun delete(path: Path, mustExist: Boolean) { + override fun delete( + path: Path, + mustExist: Boolean, + ) { if (deleteFaults.contains(path)) throw IOException("boom!") super.delete(path, mustExist) } @Throws(IOException::class) - override fun deleteRecursively(fileOrDirectory: Path, mustExist: Boolean) { + override fun deleteRecursively( + fileOrDirectory: Path, + mustExist: Boolean, + ) { if (deleteFaults.contains(fileOrDirectory)) throw IOException("boom!") super.deleteRecursively(fileOrDirectory, mustExist) } - override fun appendingSink(file: Path, mustExist: Boolean): Sink = - FaultySink(super.appendingSink(file, mustExist), file) + override fun appendingSink( + file: Path, + mustExist: Boolean, + ): Sink = FaultySink(super.appendingSink(file, mustExist), file) - override fun sink(file: Path, mustCreate: Boolean): Sink = - FaultySink(super.sink(file, mustCreate), file) + override fun sink( + file: Path, + mustCreate: Boolean, + ): Sink = FaultySink(super.sink(file, mustCreate), file) inner class FaultySink(sink: Sink, private val file: Path) : ForwardingSink(sink) { - override fun write(source: Buffer, byteCount: Long) { + override fun write( + source: Buffer, + byteCount: Long, + ) { if (writeFaults.contains(file)) { throw IOException("boom!") } else { diff --git a/okhttp/src/test/java/okhttp3/internal/platform/Jdk9PlatformTest.kt b/okhttp/src/test/java/okhttp3/internal/platform/Jdk9PlatformTest.kt index bb7ebe12faba..301023985afe 100644 --- a/okhttp/src/test/java/okhttp3/internal/platform/Jdk9PlatformTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/platform/Jdk9PlatformTest.kt @@ -56,11 +56,12 @@ class Jdk9PlatformTest { @Test fun selectedProtocolIsNullWhenSslSocketThrowsExceptionForApplicationProtocol() { platform.assumeJdk9() - val applicationProtocolUnsupported = object : DelegatingSSLSocket(null) { - override fun getApplicationProtocol(): String { - throw UnsupportedOperationException("Mock exception") + val applicationProtocolUnsupported = + object : DelegatingSSLSocket(null) { + override fun getApplicationProtocol(): String { + throw UnsupportedOperationException("Mock exception") + } } - } assertThat(Jdk9Platform().getSelectedProtocol(applicationProtocolUnsupported)).isNull() } } diff --git a/okhttp/src/test/java/okhttp3/internal/platform/android/AndroidSocketAdapterTest.kt b/okhttp/src/test/java/okhttp3/internal/platform/android/AndroidSocketAdapterTest.kt index 65f7d3ede510..0d1b3e57f0ec 100644 --- a/okhttp/src/test/java/okhttp3/internal/platform/android/AndroidSocketAdapterTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/platform/android/AndroidSocketAdapterTest.kt @@ -36,7 +36,8 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource class AndroidSocketAdapterTest { - @RegisterExtension @JvmField val platform = PlatformRule() + @RegisterExtension @JvmField + val platform = PlatformRule() @BeforeEach fun setUp() { @@ -90,7 +91,7 @@ class AndroidSocketAdapterTest { assertFalse(adapter.matchesSocketFactory(socketFactory)) val sslSocket = - object : DelegatingSSLSocket(context.socketFactory.createSocket() as SSLSocket) {} + object : DelegatingSSLSocket(context.socketFactory.createSocket() as SSLSocket) {} assertFalse(adapter.matchesSocket(sslSocket)) adapter.configureTlsExtensions(sslSocket, null, listOf(HTTP_2, HTTP_1_1)) @@ -102,9 +103,9 @@ class AndroidSocketAdapterTest { @JvmStatic fun data(): Collection { return listOfNotNull( - DeferredSocketAdapter(ConscryptSocketAdapter.factory), - DeferredSocketAdapter(AndroidSocketAdapter.factory("org.conscrypt")), - StandardAndroidSocketAdapter.buildIfSupported("org.conscrypt") + DeferredSocketAdapter(ConscryptSocketAdapter.factory), + DeferredSocketAdapter(AndroidSocketAdapter.factory("org.conscrypt")), + StandardAndroidSocketAdapter.buildIfSupported("org.conscrypt"), ) } } diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt index 6614a19994b9..e264cb34e36c 100644 --- a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt @@ -32,11 +32,13 @@ import org.junit.jupiter.api.Test class PublicSuffixDatabaseTest { private val publicSuffixDatabase = PublicSuffixDatabase() + @Test fun longestMatchWins() { - val buffer = Buffer() - .writeUtf8("com\n") - .writeUtf8("my.square.com\n") - .writeUtf8("square.com\n") + val buffer = + Buffer() + .writeUtf8("com\n") + .writeUtf8("my.square.com\n") + .writeUtf8("square.com\n") publicSuffixDatabase.setListBytes(buffer.readByteArray(), byteArrayOf()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("example.com")) .isEqualTo("example.com") @@ -49,10 +51,11 @@ class PublicSuffixDatabaseTest { } @Test fun wildcardMatch() { - val buffer = Buffer() - .writeUtf8("*.square.com\n") - .writeUtf8("com\n") - .writeUtf8("example.com\n") + val buffer = + Buffer() + .writeUtf8("*.square.com\n") + .writeUtf8("com\n") + .writeUtf8("example.com\n") publicSuffixDatabase.setListBytes(buffer.readByteArray(), byteArrayOf()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("my.square.com")).isNull() assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("foo.my.square.com")) @@ -62,10 +65,11 @@ class PublicSuffixDatabaseTest { } @Test fun boundarySearches() { - val buffer = Buffer() - .writeUtf8("bbb\n") - .writeUtf8("ddd\n") - .writeUtf8("fff\n") + val buffer = + Buffer() + .writeUtf8("bbb\n") + .writeUtf8("ddd\n") + .writeUtf8("fff\n") publicSuffixDatabase.setListBytes(buffer.readByteArray(), byteArrayOf()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("aaa")).isNull() assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("ggg")).isNull() @@ -74,13 +78,15 @@ class PublicSuffixDatabaseTest { } @Test fun exceptionRule() { - val exception = Buffer() - .writeUtf8("my.square.jp\n") - val buffer = Buffer() - .writeUtf8("*.jp\n") - .writeUtf8("*.square.jp\n") - .writeUtf8("example.com\n") - .writeUtf8("square.com\n") + val exception = + Buffer() + .writeUtf8("my.square.jp\n") + val buffer = + Buffer() + .writeUtf8("*.jp\n") + .writeUtf8("*.square.jp\n") + .writeUtf8("example.com\n") + .writeUtf8("square.com\n") publicSuffixDatabase.setListBytes(buffer.readByteArray(), exception.readByteArray()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("my.square.jp")) .isEqualTo("my.square.jp") @@ -90,13 +96,15 @@ class PublicSuffixDatabaseTest { } @Test fun noEffectiveTldPlusOne() { - val exception = Buffer() - .writeUtf8("my.square.jp\n") - val buffer = Buffer() - .writeUtf8("*.jp\n") - .writeUtf8("*.square.jp\n") - .writeUtf8("example.com\n") - .writeUtf8("square.com\n") + val exception = + Buffer() + .writeUtf8("my.square.jp\n") + val buffer = + Buffer() + .writeUtf8("*.jp\n") + .writeUtf8("*.square.jp\n") + .writeUtf8("example.com\n") + .writeUtf8("square.com\n") publicSuffixDatabase.setListBytes(buffer.readByteArray(), exception.readByteArray()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("example.com")).isNull() assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("foo.square.jp")).isNull() @@ -105,11 +113,11 @@ class PublicSuffixDatabaseTest { @Test fun allPublicSuffixes() { val buffer = Buffer() FileSystem.RESOURCES.source(PublicSuffixDatabase.PUBLIC_SUFFIX_RESOURCE).use { resource -> - GzipSource(resource).buffer().use { source -> - val length = source.readInt() - buffer.write(source, length.toLong()) - } + GzipSource(resource).buffer().use { source -> + val length = source.readInt() + buffer.write(source, length.toLong()) } + } while (!buffer.exhausted()) { var publicSuffix = buffer.readUtf8LineStrict() if (publicSuffix.contains("*")) { @@ -125,17 +133,17 @@ class PublicSuffixDatabaseTest { @Test fun publicSuffixExceptions() { val buffer = Buffer() FileSystem.RESOURCES.source(PublicSuffixDatabase.PUBLIC_SUFFIX_RESOURCE).use { resource -> - GzipSource(resource).buffer().use { source -> - var length = source.readInt() - source.skip(length.toLong()) - length = source.readInt() - buffer.write(source, length.toLong()) - } + GzipSource(resource).buffer().use { source -> + var length = source.readInt() + source.skip(length.toLong()) + length = source.readInt() + buffer.write(source, length.toLong()) } + } while (!buffer.exhausted()) { val exception = buffer.readUtf8LineStrict() assertThat(publicSuffixDatabase.getEffectiveTldPlusOne(exception)).isEqualTo( - exception + exception, ) val test = "foobar.$exception" assertThat(publicSuffixDatabase.getEffectiveTldPlusOne(test)).isEqualTo(exception) @@ -153,9 +161,10 @@ class PublicSuffixDatabaseTest { } @Test fun secondReadFailsSameAsFirst() { - val badPublicSuffixDatabase = PublicSuffixDatabase( - path = "/xxx.gz".toPath() - ) + val badPublicSuffixDatabase = + PublicSuffixDatabase( + path = "/xxx.gz".toPath(), + ) lateinit var firstFailure: Exception assertFailsWith { badPublicSuffixDatabase.getEffectiveTldPlusOne("squareup.com") @@ -189,10 +198,10 @@ class PublicSuffixDatabaseTest { checkPublicSuffix("b.example.example", "example.example") checkPublicSuffix("a.b.example.example", "example.example") // Listed, but non-Internet, TLD. - //checkPublicSuffix("local", null); - //checkPublicSuffix("example.local", null); - //checkPublicSuffix("b.example.local", null); - //checkPublicSuffix("a.b.example.local", null); + // checkPublicSuffix("local", null); + // checkPublicSuffix("example.local", null); + // checkPublicSuffix("b.example.local", null); + // checkPublicSuffix("a.b.example.local", null); // TLD with only 1 rule. checkPublicSuffix("biz", null) checkPublicSuffix("domain.biz", "domain.biz") @@ -269,7 +278,10 @@ class PublicSuffixDatabaseTest { checkPublicSuffix("xn--fiqs8s", null) } - private fun checkPublicSuffix(domain: String, registrablePart: String?) { + private fun checkPublicSuffix( + domain: String, + registrablePart: String?, + ) { val canonicalDomain = domain.toCanonicalHost() ?: return val result = publicSuffixDatabase.getEffectiveTldPlusOne(canonicalDomain) if (registrablePart == null) { diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt index 9d41a1df1742..f83112e2918a 100644 --- a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt +++ b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt @@ -47,7 +47,7 @@ import okio.gzip class PublicSuffixListGenerator( projectRoot: Path = ".".toPath(), val fileSystem: FileSystem = FileSystem.SYSTEM, - val client: OkHttpClient = OkHttpClient() + val client: OkHttpClient = OkHttpClient(), ) { private val resources = projectRoot / "okhttp/src/main/resources/okhttp3/internal/publicsuffix" private val testResources = projectRoot / "okhttp/src/test/resources/okhttp3/internal/publicsuffix" @@ -67,38 +67,40 @@ class PublicSuffixListGenerator( writeOutputFile(importResults) } - private suspend fun updateLocalFile() = withContext(Dispatchers.IO) { - client.newCall(request).executeAsync().use { response -> - fileSystem.sink(publicSuffixListDotDat).buffer().use { sink -> - sink.writeAll(response.body.source()) + private suspend fun updateLocalFile() = + withContext(Dispatchers.IO) { + client.newCall(request).executeAsync().use { response -> + fileSystem.sink(publicSuffixListDotDat).buffer().use { sink -> + sink.writeAll(response.body.source()) + } } } - } - private suspend fun readImportResults(): ImportResults = withContext(Dispatchers.IO) { - val sortedRules: SortedSet = TreeSet() - val sortedExceptionRules: SortedSet = TreeSet() - var totalRuleBytes = 0 - var totalExceptionRuleBytes = 0 - - fileSystem.source(publicSuffixListDotDat).buffer().use { source -> - while (!source.exhausted()) { - var rule: ByteString = source.readUtf8LineStrict().toRule() ?: continue - - if (rule.startsWith(EXCEPTION_RULE_MARKER)) { - rule = rule.substring(1) - // We use '\n' for end of value. - totalExceptionRuleBytes += rule.size + 1 - sortedExceptionRules.add(rule) - } else { - totalRuleBytes += rule.size + 1 // We use '\n' for end of value. - sortedRules.add(rule) + private suspend fun readImportResults(): ImportResults = + withContext(Dispatchers.IO) { + val sortedRules: SortedSet = TreeSet() + val sortedExceptionRules: SortedSet = TreeSet() + var totalRuleBytes = 0 + var totalExceptionRuleBytes = 0 + + fileSystem.source(publicSuffixListDotDat).buffer().use { source -> + while (!source.exhausted()) { + var rule: ByteString = source.readUtf8LineStrict().toRule() ?: continue + + if (rule.startsWith(EXCEPTION_RULE_MARKER)) { + rule = rule.substring(1) + // We use '\n' for end of value. + totalExceptionRuleBytes += rule.size + 1 + sortedExceptionRules.add(rule) + } else { + totalRuleBytes += rule.size + 1 // We use '\n' for end of value. + sortedRules.add(rule) + } } } - } - ImportResults(sortedRules, sortedExceptionRules, totalRuleBytes, totalExceptionRuleBytes) - } + ImportResults(sortedRules, sortedExceptionRules, totalRuleBytes, totalExceptionRuleBytes) + } private fun String.toRule(): ByteString? { if (trim { it <= ' ' }.isEmpty() || startsWith("//")) return null @@ -112,10 +114,10 @@ class PublicSuffixListGenerator( val sortedRules: SortedSet, val sortedExceptionRules: SortedSet, val totalRuleBytes: Int, - val totalExceptionRuleBytes: Int + val totalExceptionRuleBytes: Int, ) { fun writeOut(sink: BufferedSink) { - with (sink) { + with(sink) { writeInt(totalRuleBytes) for (domain in sortedRules) { write(domain).writeByte(NEWLINE) @@ -128,11 +130,12 @@ class PublicSuffixListGenerator( } } - private suspend fun writeOutputFile(importResults: ImportResults) = withContext(Dispatchers.IO) { - fileSystem.sink(outputFile).gzip().buffer().use { sink -> + private suspend fun writeOutputFile(importResults: ImportResults) = + withContext(Dispatchers.IO) { + fileSystem.sink(outputFile).gzip().buffer().use { sink -> importResults.writeOut(sink) + } } - } /** * These assertions ensure the [PublicSuffixDatabase] remains correct. The specification is diff --git a/okhttp/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt b/okhttp/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt index 9dc1a8462ce2..00ed8f808e10 100644 --- a/okhttp/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt @@ -67,51 +67,60 @@ class CertificatePinnerChainValidationTest { @Test fun pinRootNotPresentInChain() { // Fails on 11.0.1 https://github.com/square/okhttp/issues/4703 - val rootCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .commonName("root") - .build() - val intermediateCa = HeldCertificate.Builder() - .signedBy(rootCa) - .certificateAuthority(0) - .serialNumber(2L) - .commonName("intermediate_ca") - .build() - val certificate = HeldCertificate.Builder() - .signedBy(intermediateCa) - .serialNumber(3L) - .commonName(server.hostName) - .build() - val certificatePinner = CertificatePinner.Builder() - .add(server.hostName, pin(rootCa.certificate)) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(rootCa.certificate) - .build() - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .certificatePinner(certificatePinner) - .build() - val serverHandshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate(certificate, intermediateCa.certificate) - .build() + val rootCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .commonName("root") + .build() + val intermediateCa = + HeldCertificate.Builder() + .signedBy(rootCa) + .certificateAuthority(0) + .serialNumber(2L) + .commonName("intermediate_ca") + .build() + val certificate = + HeldCertificate.Builder() + .signedBy(intermediateCa) + .serialNumber(3L) + .commonName(server.hostName) + .build() + val certificatePinner = + CertificatePinner.Builder() + .add(server.hostName, pin(rootCa.certificate)) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(rootCa.certificate) + .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .certificatePinner(certificatePinner) + .build() + val serverHandshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate(certificate, intermediateCa.certificate) + .build() server.useHttps(serverHandshakeCertificates.sslSocketFactory()) // The request should complete successfully. server.enqueue( MockResponse.Builder() .body("abc") - .build() - ) - val call1 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call1 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response1 = call1.execute() assertThat(response1.body.string()).isEqualTo("abc") } @@ -122,38 +131,46 @@ class CertificatePinnerChainValidationTest { @Test fun pinIntermediatePresentInChain() { // Fails on 11.0.1 https://github.com/square/okhttp/issues/4703 - val rootCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .commonName("root") - .build() - val intermediateCa = HeldCertificate.Builder() - .signedBy(rootCa) - .certificateAuthority(0) - .serialNumber(2L) - .commonName("intermediate_ca") - .build() - val certificate = HeldCertificate.Builder() - .signedBy(intermediateCa) - .serialNumber(3L) - .commonName(server.hostName) - .build() - val certificatePinner = CertificatePinner.Builder() - .add(server.hostName, pin(intermediateCa.certificate)) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(rootCa.certificate) - .build() - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .certificatePinner(certificatePinner) - .build() - val serverHandshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate(certificate, intermediateCa.certificate) - .build() + val rootCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .commonName("root") + .build() + val intermediateCa = + HeldCertificate.Builder() + .signedBy(rootCa) + .certificateAuthority(0) + .serialNumber(2L) + .commonName("intermediate_ca") + .build() + val certificate = + HeldCertificate.Builder() + .signedBy(intermediateCa) + .serialNumber(3L) + .commonName(server.hostName) + .build() + val certificatePinner = + CertificatePinner.Builder() + .add(server.hostName, pin(intermediateCa.certificate)) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(rootCa.certificate) + .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .certificatePinner(certificatePinner) + .build() + val serverHandshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate(certificate, intermediateCa.certificate) + .build() server.useHttps(serverHandshakeCertificates.sslSocketFactory()) // The request should complete successfully. @@ -161,13 +178,14 @@ class CertificatePinnerChainValidationTest { MockResponse.Builder() .body("abc") .socketPolicy(DisconnectAtEnd) - .build() - ) - val call1 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call1 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response1 = call1.execute() assertThat(response1.body.string()).isEqualTo("abc") response1.close() @@ -180,13 +198,14 @@ class CertificatePinnerChainValidationTest { MockResponse.Builder() .body("def") .socketPolicy(DisconnectAtEnd) - .build() - ) - val call2 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call2 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response2 = call2.execute() assertThat(response2.body.string()).isEqualTo("def") response2.close() @@ -200,72 +219,84 @@ class CertificatePinnerChainValidationTest { platform.expectFailureOnLoomPlatform() // Start with a trusted root CA certificate. - val rootCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .commonName("root") - .build() + val rootCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .commonName("root") + .build() // Add a good intermediate CA, and have that issue a good certificate to localhost. Prepare an // SSL context for an HTTP client under attack. It includes the trusted CA and a pinned // certificate. - val goodIntermediateCa = HeldCertificate.Builder() - .signedBy(rootCa) - .certificateAuthority(0) - .serialNumber(2L) - .commonName("good_intermediate_ca") - .build() - val goodCertificate = HeldCertificate.Builder() - .signedBy(goodIntermediateCa) - .serialNumber(3L) - .commonName(server.hostName) - .build() - val certificatePinner = CertificatePinner.Builder() - .add(server.hostName, pin(goodCertificate.certificate)) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(rootCa.certificate) - .build() - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .certificatePinner(certificatePinner) - .build() + val goodIntermediateCa = + HeldCertificate.Builder() + .signedBy(rootCa) + .certificateAuthority(0) + .serialNumber(2L) + .commonName("good_intermediate_ca") + .build() + val goodCertificate = + HeldCertificate.Builder() + .signedBy(goodIntermediateCa) + .serialNumber(3L) + .commonName(server.hostName) + .build() + val certificatePinner = + CertificatePinner.Builder() + .add(server.hostName, pin(goodCertificate.certificate)) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(rootCa.certificate) + .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .certificatePinner(certificatePinner) + .build() // Add a bad intermediate CA and have that issue a rogue certificate for localhost. Prepare // an SSL context for an attacking webserver. It includes both these rogue certificates plus the // trusted good certificate above. The attack is that by including the good certificate in the // chain, we may trick the certificate pinner into accepting the rouge certificate. - val compromisedIntermediateCa = HeldCertificate.Builder() - .signedBy(rootCa) - .certificateAuthority(0) - .serialNumber(4L) - .commonName("bad_intermediate_ca") - .build() - val rogueCertificate = HeldCertificate.Builder() - .serialNumber(5L) - .signedBy(compromisedIntermediateCa) - .commonName(server.hostName) - .build() - val socketFactory = newServerSocketFactory( - rogueCertificate, - compromisedIntermediateCa.certificate, goodCertificate.certificate - ) + val compromisedIntermediateCa = + HeldCertificate.Builder() + .signedBy(rootCa) + .certificateAuthority(0) + .serialNumber(4L) + .commonName("bad_intermediate_ca") + .build() + val rogueCertificate = + HeldCertificate.Builder() + .serialNumber(5L) + .signedBy(compromisedIntermediateCa) + .commonName(server.hostName) + .build() + val socketFactory = + newServerSocketFactory( + rogueCertificate, + compromisedIntermediateCa.certificate, + goodCertificate.certificate, + ) server.useHttps(socketFactory) server.enqueue( MockResponse.Builder() .body("abc") .addHeader("Content-Type: text/plain") - .build() + .build(), ) // Make a request from client to server. It should succeed certificate checks (unfortunately the // rogue CA is trusted) but it should fail certificate pinning. - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) assertFailsWith { call.execute() @@ -283,73 +314,85 @@ class CertificatePinnerChainValidationTest { platform.expectFailureOnLoomPlatform() // Start with two root CA certificates, one is good and the other is compromised. - val rootCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .commonName("root") - .build() - val compromisedRootCa = HeldCertificate.Builder() - .serialNumber(2L) - .certificateAuthority(1) - .commonName("compromised_root") - .build() + val rootCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .commonName("root") + .build() + val compromisedRootCa = + HeldCertificate.Builder() + .serialNumber(2L) + .certificateAuthority(1) + .commonName("compromised_root") + .build() // Add a good intermediate CA, and have that issue a good certificate to localhost. Prepare an // SSL context for an HTTP client under attack. It includes the trusted CA and a pinned // certificate. - val goodIntermediateCa = HeldCertificate.Builder() - .signedBy(rootCa) - .certificateAuthority(0) - .serialNumber(3L) - .commonName("intermediate_ca") - .build() - val certificatePinner = CertificatePinner.Builder() - .add(server.hostName, pin(goodIntermediateCa.certificate)) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(rootCa.certificate) - .addTrustedCertificate(compromisedRootCa.certificate) - .build() - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .certificatePinner(certificatePinner) - .build() + val goodIntermediateCa = + HeldCertificate.Builder() + .signedBy(rootCa) + .certificateAuthority(0) + .serialNumber(3L) + .commonName("intermediate_ca") + .build() + val certificatePinner = + CertificatePinner.Builder() + .add(server.hostName, pin(goodIntermediateCa.certificate)) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(rootCa.certificate) + .addTrustedCertificate(compromisedRootCa.certificate) + .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .certificatePinner(certificatePinner) + .build() // The attacker compromises the root CA, issues an intermediate with the same common name // "intermediate_ca" as the good CA. This signs a rogue certificate for localhost. The server // serves the good CAs certificate in the chain, which means the certificate pinner sees a // different set of certificates than the SSL verifier. - val compromisedIntermediateCa = HeldCertificate.Builder() - .signedBy(compromisedRootCa) - .certificateAuthority(0) - .serialNumber(4L) - .commonName("intermediate_ca") - .build() - val rogueCertificate = HeldCertificate.Builder() - .serialNumber(5L) - .signedBy(compromisedIntermediateCa) - .commonName(server.hostName) - .build() - val socketFactory = newServerSocketFactory( - rogueCertificate, - goodIntermediateCa.certificate, compromisedIntermediateCa.certificate - ) + val compromisedIntermediateCa = + HeldCertificate.Builder() + .signedBy(compromisedRootCa) + .certificateAuthority(0) + .serialNumber(4L) + .commonName("intermediate_ca") + .build() + val rogueCertificate = + HeldCertificate.Builder() + .serialNumber(5L) + .signedBy(compromisedIntermediateCa) + .commonName(server.hostName) + .build() + val socketFactory = + newServerSocketFactory( + rogueCertificate, + goodIntermediateCa.certificate, + compromisedIntermediateCa.certificate, + ) server.useHttps(socketFactory) server.enqueue( MockResponse.Builder() .body("abc") .addHeader("Content-Type: text/plain") - .build() + .build(), ) // Make a request from client to server. It should succeed certificate checks (unfortunately the // rogue CA is trusted) but it should fail certificate pinning. - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) assertFailsWith { call.execute() @@ -422,73 +465,85 @@ class CertificatePinnerChainValidationTest { */ @Test fun signersMustHaveCaBitSet() { - val attackerCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(4) - .commonName("attacker ca") - .build() - val attackerIntermediate = HeldCertificate.Builder() - .serialNumber(2L) - .certificateAuthority(3) - .commonName("attacker") - .signedBy(attackerCa) - .build() - val pinnedRoot = HeldCertificate.Builder() - .serialNumber(3L) - .certificateAuthority(2) - .commonName("pinned root") - .signedBy(attackerIntermediate) - .build() - val pinnedIntermediate = HeldCertificate.Builder() - .serialNumber(4L) - .certificateAuthority(1) - .commonName("pinned intermediate") - .signedBy(pinnedRoot) - .build() - val attackerSwitch = HeldCertificate.Builder() - .serialNumber(5L) - .keyPair(attackerIntermediate.keyPair) // share keys between compromised CA and leaf! - .commonName("attacker") - .addSubjectAlternativeName("attacker.com") - .signedBy(pinnedIntermediate) - .build() - val phonyVictim = HeldCertificate.Builder() - .serialNumber(6L) - .signedBy(attackerSwitch) - .addSubjectAlternativeName("victim.com") - .commonName("victim") - .build() - val certificatePinner = CertificatePinner.Builder() - .add(server.hostName, pin(pinnedRoot.certificate)) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(pinnedRoot.certificate) - .addTrustedCertificate(attackerCa.certificate) - .build() - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .certificatePinner(certificatePinner) - .build() - val serverHandshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate( - phonyVictim, - attackerSwitch.certificate, - pinnedIntermediate.certificate, - pinnedRoot.certificate, - attackerIntermediate.certificate - ) - .build() + val attackerCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(4) + .commonName("attacker ca") + .build() + val attackerIntermediate = + HeldCertificate.Builder() + .serialNumber(2L) + .certificateAuthority(3) + .commonName("attacker") + .signedBy(attackerCa) + .build() + val pinnedRoot = + HeldCertificate.Builder() + .serialNumber(3L) + .certificateAuthority(2) + .commonName("pinned root") + .signedBy(attackerIntermediate) + .build() + val pinnedIntermediate = + HeldCertificate.Builder() + .serialNumber(4L) + .certificateAuthority(1) + .commonName("pinned intermediate") + .signedBy(pinnedRoot) + .build() + val attackerSwitch = + HeldCertificate.Builder() + .serialNumber(5L) + .keyPair(attackerIntermediate.keyPair) // share keys between compromised CA and leaf! + .commonName("attacker") + .addSubjectAlternativeName("attacker.com") + .signedBy(pinnedIntermediate) + .build() + val phonyVictim = + HeldCertificate.Builder() + .serialNumber(6L) + .signedBy(attackerSwitch) + .addSubjectAlternativeName("victim.com") + .commonName("victim") + .build() + val certificatePinner = + CertificatePinner.Builder() + .add(server.hostName, pin(pinnedRoot.certificate)) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(pinnedRoot.certificate) + .addTrustedCertificate(attackerCa.certificate) + .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .certificatePinner(certificatePinner) + .build() + val serverHandshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate( + phonyVictim, + attackerSwitch.certificate, + pinnedIntermediate.certificate, + pinnedRoot.certificate, + attackerIntermediate.certificate, + ) + .build() server.useHttps(serverHandshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse()) // Make a request from client to server. It should succeed certificate checks (unfortunately the // rogue CA is trusted) but it should fail certificate pinning. - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) assertFailsWith { call.execute() @@ -531,65 +586,76 @@ class CertificatePinnerChainValidationTest { */ @Test fun intermediateMustNotHaveMoreIntermediatesThanSigner() { - val attackerCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(2) - .commonName("attacker ca") - .build() - val pinnedRoot = HeldCertificate.Builder() - .serialNumber(2L) - .certificateAuthority(1) - .commonName("pinned root") - .signedBy(attackerCa) - .build() - val compromisedIntermediate = HeldCertificate.Builder() - .serialNumber(3L) - .certificateAuthority(0) - .commonName("compromised intermediate") - .signedBy(pinnedRoot) - .build() - val attackerIntermediate = HeldCertificate.Builder() - .keyPair(attackerCa.keyPair) // Share keys between compromised CA and intermediate! - .serialNumber(4L) - .certificateAuthority(0) // More intermediates than permitted by signer! - .commonName("attacker intermediate") - .signedBy(compromisedIntermediate) - .build() - val phonyVictim = HeldCertificate.Builder() - .serialNumber(5L) - .signedBy(attackerIntermediate) - .addSubjectAlternativeName("victim.com") - .commonName("victim") - .build() - val certificatePinner = CertificatePinner.Builder() - .add(server.hostName, pin(pinnedRoot.certificate)) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(pinnedRoot.certificate) - .addTrustedCertificate(attackerCa.certificate) - .build() - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .certificatePinner(certificatePinner) - .build() - val serverHandshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate( - phonyVictim, - attackerIntermediate.certificate, - compromisedIntermediate.certificate, - pinnedRoot.certificate - ) - .build() + val attackerCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(2) + .commonName("attacker ca") + .build() + val pinnedRoot = + HeldCertificate.Builder() + .serialNumber(2L) + .certificateAuthority(1) + .commonName("pinned root") + .signedBy(attackerCa) + .build() + val compromisedIntermediate = + HeldCertificate.Builder() + .serialNumber(3L) + .certificateAuthority(0) + .commonName("compromised intermediate") + .signedBy(pinnedRoot) + .build() + val attackerIntermediate = + HeldCertificate.Builder() + .keyPair(attackerCa.keyPair) // Share keys between compromised CA and intermediate! + .serialNumber(4L) + .certificateAuthority(0) // More intermediates than permitted by signer! + .commonName("attacker intermediate") + .signedBy(compromisedIntermediate) + .build() + val phonyVictim = + HeldCertificate.Builder() + .serialNumber(5L) + .signedBy(attackerIntermediate) + .addSubjectAlternativeName("victim.com") + .commonName("victim") + .build() + val certificatePinner = + CertificatePinner.Builder() + .add(server.hostName, pin(pinnedRoot.certificate)) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(pinnedRoot.certificate) + .addTrustedCertificate(attackerCa.certificate) + .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .certificatePinner(certificatePinner) + .build() + val serverHandshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate( + phonyVictim, + attackerIntermediate.certificate, + compromisedIntermediate.certificate, + pinnedRoot.certificate, + ) + .build() server.useHttps(serverHandshakeCertificates.sslSocketFactory()) server.enqueue(MockResponse()) // Make a request from client to server. It should not succeed certificate checks. - val request = Request.Builder() - .url(server.url("/")) - .build() + val request = + Request.Builder() + .url(server.url("/")) + .build() val call = client.newCall(request) assertFailsWith { call.execute() @@ -598,46 +664,53 @@ class CertificatePinnerChainValidationTest { @Test fun lonePinnedCertificate() { - val onlyCertificate = HeldCertificate.Builder() - .serialNumber(1L) - .commonName("root") - .build() - val certificatePinner = CertificatePinner.Builder() - .add(server.hostName, pin(onlyCertificate.certificate)) - .build() - val handshakeCertificates = HandshakeCertificates.Builder() - .addTrustedCertificate(onlyCertificate.certificate) - .build() - val client = clientTestRule.newClientBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .certificatePinner(certificatePinner) - .build() - val serverHandshakeCertificates = HandshakeCertificates.Builder() - .heldCertificate(onlyCertificate) - .build() + val onlyCertificate = + HeldCertificate.Builder() + .serialNumber(1L) + .commonName("root") + .build() + val certificatePinner = + CertificatePinner.Builder() + .add(server.hostName, pin(onlyCertificate.certificate)) + .build() + val handshakeCertificates = + HandshakeCertificates.Builder() + .addTrustedCertificate(onlyCertificate.certificate) + .build() + val client = + clientTestRule.newClientBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .certificatePinner(certificatePinner) + .build() + val serverHandshakeCertificates = + HandshakeCertificates.Builder() + .heldCertificate(onlyCertificate) + .build() server.useHttps(serverHandshakeCertificates.sslSocketFactory()) // The request should complete successfully. server.enqueue( MockResponse.Builder() .body("abc") - .build() - ) - val call1 = client.newCall( - Request.Builder() - .url(server.url("/")) - .build() + .build(), ) + val call1 = + client.newCall( + Request.Builder() + .url(server.url("/")) + .build(), + ) val response1 = call1.execute() assertThat(response1.body.string()).isEqualTo("abc") } private fun newServerSocketFactory( heldCertificate: HeldCertificate, - vararg intermediates: X509Certificate + vararg intermediates: X509Certificate, ): SSLSocketFactory { // Test setup fails on JDK9 // java.security.KeyStoreException: Certificate chain is not valid @@ -646,13 +719,17 @@ class CertificatePinnerChainValidationTest { // http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/2c1c21d11e58/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java#l596 val keystoreType = if (platform.isJdk9()) "JKS" else null val x509KeyManager = newKeyManager(keystoreType, heldCertificate, *intermediates) - val trustManager = newTrustManager( - keystoreType, emptyList(), emptyList() - ) + val trustManager = + newTrustManager( + keystoreType, + emptyList(), + emptyList(), + ) val sslContext = get().newSSLContext() sslContext.init( - arrayOf(x509KeyManager), arrayOf(trustManager), - SecureRandom() + arrayOf(x509KeyManager), + arrayOf(trustManager), + SecureRandom(), ) return sslContext.socketFactory } diff --git a/okhttp/src/test/java/okhttp3/internal/tls/ClientAuthTest.kt b/okhttp/src/test/java/okhttp3/internal/tls/ClientAuthTest.kt index 817eb40dfc68..4249ad08d933 100644 --- a/okhttp/src/test/java/okhttp3/internal/tls/ClientAuthTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/tls/ClientAuthTest.kt @@ -78,44 +78,50 @@ class ClientAuthTest { this.server = server platform.assumeNotOpenJSSE() platform.assumeNotBouncyCastle() - serverRootCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .commonName("root") - .addSubjectAlternativeName("root_ca.com") - .build() - serverIntermediateCa = HeldCertificate.Builder() - .signedBy(serverRootCa) - .certificateAuthority(0) - .serialNumber(2L) - .commonName("intermediate_ca") - .addSubjectAlternativeName("intermediate_ca.com") - .build() - serverCert = HeldCertificate.Builder() - .signedBy(serverIntermediateCa) - .serialNumber(3L) - .commonName("Local Host") - .addSubjectAlternativeName(server.hostName) - .build() - clientRootCa = HeldCertificate.Builder() - .serialNumber(1L) - .certificateAuthority(1) - .commonName("root") - .addSubjectAlternativeName("root_ca.com") - .build() - clientIntermediateCa = HeldCertificate.Builder() - .signedBy(serverRootCa) - .certificateAuthority(0) - .serialNumber(2L) - .commonName("intermediate_ca") - .addSubjectAlternativeName("intermediate_ca.com") - .build() - clientCert = HeldCertificate.Builder() - .signedBy(clientIntermediateCa) - .serialNumber(4L) - .commonName("Jethro Willis") - .addSubjectAlternativeName("jethrowillis.com") - .build() + serverRootCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .commonName("root") + .addSubjectAlternativeName("root_ca.com") + .build() + serverIntermediateCa = + HeldCertificate.Builder() + .signedBy(serverRootCa) + .certificateAuthority(0) + .serialNumber(2L) + .commonName("intermediate_ca") + .addSubjectAlternativeName("intermediate_ca.com") + .build() + serverCert = + HeldCertificate.Builder() + .signedBy(serverIntermediateCa) + .serialNumber(3L) + .commonName("Local Host") + .addSubjectAlternativeName(server.hostName) + .build() + clientRootCa = + HeldCertificate.Builder() + .serialNumber(1L) + .certificateAuthority(1) + .commonName("root") + .addSubjectAlternativeName("root_ca.com") + .build() + clientIntermediateCa = + HeldCertificate.Builder() + .signedBy(serverRootCa) + .certificateAuthority(0) + .serialNumber(2L) + .commonName("intermediate_ca") + .addSubjectAlternativeName("intermediate_ca.com") + .build() + clientCert = + HeldCertificate.Builder() + .signedBy(clientIntermediateCa) + .serialNumber(4L) + .commonName("Jethro Willis") + .addSubjectAlternativeName("jethrowillis.com") + .build() } @Test @@ -127,7 +133,7 @@ class ClientAuthTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() + .build(), ) val call = client.newCall(Request.Builder().url(server.url("/")).build()) val response = call.execute() @@ -147,15 +153,15 @@ class ClientAuthTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() + .build(), ) val call = client.newCall(Request.Builder().url(server.url("/")).build()) val response = call.execute() assertThat(response.handshake!!.peerPrincipal).isEqualTo( - X500Principal("CN=Local Host") + X500Principal("CN=Local Host"), ) assertThat(response.handshake!!.localPrincipal).isEqualTo( - X500Principal("CN=Jethro Willis") + X500Principal("CN=Jethro Willis"), ) assertThat(response.body.string()).isEqualTo("abc") } @@ -169,12 +175,12 @@ class ClientAuthTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() + .build(), ) val call = client.newCall(Request.Builder().url(server.url("/")).build()) val response = call.execute() assertThat(response.handshake!!.peerPrincipal).isEqualTo( - X500Principal("CN=Local Host") + X500Principal("CN=Local Host"), ) assertThat(response.handshake!!.localPrincipal).isNull() assertThat(response.body.string()).isEqualTo("abc") @@ -189,12 +195,12 @@ class ClientAuthTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() + .build(), ) val call = client.newCall(Request.Builder().url(server.url("/")).build()) val response = call.execute() assertThat(response.handshake!!.peerPrincipal).isEqualTo( - X500Principal("CN=Local Host") + X500Principal("CN=Local Host"), ) assertThat(response.handshake!!.localPrincipal).isNull() assertThat(response.body.string()).isEqualTo("abc") @@ -232,12 +238,13 @@ class ClientAuthTest { @Test fun commonNameIsNotTrusted() { - serverCert = HeldCertificate.Builder() - .signedBy(serverIntermediateCa) - .serialNumber(3L) - .commonName(server.hostName) - .addSubjectAlternativeName("different-host.com") - .build() + serverCert = + HeldCertificate.Builder() + .signedBy(serverIntermediateCa) + .serialNumber(3L) + .commonName(server.hostName) + .addSubjectAlternativeName("different-host.com") + .build() val client = buildClient(clientCert, clientIntermediateCa.certificate) val socketFactory = buildServerSslSocketFactory() server.useHttps(socketFactory) @@ -252,10 +259,11 @@ class ClientAuthTest { fun invalidClientAuthFails() { // Fails with https://github.com/square/okhttp/issues/4598 // StreamReset stream was reset: PROT... - val clientCert2 = HeldCertificate.Builder() - .serialNumber(4L) - .commonName("Jethro Willis") - .build() + val clientCert2 = + HeldCertificate.Builder() + .serialNumber(4L) + .commonName("Jethro Willis") + .build() val client = buildClient(clientCert2) val socketFactory = buildServerSslSocketFactory() server.useHttps(socketFactory) @@ -289,20 +297,22 @@ class ClientAuthTest { server.enqueue( MockResponse.Builder() .body("abc") - .build() + .build(), ) - clientCert = HeldCertificate.Builder() - .signedBy(clientIntermediateCa) - .serialNumber(4L) - .commonName("Jethro Willis") - .addSubjectAlternativeName("jethrowillis.com") - .validityInterval(1, 2) - .build() + clientCert = + HeldCertificate.Builder() + .signedBy(clientIntermediateCa) + .serialNumber(4L) + .commonName("Jethro Willis") + .addSubjectAlternativeName("jethrowillis.com") + .validityInterval(1, 2) + .build() var client = buildClient(clientCert, clientIntermediateCa.certificate) val listener = RecordingEventListener() - client = client.newBuilder() - .eventListener(listener) - .build() + client = + client.newBuilder() + .eventListener(listener) + .build() val socketFactory = buildServerSslSocketFactory() server.useHttps(socketFactory) server.requireClientAuth() @@ -330,23 +340,26 @@ class ClientAuthTest { "DnsStart", "DnsEnd", "ConnectStart", - "SecureConnectStart" + "SecureConnectStart", ) assertThat(recordedEventTypes).endsWith("CallFailed") } private fun buildClient( - heldCertificate: HeldCertificate?, vararg intermediates: X509Certificate + heldCertificate: HeldCertificate?, + vararg intermediates: X509Certificate, ): OkHttpClient { - val builder = HandshakeCertificates.Builder() - .addTrustedCertificate(serverRootCa.certificate) + val builder = + HandshakeCertificates.Builder() + .addTrustedCertificate(serverRootCa.certificate) if (heldCertificate != null) { builder.heldCertificate(heldCertificate, *intermediates) } val handshakeCertificates = builder.build() return clientTestRule.newClientBuilder() .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager + handshakeCertificates.sslSocketFactory(), + handshakeCertificates.trustManager, ) .build() } @@ -355,17 +368,23 @@ class ClientAuthTest { // The test uses JDK default SSL Context instead of the Platform provided one // as Conscrypt seems to have some differences, we only want to test client side here. return try { - val keyManager = newKeyManager( - null, serverCert, serverIntermediateCa.certificate - ) - val trustManager = newTrustManager( - null, - Arrays.asList(serverRootCa.certificate, clientRootCa.certificate), emptyList() - ) + val keyManager = + newKeyManager( + null, + serverCert, + serverIntermediateCa.certificate, + ) + val trustManager = + newTrustManager( + null, + Arrays.asList(serverRootCa.certificate, clientRootCa.certificate), + emptyList(), + ) val sslContext = SSLContext.getInstance("TLS") sslContext.init( - arrayOf(keyManager), arrayOf(trustManager), - SecureRandom() + arrayOf(keyManager), + arrayOf(trustManager), + SecureRandom(), ) sslContext.socketFactory } catch (e: GeneralSecurityException) { diff --git a/okhttp/src/test/java/okhttp3/internal/tls/HostnameVerifierTest.kt b/okhttp/src/test/java/okhttp3/internal/tls/HostnameVerifierTest.kt index ca76e871d0b9..33118b14a2a4 100644 --- a/okhttp/src/test/java/okhttp3/internal/tls/HostnameVerifierTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/tls/HostnameVerifierTest.kt @@ -53,35 +53,36 @@ class HostnameVerifierTest { @Test fun verifyCn() { // CN=foo.com - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aQMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzE0MVoXDTI4MTEwNTE1MzE0MVowgaQx - CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl - cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs - aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC - ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B - lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy - zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY - 07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8 - BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV - JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB - hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE - FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS - yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQC3jRmEya6sQCkmieULcvx8zz1euCk9 - fSez7BEtki8+dmfMXe3K7sH0lI8f4jJR0rbSCjpmCQLYmzC3NxBKeJOW0RcjNBpO - c2JlGO9auXv2GDP4IYiXElLJ6VSqc8WvDikv0JmCCWm0Zga+bZbR/EWN5DeEtFdF - 815CLpJZNcYwiYwGy/CVQ7w2TnXlG+mraZOz+owr+cL6J/ZesbdEWfjoS1+cUEhE - HwlNrAu8jlZ2UqSgskSWlhYdMTAP9CPHiUv9N7FcT58Itv/I4fKREINQYjDpvQcx - SaTYb9dr5sB4WLNglk7zxDtM80H518VvihTcP7FHL+Gn6g4j5fkI98+S - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aQMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzE0MVoXDTI4MTEwNTE1MzE0MVowgaQx + CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl + cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs + aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC + ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B + lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy + zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY + 07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8 + BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV + JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB + hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE + FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS + yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQC3jRmEya6sQCkmieULcvx8zz1euCk9 + fSez7BEtki8+dmfMXe3K7sH0lI8f4jJR0rbSCjpmCQLYmzC3NxBKeJOW0RcjNBpO + c2JlGO9auXv2GDP4IYiXElLJ6VSqc8WvDikv0JmCCWm0Zga+bZbR/EWN5DeEtFdF + 815CLpJZNcYwiYwGy/CVQ7w2TnXlG+mraZOz+owr+cL6J/ZesbdEWfjoS1+cUEhE + HwlNrAu8jlZ2UqSgskSWlhYdMTAP9CPHiUv9N7FcT58Itv/I4fKREINQYjDpvQcx + SaTYb9dr5sB4WLNglk7zxDtM80H518VvihTcP7FHL+Gn6g4j5fkI98+S + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("a.foo.com", session)).isFalse() assertThat(verifier.verify("bar.com", session)).isFalse() @@ -89,71 +90,73 @@ class HostnameVerifierTest { @Test fun verifyNonAsciiCn() { // CN=花子.co.jp - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIESzCCAzOgAwIBAgIJAIz+EYMBU6aTMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1NDIxNVoXDTI4MTEwNTE1NDIxNVowgakx - CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl - cnRpZmljYXRlczEVMBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkB - FhZqdWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A - MIIBCgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjU - g4pNjYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQc - wHf0ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t - 7iu1JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAn - AxK6q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArD - qUYxqJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwG - CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV - HQ4EFgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLS - rNuzA1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBALJ27i3okV/KvlDp6KMID3gd - ITl68PyItzzx+SquF8gahMh016NX73z/oVZoVUNdftla8wPUB1GwIkAnGkhQ9LHK - spBdbRiCj0gMmLCsX8SrjFvr7cYb2cK6J/fJe92l1tg/7Y4o7V/s4JBe/cy9U9w8 - a0ctuDmEBCgC784JMDtT67klRfr/2LlqWhlOEq7pUFxRLbhpquaAHSOjmIcWnVpw - 9BsO7qe46hidgn39hKh1WjKK2VcL/3YRsC4wUi0PBtFW6ScMCuMhgIRXSPU55Rae - UIlOdPjjr1SUNWGId1rD7W16Scpwnknn310FNxFMHVI0GTGFkNdkilNCFJcIoRA= - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIESzCCAzOgAwIBAgIJAIz+EYMBU6aTMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1NDIxNVoXDTI4MTEwNTE1NDIxNVowgakx + CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl + cnRpZmljYXRlczEVMBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkB + FhZqdWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A + MIIBCgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjU + g4pNjYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQc + wHf0ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t + 7iu1JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAn + AxK6q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArD + qUYxqJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwG + CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV + HQ4EFgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLS + rNuzA1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBALJ27i3okV/KvlDp6KMID3gd + ITl68PyItzzx+SquF8gahMh016NX73z/oVZoVUNdftla8wPUB1GwIkAnGkhQ9LHK + spBdbRiCj0gMmLCsX8SrjFvr7cYb2cK6J/fJe92l1tg/7Y4o7V/s4JBe/cy9U9w8 + a0ctuDmEBCgC784JMDtT67klRfr/2LlqWhlOEq7pUFxRLbhpquaAHSOjmIcWnVpw + 9BsO7qe46hidgn39hKh1WjKK2VcL/3YRsC4wUi0PBtFW6ScMCuMhgIRXSPU55Rae + UIlOdPjjr1SUNWGId1rD7W16Scpwnknn310FNxFMHVI0GTGFkNdkilNCFJcIoRA= + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("\u82b1\u5b50.co.jp", session)).isFalse() assertThat(verifier.verify("a.\u82b1\u5b50.co.jp", session)).isFalse() } @Test fun verifySubjectAlt() { // CN=foo.com, subjectAlt=bar.com - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIEXDCCA0SgAwIBAgIJAIz+EYMBU6aRMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzYyOVoXDTI4MTEwNTE1MzYyOVowgaQx - CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl - cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs - aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC - ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B - lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy - zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY - 07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8 - BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV - JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCG - SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E - FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz - A1LKh6YNPg0wEgYDVR0RBAswCYIHYmFyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEA - dQyprNZBmVnvuVWjV42sey/PTfkYShJwy1j0/jcFZR/ypZUovpiHGDO1DgL3Y3IP - zVQ26uhUsSw6G0gGRiaBDe/0LUclXZoJzXX1qpS55OadxW73brziS0sxRgGrZE/d - 3g5kkio6IED47OP6wYnlmZ7EKP9cqjWwlnvHnnUcZ2SscoLNYs9rN9ccp8tuq2by - 88OyhKwGjJfhOudqfTNZcDzRHx4Fzm7UsVaycVw4uDmhEHJrAsmMPpj/+XRK9/42 - 2xq+8bc6HojdtbCyug/fvBZvZqQXSmU8m8IVcMmWMz0ZQO8ee3QkBHMZfCy7P/kr - VbWx/uETImUu+NZg22ewEw== - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIEXDCCA0SgAwIBAgIJAIz+EYMBU6aRMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzYyOVoXDTI4MTEwNTE1MzYyOVowgaQx + CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl + cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs + aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC + ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B + lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy + zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY + 07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8 + BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV + JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCG + SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E + FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz + A1LKh6YNPg0wEgYDVR0RBAswCYIHYmFyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEA + dQyprNZBmVnvuVWjV42sey/PTfkYShJwy1j0/jcFZR/ypZUovpiHGDO1DgL3Y3IP + zVQ26uhUsSw6G0gGRiaBDe/0LUclXZoJzXX1qpS55OadxW73brziS0sxRgGrZE/d + 3g5kkio6IED47OP6wYnlmZ7EKP9cqjWwlnvHnnUcZ2SscoLNYs9rN9ccp8tuq2by + 88OyhKwGjJfhOudqfTNZcDzRHx4Fzm7UsVaycVw4uDmhEHJrAsmMPpj/+XRK9/42 + 2xq+8bc6HojdtbCyug/fvBZvZqQXSmU8m8IVcMmWMz0ZQO8ee3QkBHMZfCy7P/kr + VbWx/uETImUu+NZg22ewEw== + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("a.foo.com", session)).isFalse() assertThat(verifier.verify("bar.com", session)).isTrue() @@ -174,36 +177,37 @@ class HostnameVerifierTest { // CN=foo.com, subjectAlt=bar.com, subjectAlt=花子.co.jp // (hanako.co.jp in kanji) - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIEajCCA1KgAwIBAgIJAIz+EYMBU6aSMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzgxM1oXDTI4MTEwNTE1MzgxM1owgaQx - CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl - cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs - aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC - ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B - lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy - zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY - 07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8 - BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV - JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBnjCBmzAJBgNVHRMEAjAAMCwGCWCG - SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E - FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz - A1LKh6YNPg0wIAYDVR0RBBkwF4IHYmFyLmNvbYIM6Iqx5a2QLmNvLmpwMA0GCSqG - SIb3DQEBBQUAA4IBAQBeZs7ZIYyKtdnVxVvdLgwySEPOE4pBSXii7XYv0Q9QUvG/ - ++gFGQh89HhABzA1mVUjH5dJTQqSLFvRfqTHqLpxSxSWqMHnvRM4cPBkIRp/XlMK - PlXadYtJLPTgpbgvulA1ickC9EwlNYWnowZ4uxnfsMghW4HskBqaV+PnQ8Zvy3L0 - 12c7Cg4mKKS5pb1HdRuiD2opZ+Hc77gRQLvtWNS8jQvd/iTbh6fuvTKfAOFoXw22 - sWIKHYrmhCIRshUNohGXv50m2o+1w9oWmQ6Dkq7lCjfXfUB4wIbggJjpyEtbNqBt - j4MC2x5rfsLKKqToKmNE7pFEgqwe8//Aar1b+Qj+ - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIEajCCA1KgAwIBAgIJAIz+EYMBU6aSMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzgxM1oXDTI4MTEwNTE1MzgxM1owgaQx + CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl + cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs + aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC + ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B + lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy + zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY + 07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8 + BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV + JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBnjCBmzAJBgNVHRMEAjAAMCwGCWCG + SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E + FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz + A1LKh6YNPg0wIAYDVR0RBBkwF4IHYmFyLmNvbYIM6Iqx5a2QLmNvLmpwMA0GCSqG + SIb3DQEBBQUAA4IBAQBeZs7ZIYyKtdnVxVvdLgwySEPOE4pBSXii7XYv0Q9QUvG/ + ++gFGQh89HhABzA1mVUjH5dJTQqSLFvRfqTHqLpxSxSWqMHnvRM4cPBkIRp/XlMK + PlXadYtJLPTgpbgvulA1ickC9EwlNYWnowZ4uxnfsMghW4HskBqaV+PnQ8Zvy3L0 + 12c7Cg4mKKS5pb1HdRuiD2opZ+Hc77gRQLvtWNS8jQvd/iTbh6fuvTKfAOFoXw22 + sWIKHYrmhCIRshUNohGXv50m2o+1w9oWmQ6Dkq7lCjfXfUB4wIbggJjpyEtbNqBt + j4MC2x5rfsLKKqToKmNE7pFEgqwe8//Aar1b+Qj+ + -----END CERTIFICATE----- + """.trimIndent(), + ) val peerCertificate = session.peerCertificates[0] as X509Certificate if (isAndroid || platform.isConscrypt()) { @@ -226,35 +230,36 @@ class HostnameVerifierTest { @Test fun verifySubjectAltOnly() { // subjectAlt=foo.com - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIESjCCAzKgAwIBAgIJAIz+EYMBU6aYMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MjYxMFoXDTI4MTEwNTE2MjYxMFowgZIx - CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl - cnRpZmljYXRlczElMCMGCSqGSIb3DQEJARYWanVsaXVzZGF2aWVzQGdtYWlsLmNv - bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhjr5aCPoyp0R1iroWA - fnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2BlYho4O84X244QrZTRl8kQbYt - xnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRyzerA/ZtrlUqf+lKo0uWcocxe - Rc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY07hNKXAb2odnVqgzcYiDkLV8 - ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8BqnGd87xQU3FVZI4tbtkB+Kz - jD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiVJTxpTKqym93whYk93l3ocEe5 - 5c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM - IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86tso4gkJIFiza - 0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0wEgYDVR0RBAsw - CYIHZm9vLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAjl78oMjzFdsMy6F1sGg/IkO8 - tF5yUgPgFYrs41yzAca7IQu6G9qtFDJz/7ehh/9HoG+oqCCIHPuIOmS7Sd0wnkyJ - Y7Y04jVXIb3a6f6AgBkEFP1nOT0z6kjT7vkA5LJ2y3MiDcXuRNMSta5PYVnrX8aZ - yiqVUNi40peuZ2R8mAUSBvWgD7z2qWhF8YgDb7wWaFjg53I36vWKn90ZEti3wNCw - qAVqixM+J0qJmQStgAc53i2aTMvAQu3A3snvH/PHTBo+5UL72n9S1kZyNCsVf1Qo - n8jKTiRriEM+fMFlcgQP284EBFzYHyCXFb9O/hMjK2+6mY9euMB1U1aFFzM/Bg== - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIESjCCAzKgAwIBAgIJAIz+EYMBU6aYMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MjYxMFoXDTI4MTEwNTE2MjYxMFowgZIx + CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl + cnRpZmljYXRlczElMCMGCSqGSIb3DQEJARYWanVsaXVzZGF2aWVzQGdtYWlsLmNv + bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhjr5aCPoyp0R1iroWA + fnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2BlYho4O84X244QrZTRl8kQbYt + xnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRyzerA/ZtrlUqf+lKo0uWcocxe + Rc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY07hNKXAb2odnVqgzcYiDkLV8 + ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8BqnGd87xQU3FVZI4tbtkB+Kz + jD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiVJTxpTKqym93whYk93l3ocEe5 + 5c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM + IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86tso4gkJIFiza + 0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0wEgYDVR0RBAsw + CYIHZm9vLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAjl78oMjzFdsMy6F1sGg/IkO8 + tF5yUgPgFYrs41yzAca7IQu6G9qtFDJz/7ehh/9HoG+oqCCIHPuIOmS7Sd0wnkyJ + Y7Y04jVXIb3a6f6AgBkEFP1nOT0z6kjT7vkA5LJ2y3MiDcXuRNMSta5PYVnrX8aZ + yiqVUNi40peuZ2R8mAUSBvWgD7z2qWhF8YgDb7wWaFjg53I36vWKn90ZEti3wNCw + qAVqixM+J0qJmQStgAc53i2aTMvAQu3A3snvH/PHTBo+5UL72n9S1kZyNCsVf1Qo + n8jKTiRriEM+fMFlcgQP284EBFzYHyCXFb9O/hMjK2+6mY9euMB1U1aFFzM/Bg== + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.com", session)).isTrue() assertThat(verifier.verify("a.foo.com", session)).isFalse() assertThat(verifier.verify("foo.com", session)).isTrue() @@ -263,36 +268,37 @@ class HostnameVerifierTest { @Test fun verifyMultipleCn() { // CN=foo.com, CN=bar.com, CN=花子.co.jp - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIEbzCCA1egAwIBAgIJAIz+EYMBU6aXMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTk0NVoXDTI4MTEwNTE2MTk0NVowgc0x - CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl - cnRpZmljYXRlczEQMA4GA1UEAwwHZm9vLmNvbTEQMA4GA1UEAwwHYmFyLmNvbTEV - MBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyGOv - loI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pNjYGViGjg7zhf - bjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0ZHLN6sD9m2uV - Sp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1JVjTuE0pcBva - h2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6q/wGqcZ3zvFB - TcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYxqJUlPGlMqrKb - 3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf - Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86 - tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0w - DQYJKoZIhvcNAQEFBQADggEBAGuZb8ai1NO2j4v3y9TLZvd5s0vh5/TE7n7RX+8U - y37OL5k7x9nt0mM1TyAKxlCcY+9h6frue8MemZIILSIvMrtzccqNz0V1WKgA+Orf - uUrabmn+CxHF5gpy6g1Qs2IjVYWA5f7FROn/J+Ad8gJYc1azOWCLQqSyfpNRLSvY - EriQFEV63XvkJ8JrG62b+2OT2lqT4OO07gSPetppdlSa8NBSKP6Aro9RIX1ZjUZQ - SpQFCfo02NO0uNRDPUdJx2huycdNb+AXHaO7eXevDLJ+QnqImIzxWiY6zLOdzjjI - VBMkLHmnP7SjGSQ3XA4ByrQOxfOUTyLyE7NuemhHppuQPxE= - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIEbzCCA1egAwIBAgIJAIz+EYMBU6aXMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTk0NVoXDTI4MTEwNTE2MTk0NVowgc0x + CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl + cnRpZmljYXRlczEQMA4GA1UEAwwHZm9vLmNvbTEQMA4GA1UEAwwHYmFyLmNvbTEV + MBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyGOv + loI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pNjYGViGjg7zhf + bjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0ZHLN6sD9m2uV + Sp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1JVjTuE0pcBva + h2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6q/wGqcZ3zvFB + TcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYxqJUlPGlMqrKb + 3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf + Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86 + tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0w + DQYJKoZIhvcNAQEFBQADggEBAGuZb8ai1NO2j4v3y9TLZvd5s0vh5/TE7n7RX+8U + y37OL5k7x9nt0mM1TyAKxlCcY+9h6frue8MemZIILSIvMrtzccqNz0V1WKgA+Orf + uUrabmn+CxHF5gpy6g1Qs2IjVYWA5f7FROn/J+Ad8gJYc1azOWCLQqSyfpNRLSvY + EriQFEV63XvkJ8JrG62b+2OT2lqT4OO07gSPetppdlSa8NBSKP6Aro9RIX1ZjUZQ + SpQFCfo02NO0uNRDPUdJx2huycdNb+AXHaO7eXevDLJ+QnqImIzxWiY6zLOdzjjI + VBMkLHmnP7SjGSQ3XA4ByrQOxfOUTyLyE7NuemhHppuQPxE= + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("a.foo.com", session)).isFalse() assertThat(verifier.verify("bar.com", session)).isFalse() @@ -303,35 +309,36 @@ class HostnameVerifierTest { @Test fun verifyWilcardCn() { // CN=*.foo.com - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIESDCCAzCgAwIBAgIJAIz+EYMBU6aUMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTU1NVoXDTI4MTEwNTE2MTU1NVowgaYx - CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl - cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq - dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB - CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN - jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0 - ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1 - JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6 - q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx - qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG - SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E - FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz - A1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBAH0ipG6J561UKUfgkeW7GvYwW98B - N1ZooWX+JEEZK7+Pf/96d3Ij0rw9ACfN4bpfnCq0VUNZVSYB+GthQ2zYuz7tf/UY - A6nxVgR/IjG69BmsBl92uFO7JTNtHztuiPqBn59pt+vNx4yPvno7zmxsfI7jv0ww - yfs+0FNm7FwdsC1k47GBSOaGw38kuIVWqXSAbL4EX9GkryGGOKGNh0qvAENCdRSB - G9Z6tyMbmfRY+dLSh3a9JwoEcBUso6EWYBakLbq4nG/nvYdYvG9ehrnLVwZFL82e - l3Q/RK95bnA6cuRClGusLad0e6bjkBzx/VQ3VarDEpAkTLUGVAa0CLXtnyc= - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIESDCCAzCgAwIBAgIJAIz+EYMBU6aUMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTU1NVoXDTI4MTEwNTE2MTU1NVowgaYx + CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl + cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq + dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN + jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0 + ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1 + JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6 + q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx + qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG + SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E + FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz + A1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBAH0ipG6J561UKUfgkeW7GvYwW98B + N1ZooWX+JEEZK7+Pf/96d3Ij0rw9ACfN4bpfnCq0VUNZVSYB+GthQ2zYuz7tf/UY + A6nxVgR/IjG69BmsBl92uFO7JTNtHztuiPqBn59pt+vNx4yPvno7zmxsfI7jv0ww + yfs+0FNm7FwdsC1k47GBSOaGw38kuIVWqXSAbL4EX9GkryGGOKGNh0qvAENCdRSB + G9Z6tyMbmfRY+dLSh3a9JwoEcBUso6EWYBakLbq4nG/nvYdYvG9ehrnLVwZFL82e + l3Q/RK95bnA6cuRClGusLad0e6bjkBzx/VQ3VarDEpAkTLUGVAa0CLXtnyc= + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("www.foo.com", session)).isFalse() assertThat(verifier.verify("\u82b1\u5b50.foo.com", session)).isFalse() @@ -341,35 +348,36 @@ class HostnameVerifierTest { @Test fun verifyWilcardCnOnTld() { // It's the CA's responsibility to not issue broad-matching certificates! // CN=*.co.jp - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aVMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTYzMFoXDTI4MTEwNTE2MTYzMFowgaQx - CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl - cnRpZmljYXRlczEQMA4GA1UEAxQHKi5jby5qcDElMCMGCSqGSIb3DQEJARYWanVs - aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC - ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B - lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy - zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY - 07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8 - BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV - JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB - hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE - FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS - yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQA0sWglVlMx2zNGvUqFC73XtREwii53 - CfMM6mtf2+f3k/d8KXhLNySrg8RRlN11zgmpPaLtbdTLrmG4UdAHHYr8O4y2BBmE - 1cxNfGxxechgF8HX10QV4dkyzp6Z1cfwvCeMrT5G/V1pejago0ayXx+GPLbWlNeZ - S+Kl0m3p+QplXujtwG5fYcIpaGpiYraBLx3Tadih39QN65CnAh/zRDhLCUzKyt9l - UGPLEUDzRHMPHLnSqT1n5UU5UDRytbjJPXzF+l/+WZIsanefWLsxnkgAuZe/oMMF - EJMryEzOjg4Tfuc5qM0EXoPcQ/JlheaxZ40p2IyHqbsWV4MRYuFH4bkM - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aVMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTYzMFoXDTI4MTEwNTE2MTYzMFowgaQx + CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl + cnRpZmljYXRlczEQMA4GA1UEAxQHKi5jby5qcDElMCMGCSqGSIb3DQEJARYWanVs + aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC + ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B + lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy + zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY + 07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8 + BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV + JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB + hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE + FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS + yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQA0sWglVlMx2zNGvUqFC73XtREwii53 + CfMM6mtf2+f3k/d8KXhLNySrg8RRlN11zgmpPaLtbdTLrmG4UdAHHYr8O4y2BBmE + 1cxNfGxxechgF8HX10QV4dkyzp6Z1cfwvCeMrT5G/V1pejago0ayXx+GPLbWlNeZ + S+Kl0m3p+QplXujtwG5fYcIpaGpiYraBLx3Tadih39QN65CnAh/zRDhLCUzKyt9l + UGPLEUDzRHMPHLnSqT1n5UU5UDRytbjJPXzF+l/+WZIsanefWLsxnkgAuZe/oMMF + EJMryEzOjg4Tfuc5qM0EXoPcQ/JlheaxZ40p2IyHqbsWV4MRYuFH4bkM + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.co.jp", session)).isFalse() assertThat(verifier.verify("\u82b1\u5b50.co.jp", session)).isFalse() } @@ -388,36 +396,37 @@ class HostnameVerifierTest { // CN=*.foo.com, subjectAlt=*.bar.com, subjectAlt=*.花子.co.jp // (*.hanako.co.jp in kanji) - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIEcDCCA1igAwIBAgIJAIz+EYMBU6aWMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD - VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE - ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU - FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp - ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTczMVoXDTI4MTEwNTE2MTczMVowgaYx - CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 - IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl - cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq - dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB - CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN - jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0 - ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1 - JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6 - q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx - qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo4GiMIGfMAkGA1UdEwQCMAAwLAYJ - YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1Ud - DgQWBBSfFHe/Pzq2yjiCQkgWLNrQy16H2DAfBgNVHSMEGDAWgBR7mtqPkJlOUtKs - 27MDUsqHpg0+DTAkBgNVHREEHTAbggkqLmJhci5jb22CDiou6Iqx5a2QLmNvLmpw - MA0GCSqGSIb3DQEBBQUAA4IBAQBobWC+D5/lx6YhX64CwZ26XLjxaE0S415ajbBq - DK7lz+Rg7zOE3GsTAMi+ldUYnhyz0wDiXB8UwKXl0SDToB2Z4GOgqQjAqoMmrP0u - WB6Y6dpkfd1qDRUzI120zPYgSdsXjHW9q2H77iV238hqIU7qCvEz+lfqqWEY504z - hYNlknbUnR525ItosEVwXFBJTkZ3Yw8gg02c19yi8TAh5Li3Ad8XQmmSJMWBV4XK - qFr0AIZKBlg6NZZFf/0dP9zcKhzSriW27bY0XfzA6GSiRDXrDjgXq6baRT6YwgIg - pgJsDbJtZfHnV1nd3M6zOtQPm1TIQpNmMMMd/DPrGcUQerD3 - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIEcDCCA1igAwIBAgIJAIz+EYMBU6aWMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD + VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE + ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU + FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp + ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTczMVoXDTI4MTEwNTE2MTczMVowgaYx + CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0 + IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl + cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq + dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN + jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0 + ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1 + JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6 + q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx + qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo4GiMIGfMAkGA1UdEwQCMAAwLAYJ + YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1Ud + DgQWBBSfFHe/Pzq2yjiCQkgWLNrQy16H2DAfBgNVHSMEGDAWgBR7mtqPkJlOUtKs + 27MDUsqHpg0+DTAkBgNVHREEHTAbggkqLmJhci5jb22CDiou6Iqx5a2QLmNvLmpw + MA0GCSqGSIb3DQEBBQUAA4IBAQBobWC+D5/lx6YhX64CwZ26XLjxaE0S415ajbBq + DK7lz+Rg7zOE3GsTAMi+ldUYnhyz0wDiXB8UwKXl0SDToB2Z4GOgqQjAqoMmrP0u + WB6Y6dpkfd1qDRUzI120zPYgSdsXjHW9q2H77iV238hqIU7qCvEz+lfqqWEY504z + hYNlknbUnR525ItosEVwXFBJTkZ3Yw8gg02c19yi8TAh5Li3Ad8XQmmSJMWBV4XK + qFr0AIZKBlg6NZZFf/0dP9zcKhzSriW27bY0XfzA6GSiRDXrDjgXq6baRT6YwgIg + pgJsDbJtZfHnV1nd3M6zOtQPm1TIQpNmMMMd/DPrGcUQerD3 + -----END CERTIFICATE----- + """.trimIndent(), + ) val peerCertificate = session.peerCertificates[0] as X509Certificate if (isAndroid || platform.isConscrypt()) { assertThat(certificateSANs(peerCertificate)).containsExactly("*.bar.com") @@ -455,22 +464,23 @@ class HostnameVerifierTest { // // $ openssl req -x509 -nodes -days 36500 -subj '/CN=localhost' -config ./cert.cnf \ // -newkey rsa:512 -out cert.pem - val certificate = certificate( - """ - -----BEGIN CERTIFICATE----- - MIIBWDCCAQKgAwIBAgIJANS1EtICX2AZMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV - BAMTCWxvY2FsaG9zdDAgFw0xMjAxMDIxOTA4NThaGA8yMTExMTIwOTE5MDg1OFow - FDESMBAGA1UEAxMJbG9jYWxob3N0MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPpt - atK8r4/hf4hSIs0os/BSlQLbRBaK9AfBReM4QdAklcQqe6CHsStKfI8pp0zs7Ptg - PmMdpbttL0O7mUboBC8CAwEAAaM1MDMwMQYDVR0RBCowKIIVbG9jYWxob3N0Lmxv - Y2FsZG9tYWlugglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQEFBQADQQD0ntfL - DCzOCv9Ma6Lv5o5jcYWVxvBSTsnt22hsJpWD1K7iY9lbkLwl0ivn73pG2evsAn9G - X8YKH52fnHsCrhSD - -----END CERTIFICATE----- - """.trimIndent() - ) + val certificate = + certificate( + """ + -----BEGIN CERTIFICATE----- + MIIBWDCCAQKgAwIBAgIJANS1EtICX2AZMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV + BAMTCWxvY2FsaG9zdDAgFw0xMjAxMDIxOTA4NThaGA8yMTExMTIwOTE5MDg1OFow + FDESMBAGA1UEAxMJbG9jYWxob3N0MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPpt + atK8r4/hf4hSIs0os/BSlQLbRBaK9AfBReM4QdAklcQqe6CHsStKfI8pp0zs7Ptg + PmMdpbttL0O7mUboBC8CAwEAAaM1MDMwMQYDVR0RBCowKIIVbG9jYWxob3N0Lmxv + Y2FsZG9tYWlugglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQEFBQADQQD0ntfL + DCzOCv9Ma6Lv5o5jcYWVxvBSTsnt22hsJpWD1K7iY9lbkLwl0ivn73pG2evsAn9G + X8YKH52fnHsCrhSD + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(certificate.subjectX500Principal).isEqualTo( - X500Principal("CN=localhost") + X500Principal("CN=localhost"), ) val session = FakeSSLSession(certificate) assertThat(verifier.verify("localhost", session)).isTrue() @@ -482,21 +492,22 @@ class HostnameVerifierTest { @Test fun wildcardsCannotMatchIpAddresses() { // openssl req -x509 -nodes -days 36500 -subj '/CN=*.0.0.1' -newkey rsa:512 -out cert.pem - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIBkjCCATygAwIBAgIJAMdemqOwd/BEMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV - BAMUByouMC4wLjEwIBcNMTAxMjIwMTY0NDI1WhgPMjExMDExMjYxNjQ0MjVaMBIx - EDAOBgNVBAMUByouMC4wLjEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAqY8c9Qrt - YPWCvb7lclI+aDHM6fgbJcHsS9Zg8nUOh5dWrS7AgeA25wyaokFl4plBbbHQe2j+ - cCjsRiJIcQo9HwIDAQABo3MwcTAdBgNVHQ4EFgQUJ436TZPJvwCBKklZZqIvt1Yt - JjEwQgYDVR0jBDswOYAUJ436TZPJvwCBKklZZqIvt1YtJjGhFqQUMBIxEDAOBgNV - BAMUByouMC4wLjGCCQDHXpqjsHfwRDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB - BQUAA0EAk9i88xdjWoewqvE+iMC9tD2obMchgFDaHH0ogxxiRaIKeEly3g0uGxIt - fl2WRY8hb4x+zRrwsFaLEpdEvqcjOQ== - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIBkjCCATygAwIBAgIJAMdemqOwd/BEMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV + BAMUByouMC4wLjEwIBcNMTAxMjIwMTY0NDI1WhgPMjExMDExMjYxNjQ0MjVaMBIx + EDAOBgNVBAMUByouMC4wLjEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAqY8c9Qrt + YPWCvb7lclI+aDHM6fgbJcHsS9Zg8nUOh5dWrS7AgeA25wyaokFl4plBbbHQe2j+ + cCjsRiJIcQo9HwIDAQABo3MwcTAdBgNVHQ4EFgQUJ436TZPJvwCBKklZZqIvt1Yt + JjEwQgYDVR0jBDswOYAUJ436TZPJvwCBKklZZqIvt1YtJjGhFqQUMBIxEDAOBgNV + BAMUByouMC4wLjGCCQDHXpqjsHfwRDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB + BQUAA0EAk9i88xdjWoewqvE+iMC9tD2obMchgFDaHH0ogxxiRaIKeEly3g0uGxIt + fl2WRY8hb4x+zRrwsFaLEpdEvqcjOQ== + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("127.0.0.1", session)).isFalse() } @@ -507,21 +518,22 @@ class HostnameVerifierTest { */ @Test fun wildcardsDoesNotNeedTwoDots() { // openssl req -x509 -nodes -days 36500 -subj '/CN=*.com' -newkey rsa:512 -out cert.pem - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIBjDCCATagAwIBAgIJAOVulXCSu6HuMA0GCSqGSIb3DQEBBQUAMBAxDjAMBgNV - BAMUBSouY29tMCAXDTEwMTIyMDE2NDkzOFoYDzIxMTAxMTI2MTY0OTM4WjAQMQ4w - DAYDVQQDFAUqLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDJd8xqni+h7Iaz - ypItivs9kPuiJUqVz+SuJ1C05SFc3PmlRCvwSIfhyD67fHcbMdl+A/LrIjhhKZJe - 1joO0+pFAgMBAAGjcTBvMB0GA1UdDgQWBBS4Iuzf5w8JdCp+EtBfdFNudf6+YzBA - BgNVHSMEOTA3gBS4Iuzf5w8JdCp+EtBfdFNudf6+Y6EUpBIwEDEOMAwGA1UEAxQF - Ki5jb22CCQDlbpVwkruh7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA0EA - U6LFxmZr31lFyis2/T68PpjAppc0DpNQuA2m/Y7oTHBDi55Fw6HVHCw3lucuWZ5d - qUYo4ES548JdpQtcLrW2sA== - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIBjDCCATagAwIBAgIJAOVulXCSu6HuMA0GCSqGSIb3DQEBBQUAMBAxDjAMBgNV + BAMUBSouY29tMCAXDTEwMTIyMDE2NDkzOFoYDzIxMTAxMTI2MTY0OTM4WjAQMQ4w + DAYDVQQDFAUqLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDJd8xqni+h7Iaz + ypItivs9kPuiJUqVz+SuJ1C05SFc3PmlRCvwSIfhyD67fHcbMdl+A/LrIjhhKZJe + 1joO0+pFAgMBAAGjcTBvMB0GA1UdDgQWBBS4Iuzf5w8JdCp+EtBfdFNudf6+YzBA + BgNVHSMEOTA3gBS4Iuzf5w8JdCp+EtBfdFNudf6+Y6EUpBIwEDEOMAwGA1UEAxQF + Ki5jb22CCQDlbpVwkruh7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA0EA + U6LFxmZr31lFyis2/T68PpjAppc0DpNQuA2m/Y7oTHBDi55Fw6HVHCw3lucuWZ5d + qUYo4ES548JdpQtcLrW2sA== + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("google.com", session)).isFalse() } @@ -538,19 +550,20 @@ class HostnameVerifierTest { // // $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \ // -newkey rsa:512 -out cert.pem - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIBPTCB6KADAgECAgkA7zoHaaqNGHQwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UE - AxMHZm9vLmNvbTAgFw0xMDEyMjAxODM5MzZaGA8yMTEwMTEyNjE4MzkzNlowEjEQ - MA4GA1UEAxMHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC+gmoSxF+8 - hbV+rgRQqHIJd50216OWQJbU3BvdlPbca779NYO4+UZWTFdBM8BdQqs3H4B5Agvp - y7HeSff1F7XRAgMBAAGjHzAdMBsGA1UdEQQUMBKCB2Jhci5jb22CB2Jhei5jb20w - DQYJKoZIhvcNAQEFBQADQQBXpZZPOY2Dy1lGG81JTr8L4or9jpKacD7n51eS8iqI - oTznPNuXHU5bFN0AAGX2ij47f/EahqTpo5RdS95P4sVm - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIBPTCB6KADAgECAgkA7zoHaaqNGHQwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UE + AxMHZm9vLmNvbTAgFw0xMDEyMjAxODM5MzZaGA8yMTEwMTEyNjE4MzkzNlowEjEQ + MA4GA1UEAxMHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC+gmoSxF+8 + hbV+rgRQqHIJd50216OWQJbU3BvdlPbca779NYO4+UZWTFdBM8BdQqs3H4B5Agvp + y7HeSff1F7XRAgMBAAGjHzAdMBsGA1UdEQQUMBKCB2Jhci5jb22CB2Jhei5jb20w + DQYJKoZIhvcNAQEFBQADQQBXpZZPOY2Dy1lGG81JTr8L4or9jpKacD7n51eS8iqI + oTznPNuXHU5bFN0AAGX2ij47f/EahqTpo5RdS95P4sVm + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("bar.com", session)).isTrue() assertThat(verifier.verify("baz.com", session)).isTrue() @@ -571,19 +584,20 @@ class HostnameVerifierTest { // // $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \ // -newkey rsa:512 -out cert.pem - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIBPzCB6qADAgECAgkAnv/7Jv5r7pMwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UE - AxMHZm9vLmNvbTAgFw0xMDEyMjAxODQ2MDFaGA8yMTEwMTEyNjE4NDYwMVowEjEQ - MA4GA1UEAxMHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDAz2YXnyog - YdYLSFr/OEgSumtwqtZKJTB4wqTW/eKbBCEzxnyUMxWZIqUGu353PzwfOuWp2re3 - nvVV+QDYQlh9AgMBAAGjITAfMB0GA1UdEQQWMBSCB2Jhci5jb22CCSouYmF6LmNv - bTANBgkqhkiG9w0BAQUFAANBAB8yrSl8zqy07i0SNYx2B/FnvQY734pxioaqFWfO - Bqo1ZZl/9aPHEWIwBrxYNVB0SGu/kkbt/vxqOjzzrkXukmI= - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIBPzCB6qADAgECAgkAnv/7Jv5r7pMwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UE + AxMHZm9vLmNvbTAgFw0xMDEyMjAxODQ2MDFaGA8yMTEwMTEyNjE4NDYwMVowEjEQ + MA4GA1UEAxMHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDAz2YXnyog + YdYLSFr/OEgSumtwqtZKJTB4wqTW/eKbBCEzxnyUMxWZIqUGu353PzwfOuWp2re3 + nvVV+QDYQlh9AgMBAAGjITAfMB0GA1UdEQQWMBSCB2Jhci5jb22CCSouYmF6LmNv + bTANBgkqhkiG9w0BAQUFAANBAB8yrSl8zqy07i0SNYx2B/FnvQY734pxioaqFWfO + Bqo1ZZl/9aPHEWIwBrxYNVB0SGu/kkbt/vxqOjzzrkXukmI= + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("bar.com", session)).isTrue() assertThat(verifier.verify("a.baz.com", session)).isTrue() @@ -606,20 +620,21 @@ class HostnameVerifierTest { // // $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \ // -newkey rsa:512 -out cert.pem - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIBaDCCARKgAwIBAgIJALxN+AOBVGwQMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV - BAMMB2Zvby5jb20wIBcNMjAwMzIyMTEwNDI4WhgPMjEyMDAyMjcxMTA0MjhaMBIx - EDAOBgNVBAMMB2Zvby5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAlnVbVfQ9 - 4aYjrPCcFuxOpjXuvyOc9Hcha4K7TfXyfsrjhAvCjCBIT/TiLOUVF3sx4yoCAtX8 - wmt404tTbKD6UwIDAQABo0kwRzBFBgNVHREEPjA8hxAAAAAAAAAAAAAAAAAAAAAB - hxAqAyiA8AMMB/rOsAwAAAAChxAAAAAAAAAAAAAAAAAAAAAFhwTAqAEBMA0GCSqG - SIb3DQEBCwUAA0EAPSOYHJh7hB4ElBqTCAFW+T5Y7mXsv9nQjBJ7w0YIw83V2PEI - 3KbBIyGTrqHD6lG8QGZy+yNkIcRlodG8OfQRUg== - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIBaDCCARKgAwIBAgIJALxN+AOBVGwQMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV + BAMMB2Zvby5jb20wIBcNMjAwMzIyMTEwNDI4WhgPMjEyMDAyMjcxMTA0MjhaMBIx + EDAOBgNVBAMMB2Zvby5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAlnVbVfQ9 + 4aYjrPCcFuxOpjXuvyOc9Hcha4K7TfXyfsrjhAvCjCBIT/TiLOUVF3sx4yoCAtX8 + wmt404tTbKD6UwIDAQABo0kwRzBFBgNVHREEPjA8hxAAAAAAAAAAAAAAAAAAAAAB + hxAqAyiA8AMMB/rOsAwAAAAChxAAAAAAAAAAAAAAAAAAAAAFhwTAqAEBMA0GCSqG + SIb3DQEBCwUAA0EAPSOYHJh7hB4ElBqTCAFW+T5Y7mXsv9nQjBJ7w0YIw83V2PEI + 3KbBIyGTrqHD6lG8QGZy+yNkIcRlodG8OfQRUg== + -----END CERTIFICATE----- + """.trimIndent(), + ) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("::1", session)).isTrue() assertThat(verifier.verify("::2", session)).isFalse() @@ -635,10 +650,11 @@ class HostnameVerifierTest { } @Test fun generatedCertificate() { - val heldCertificate = HeldCertificate.Builder() - .commonName("Foo Corp") - .addSubjectAlternativeName("foo.com") - .build() + val heldCertificate = + HeldCertificate.Builder() + .commonName("Foo Corp") + .addSubjectAlternativeName("foo.com") + .build() val session = session(heldCertificate.certificatePem()) assertThat(verifier.verify("foo.com", session)).isTrue() assertThat(verifier.verify("bar.com", session)).isFalse() @@ -647,11 +663,12 @@ class HostnameVerifierTest { @Test fun specialKInHostname() { // https://github.com/apache/httpcomponents-client/commit/303e435d7949652ea77a6c50df1c548682476b6e // https://www.gosecure.net/blog/2020/10/27/weakness-in-java-tls-host-verification/ - val heldCertificate = HeldCertificate.Builder() - .commonName("Foo Corp") - .addSubjectAlternativeName("k.com") - .addSubjectAlternativeName("tel.com") - .build() + val heldCertificate = + HeldCertificate.Builder() + .commonName("Foo Corp") + .addSubjectAlternativeName("k.com") + .addSubjectAlternativeName("tel.com") + .build() val session = session(heldCertificate.certificatePem()) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("bar.com", session)).isFalse() @@ -669,11 +686,12 @@ class HostnameVerifierTest { @Test fun specialKInCert() { // https://github.com/apache/httpcomponents-client/commit/303e435d7949652ea77a6c50df1c548682476b6e // https://www.gosecure.net/blog/2020/10/27/weakness-in-java-tls-host-verification/ - val heldCertificate = HeldCertificate.Builder() - .commonName("Foo Corp") - .addSubjectAlternativeName("\u2121.com") - .addSubjectAlternativeName("\u212A.com") - .build() + val heldCertificate = + HeldCertificate.Builder() + .commonName("Foo Corp") + .addSubjectAlternativeName("\u2121.com") + .addSubjectAlternativeName("\u212A.com") + .build() val session = session(heldCertificate.certificatePem()) assertThat(verifier.verify("foo.com", session)).isFalse() assertThat(verifier.verify("bar.com", session)).isFalse() @@ -705,19 +723,20 @@ class HostnameVerifierTest { // // $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \ // -newkey rsa:512 -out cert.pem - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIBSDCB86ADAgECAhRLR4TGgXBegg0np90FZ1KPeWpDtjANBgkqhkiG9w0BAQsF - ADASMRAwDgYDVQQDDAdmb28uY29tMCAXDTIwMTAyOTA2NTkwNVoYDzIxMjAxMDA1 - MDY1OTA1WjASMRAwDgYDVQQDDAdmb28uY29tMFwwDQYJKoZIhvcNAQEBBQADSwAw - SAJBALQcTVW9aW++ClIV9/9iSzijsPvQGEu/FQOjIycSrSIheZyZmR8bluSNBq0C - 9fpalRKZb0S2tlCTi5WoX8d3K30CAwEAAaMfMB0wGwYDVR0RBBQwEoIH4oShLmNv - bYIH4oSqLmNvbTANBgkqhkiG9w0BAQsFAANBAA1+/eDvSUGv78iEjNW+1w3OPAwt - Ij1qLQ/YI8OogZPMk7YY46/ydWWp7UpD47zy/vKmm4pOc8Glc8MoDD6UADs= - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIBSDCB86ADAgECAhRLR4TGgXBegg0np90FZ1KPeWpDtjANBgkqhkiG9w0BAQsF + ADASMRAwDgYDVQQDDAdmb28uY29tMCAXDTIwMTAyOTA2NTkwNVoYDzIxMjAxMDA1 + MDY1OTA1WjASMRAwDgYDVQQDDAdmb28uY29tMFwwDQYJKoZIhvcNAQEBBQADSwAw + SAJBALQcTVW9aW++ClIV9/9iSzijsPvQGEu/FQOjIycSrSIheZyZmR8bluSNBq0C + 9fpalRKZb0S2tlCTi5WoX8d3K30CAwEAAaMfMB0wGwYDVR0RBBQwEoIH4oShLmNv + bYIH4oSqLmNvbTANBgkqhkiG9w0BAQsFAANBAA1+/eDvSUGv78iEjNW+1w3OPAwt + Ij1qLQ/YI8OogZPMk7YY46/ydWWp7UpD47zy/vKmm4pOc8Glc8MoDD6UADs= + -----END CERTIFICATE----- + """.trimIndent(), + ) val peerCertificate = session.peerCertificates[0] as X509Certificate if (isAndroid) { assertThat(certificateSANs(peerCertificate)).containsExactly() @@ -752,19 +771,20 @@ class HostnameVerifierTest { // // $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \ // -newkey rsa:512 -out cert.pem - val session = session( - """ - -----BEGIN CERTIFICATE----- - MIIBSDCB86ADAgECAhRLR4TGgXBegg0np90FZ1KPeWpDtjANBgkqhkiG9w0BAQsF - ADASMRAwDgYDVQQDDAdmb28uY29tMCAXDTIwMTAyOTA2NTkwNVoYDzIxMjAxMDA1 - MDY1OTA1WjASMRAwDgYDVQQDDAdmb28uY29tMFwwDQYJKoZIhvcNAQEBBQADSwAw - SAJBALQcTVW9aW++ClIV9/9iSzijsPvQGEu/FQOjIycSrSIheZyZmR8bluSNBq0C - 9fpalRKZb0S2tlCTi5WoX8d3K30CAwEAAaMfMB0wGwYDVR0RBBQwEoIH4oShLmNv - bYIH4oSqLmNvbTANBgkqhkiG9w0BAQsFAANBAA1+/eDvSUGv78iEjNW+1w3OPAwt - Ij1qLQ/YI8OogZPMk7YY46/ydWWp7UpD47zy/vKmm4pOc8Glc8MoDD6UADs= - -----END CERTIFICATE----- - """.trimIndent() - ) + val session = + session( + """ + -----BEGIN CERTIFICATE----- + MIIBSDCB86ADAgECAhRLR4TGgXBegg0np90FZ1KPeWpDtjANBgkqhkiG9w0BAQsF + ADASMRAwDgYDVQQDDAdmb28uY29tMCAXDTIwMTAyOTA2NTkwNVoYDzIxMjAxMDA1 + MDY1OTA1WjASMRAwDgYDVQQDDAdmb28uY29tMFwwDQYJKoZIhvcNAQEBBQADSwAw + SAJBALQcTVW9aW++ClIV9/9iSzijsPvQGEu/FQOjIycSrSIheZyZmR8bluSNBq0C + 9fpalRKZb0S2tlCTi5WoX8d3K30CAwEAAaMfMB0wGwYDVR0RBBQwEoIH4oShLmNv + bYIH4oSqLmNvbTANBgkqhkiG9w0BAQsFAANBAA1+/eDvSUGv78iEjNW+1w3OPAwt + Ij1qLQ/YI8OogZPMk7YY46/ydWWp7UpD47zy/vKmm4pOc8Glc8MoDD6UADs= + -----END CERTIFICATE----- + """.trimIndent(), + ) // Replacement characters are deliberate, from certificate loading. assertThat(verifier.verify("���.com", session)).isFalse() diff --git a/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt b/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt index bea5124476a4..731c7435f09d 100644 --- a/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt @@ -255,7 +255,7 @@ class RealWebSocketTest { assertThat(client.closed).isTrue() client.listener.assertFailure( ProtocolException::class.java, - "Control frames must be final." + "Control frames must be final.", ) server.processNextFrame() taskFaker.runTasks() @@ -276,7 +276,8 @@ class RealWebSocketTest { client.webSocket!!.finishReader() assertThat(client.closed).isTrue() client.listener.assertFailure( - ProtocolException::class.java, "Server-sent frames must not be masked." + ProtocolException::class.java, + "Server-sent frames must not be masked.", ) server.listener.assertClosing(1000, "Hello") server.listener.assertExhausted() // Client should not have sent second close. @@ -297,7 +298,7 @@ class RealWebSocketTest { assertThat(client.closed).isTrue() client.listener.assertFailure( ProtocolException::class.java, - "Control frames must be final." + "Control frames must be final.", ) server.listener.assertClosing(1000, "Hello!") server.listener.assertExhausted() // Client should not have sent second close. @@ -353,7 +354,7 @@ class RealWebSocketTest { taskFaker.advanceUntil(ns(1000L)) client.listener.assertFailure( SocketTimeoutException::class.java, - "sent ping but didn't receive pong within 500ms (after 0 successful ping/pongs)" + "sent ping but didn't receive pong within 500ms (after 0 successful ping/pongs)", ) } @@ -382,7 +383,7 @@ class RealWebSocketTest { taskFaker.advanceUntil(ns(1500L)) client.listener.assertFailure( SocketTimeoutException::class.java, - "sent ping but didn't receive pong within 500ms (after 1 successful ping/pongs)" + "sent ping but didn't receive pong within 500ms (after 1 successful ping/pongs)", ) } @@ -443,20 +444,23 @@ class RealWebSocketTest { responseHeaders: Headers? = headersOf(), ) { val url = "http://example.com/websocket" - val response = Response.Builder() - .code(101) - .message("OK") - .request(Request.Builder().url(url).build()) - .headers(responseHeaders!!) - .protocol(Protocol.HTTP_1_1) - .build() - webSocket = RealWebSocket( - taskFaker.taskRunner, response.request, listener, random!!, - pingIntervalMillis.toLong(), parse( - responseHeaders - ), - RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE - ) + val response = + Response.Builder() + .code(101) + .message("OK") + .request(Request.Builder().url(url).build()) + .headers(responseHeaders!!) + .protocol(Protocol.HTTP_1_1) + .build() + webSocket = + RealWebSocket( + taskFaker.taskRunner, response.request, listener, random!!, + pingIntervalMillis.toLong(), + parse( + responseHeaders, + ), + RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE, + ) webSocket!!.initReaderAndWriter(name, this) } diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketExtensionsTest.kt b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketExtensionsTest.kt index ced26283b4c1..9c22fb973564 100644 --- a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketExtensionsTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketExtensionsTest.kt @@ -29,197 +29,243 @@ class WebSocketExtensionsTest { @Test fun noExtensionHeader() { assertThat(WebSocketExtensions.parse(headersOf())) - .isEqualTo(WebSocketExtensions()) + .isEqualTo(WebSocketExtensions()) } @Test fun emptyExtension() { assertThat(parse(", permessage-deflate")) - .isEqualTo(WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) + .isEqualTo(WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) } @Test fun unknownExtension() { assertThat(parse("unknown-ext")) - .isEqualTo(WebSocketExtensions(unknownValues = true)) + .isEqualTo(WebSocketExtensions(unknownValues = true)) } @Test fun perMessageDeflate() { assertThat(parse("permessage-deflate")) - .isEqualTo(WebSocketExtensions(perMessageDeflate = true)) + .isEqualTo(WebSocketExtensions(perMessageDeflate = true)) } @Test fun emptyParameters() { assertThat(parse("permessage-deflate;")) - .isEqualTo(WebSocketExtensions(perMessageDeflate = true)) + .isEqualTo(WebSocketExtensions(perMessageDeflate = true)) } @Test fun repeatedPerMessageDeflate() { assertThat(parse("permessage-deflate, permessage-deflate; server_no_context_takeover")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - serverNoContextTakeover = true, - unknownValues = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + serverNoContextTakeover = true, + unknownValues = true, + ), + ) } @Test fun multiplePerMessageDeflateHeaders() { - val extensions = WebSocketExtensions.parse(headersOf( - "Sec-WebSocket-Extensions", "", - "Sec-WebSocket-Extensions", "permessage-deflate" - )) + val extensions = + WebSocketExtensions.parse( + headersOf( + "Sec-WebSocket-Extensions", + "", + "Sec-WebSocket-Extensions", + "permessage-deflate", + ), + ) assertThat(extensions) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + ), + ) } @Test fun noContextTakeoverServerAndClient() { assertThat(parse("permessage-deflate; server_no_context_takeover; client_no_context_takeover")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - clientNoContextTakeover = true, - serverNoContextTakeover = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + clientNoContextTakeover = true, + serverNoContextTakeover = true, + ), + ) } @Test fun everything() { - assertThat(parse("permessage-deflate; client_max_window_bits=15; client_no_context_takeover; " + - "server_max_window_bits=8; server_no_context_takeover")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - clientMaxWindowBits = 15, - clientNoContextTakeover = true, - serverMaxWindowBits = 8, - serverNoContextTakeover = true - )) + assertThat( + parse( + "permessage-deflate; client_max_window_bits=15; client_no_context_takeover; " + + "server_max_window_bits=8; server_no_context_takeover", + ), + ) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + clientMaxWindowBits = 15, + clientNoContextTakeover = true, + serverMaxWindowBits = 8, + serverNoContextTakeover = true, + ), + ) } @Test fun noWhitespace() { assertThat(parse("permessage-deflate;server_no_context_takeover;client_no_context_takeover")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - clientNoContextTakeover = true, - serverNoContextTakeover = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + clientNoContextTakeover = true, + serverNoContextTakeover = true, + ), + ) } @Test fun excessWhitespace() { - assertThat(parse( - " permessage-deflate\t ; \tserver_no_context_takeover\t ; client_no_context_takeover " - )).isEqualTo(WebSocketExtensions( + assertThat( + parse( + " permessage-deflate\t ; \tserver_no_context_takeover\t ; client_no_context_takeover ", + ), + ).isEqualTo( + WebSocketExtensions( perMessageDeflate = true, clientNoContextTakeover = true, - serverNoContextTakeover = true - )) + serverNoContextTakeover = true, + ), + ) } @Test fun noContextTakeoverClientAndServer() { assertThat(parse("permessage-deflate; client_no_context_takeover; server_no_context_takeover")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - clientNoContextTakeover = true, - serverNoContextTakeover = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + clientNoContextTakeover = true, + serverNoContextTakeover = true, + ), + ) } @Test fun noContextTakeoverClient() { assertThat(parse("permessage-deflate; client_no_context_takeover")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - clientNoContextTakeover = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + clientNoContextTakeover = true, + ), + ) } @Test fun noContextTakeoverServer() { assertThat(parse("permessage-deflate; server_no_context_takeover")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, serverNoContextTakeover = true)) + WebSocketExtensions(perMessageDeflate = true, serverNoContextTakeover = true), + ) } @Test fun clientMaxWindowBits() { assertThat(parse("permessage-deflate; client_max_window_bits=8")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 8)) + WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 8), + ) assertThat(parse("permessage-deflate; client_max_window_bits=\"8\"")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 8)) + WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 8), + ) assertThat(parse("permessage-deflate; client_max_window_bits=15")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 15)) + WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 15), + ) assertThat(parse("permessage-deflate; client_max_window_bits=\"15\"")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 15)) + WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 15), + ) assertThat(parse("permessage-deflate; client_max_window_bits\t =\t 8\t ")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 8)) + WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 8), + ) assertThat(parse("permessage-deflate; client_max_window_bits\t =\t \"8\"\t ")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 8)) + WebSocketExtensions(perMessageDeflate = true, clientMaxWindowBits = 8), + ) } @Test fun serverMaxWindowBits() { assertThat(parse("permessage-deflate; server_max_window_bits=8")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 8)) + WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 8), + ) assertThat(parse("permessage-deflate; server_max_window_bits=\"8\"")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 8)) + WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 8), + ) assertThat(parse("permessage-deflate; server_max_window_bits=15")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 15)) + WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 15), + ) assertThat(parse("permessage-deflate; server_max_window_bits=\"15\"")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 15)) + WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 15), + ) assertThat(parse("permessage-deflate; server_max_window_bits\t =\t 8\t ")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 8)) + WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 8), + ) assertThat(parse("permessage-deflate; server_max_window_bits\t =\t \"8\"\t ")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 8)) + WebSocketExtensions(perMessageDeflate = true, serverMaxWindowBits = 8), + ) } @Test fun unknownParameters() { assertThat(parse("permessage-deflate; unknown")) - .isEqualTo(WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) + .isEqualTo(WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) assertThat(parse("permessage-deflate; unknown_parameter=15")) - .isEqualTo(WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) + .isEqualTo(WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) assertThat(parse("permessage-deflate; unknown_parameter=15; unknown_parameter=15")) - .isEqualTo(WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) + .isEqualTo(WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) } @Test fun unexpectedValue() { assertThat(parse("permessage-deflate; client_no_context_takeover=true")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - clientNoContextTakeover = true, - unknownValues = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + clientNoContextTakeover = true, + unknownValues = true, + ), + ) assertThat(parse("permessage-deflate; server_max_window_bits=true")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - unknownValues = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + unknownValues = true, + ), + ) } @Test fun absentValue() { assertThat(parse("permessage-deflate; server_max_window_bits")).isEqualTo( - WebSocketExtensions(perMessageDeflate = true, unknownValues = true)) + WebSocketExtensions(perMessageDeflate = true, unknownValues = true), + ) } @Test fun uppercase() { assertThat(parse("PERMESSAGE-DEFLATE; SERVER_NO_CONTEXT_TAKEOVER; CLIENT_NO_CONTEXT_TAKEOVER")) - .isEqualTo(WebSocketExtensions( - perMessageDeflate = true, - clientNoContextTakeover = true, - serverNoContextTakeover = true - )) + .isEqualTo( + WebSocketExtensions( + perMessageDeflate = true, + clientNoContextTakeover = true, + serverNoContextTakeover = true, + ), + ) } - private fun parse(extension: String) = - WebSocketExtensions.parse(headersOf("Sec-WebSocket-Extensions", extension)) + private fun parse(extension: String) = WebSocketExtensions.parse(headersOf("Sec-WebSocket-Extensions", extension)) } diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.kt b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.kt index e90391843665..202b95c2af6c 100644 --- a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.kt @@ -93,16 +93,19 @@ class WebSocketHttpTest { private val clientListener = WebSocketRecorder("client") private val serverListener = WebSocketRecorder("server") private val random = Random(0) - private var client = clientTestRule.newClientBuilder() - .writeTimeout(Duration.ofMillis(500)) - .readTimeout(Duration.ofMillis(500)) - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - val response = chain.proceed(chain.request()) - // Ensure application interceptors never see a null body. - assertThat(response.body).isNotNull() - response - }) - .build() + private var client = + clientTestRule.newClientBuilder() + .writeTimeout(Duration.ofMillis(500)) + .readTimeout(Duration.ofMillis(500)) + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + val response = chain.proceed(chain.request()) + // Ensure application interceptors never see a null body. + assertThat(response.body).isNotNull() + response + }, + ) + .build() private fun configureClientTestRule(): OkHttpClientTestRule { val clientTestRule = OkHttpClientTestRule() @@ -127,7 +130,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -142,7 +145,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -157,7 +160,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -172,14 +175,19 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val e = RuntimeException() - clientListener.setNextEventDelegate(object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - throw e - } - }) + clientListener.setNextEventDelegate( + object : WebSocketListener() { + override fun onOpen( + webSocket: WebSocket, + response: Response, + ) { + throw e + } + }, + ) newWebSocket() serverListener.assertOpen() serverListener.assertFailure(EOFException::class.java) @@ -190,21 +198,27 @@ class WebSocketHttpTest { @Disabled("AsyncCall currently lets runtime exceptions propagate.") @Test @Throws( - Exception::class + Exception::class, ) fun throwingOnFailLogs() { webServer.enqueue( MockResponse.Builder() .code(200) .body("Body") - .build() + .build(), ) val e = RuntimeException("boom") - clientListener.setNextEventDelegate(object : WebSocketListener() { - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - throw e - } - }) + clientListener.setNextEventDelegate( + object : WebSocketListener() { + override fun onFailure( + webSocket: WebSocket, + t: Throwable, + response: Response?, + ) { + throw e + } + }, + ) newWebSocket() assertThat(testLogHandler.take()).isEqualTo("INFO: [WS client] onFailure") } @@ -214,17 +228,22 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) newWebSocket() clientListener.assertOpen() val server = serverListener.assertOpen() val e = RuntimeException() - clientListener.setNextEventDelegate(object : WebSocketListener() { - override fun onMessage(webSocket: WebSocket, text: String) { - throw e - } - }) + clientListener.setNextEventDelegate( + object : WebSocketListener() { + override fun onMessage( + webSocket: WebSocket, + text: String, + ) { + throw e + } + }, + ) server.send("Hello, WebSockets!") clientListener.assertFailure(e) serverListener.assertFailure(EOFException::class.java) @@ -236,17 +255,23 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) newWebSocket() clientListener.assertOpen() val server = serverListener.assertOpen() val e = RuntimeException() - clientListener.setNextEventDelegate(object : WebSocketListener() { - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - throw e - } - }) + clientListener.setNextEventDelegate( + object : WebSocketListener() { + override fun onClosing( + webSocket: WebSocket, + code: Int, + reason: String, + ) { + throw e + } + }, + ) server.close(1000, "bye") clientListener.assertFailure(e) serverListener.assertFailure() @@ -258,16 +283,22 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) newWebSocket() clientListener.assertOpen() val server = serverListener.assertOpen() - clientListener.setNextEventDelegate(object : WebSocketListener() { - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - webSocket.close(1000, null) - } - }) + clientListener.setNextEventDelegate( + object : WebSocketListener() { + override fun onClosing( + webSocket: WebSocket, + code: Int, + reason: String, + ) { + webSocket.close(1000, null) + } + }, + ) server.close(1001, "bye") clientListener.assertClosed(1001, "bye") clientListener.assertExhausted() @@ -281,7 +312,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) newWebSocket() val webSocket = clientListener.assertOpen() @@ -296,12 +327,14 @@ class WebSocketHttpTest { MockResponse.Builder() .code(200) .body("Body") - .build() + .build(), ) newWebSocket() clientListener.assertFailure( - 200, "Body", ProtocolException::class.java, - "Expected HTTP 101 response but was '200 OK'" + 200, + "Body", + ProtocolException::class.java, + "Expected HTTP 101 response but was '200 OK'", ) } @@ -311,12 +344,14 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .status("HTTP/1.1 404 Not Found") - .build() + .build(), ) newWebSocket() clientListener.assertFailure( - 404, null, ProtocolException::class.java, - "Expected HTTP 101 response but was '404 Not Found'" + 404, + null, + ProtocolException::class.java, + "Expected HTTP 101 response but was '404 Not Found'", ) } @@ -325,12 +360,12 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .code(408) - .build() + .build(), ) webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -350,17 +385,19 @@ class WebSocketHttpTest { .code(101) .setHeader("Upgrade", "websocket") .setHeader("Sec-WebSocket-Accept", "ujmZX4KXZqjwy6vi1aQFH5p4Ygk=") - .build() + .build(), ) webServer.enqueue( MockResponse.Builder() .socketPolicy(SocketPolicy.DisconnectAtStart) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertFailure( - 101, null, ProtocolException::class.java, - "Expected 'Connection' header value 'Upgrade' but was 'null'" + 101, + null, + ProtocolException::class.java, + "Expected 'Connection' header value 'Upgrade' but was 'null'", ) webSocket.cancel() } @@ -374,17 +411,19 @@ class WebSocketHttpTest { .setHeader("Upgrade", "websocket") .setHeader("Connection", "Downgrade") .setHeader("Sec-WebSocket-Accept", "ujmZX4KXZqjwy6vi1aQFH5p4Ygk=") - .build() + .build(), ) webServer.enqueue( MockResponse.Builder() .socketPolicy(SocketPolicy.DisconnectAtStart) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertFailure( - 101, null, ProtocolException::class.java, - "Expected 'Connection' header value 'Upgrade' but was 'Downgrade'" + 101, + null, + ProtocolException::class.java, + "Expected 'Connection' header value 'Upgrade' but was 'Downgrade'", ) webSocket.cancel() } @@ -397,17 +436,19 @@ class WebSocketHttpTest { .code(101) .setHeader("Connection", "Upgrade") .setHeader("Sec-WebSocket-Accept", "ujmZX4KXZqjwy6vi1aQFH5p4Ygk=") - .build() + .build(), ) webServer.enqueue( MockResponse.Builder() .socketPolicy(SocketPolicy.DisconnectAtStart) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertFailure( - 101, null, ProtocolException::class.java, - "Expected 'Upgrade' header value 'websocket' but was 'null'" + 101, + null, + ProtocolException::class.java, + "Expected 'Upgrade' header value 'websocket' but was 'null'", ) webSocket.cancel() } @@ -421,17 +462,19 @@ class WebSocketHttpTest { .setHeader("Connection", "Upgrade") .setHeader("Upgrade", "Pepsi") .setHeader("Sec-WebSocket-Accept", "ujmZX4KXZqjwy6vi1aQFH5p4Ygk=") - .build() + .build(), ) webServer.enqueue( MockResponse.Builder() .socketPolicy(SocketPolicy.DisconnectAtStart) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertFailure( - 101, null, ProtocolException::class.java, - "Expected 'Upgrade' header value 'websocket' but was 'Pepsi'" + 101, + null, + ProtocolException::class.java, + "Expected 'Upgrade' header value 'websocket' but was 'Pepsi'", ) webSocket.cancel() } @@ -444,17 +487,19 @@ class WebSocketHttpTest { .code(101) .setHeader("Connection", "Upgrade") .setHeader("Upgrade", "websocket") - .build() + .build(), ) webServer.enqueue( MockResponse.Builder() .socketPolicy(SocketPolicy.DisconnectAtStart) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertFailure( - 101, null, ProtocolException::class.java, - "Expected 'Sec-WebSocket-Accept' header value 'ujmZX4KXZqjwy6vi1aQFH5p4Ygk=' but was 'null'" + 101, + null, + ProtocolException::class.java, + "Expected 'Sec-WebSocket-Accept' header value 'ujmZX4KXZqjwy6vi1aQFH5p4Ygk=' but was 'null'", ) webSocket.cancel() } @@ -468,17 +513,19 @@ class WebSocketHttpTest { .setHeader("Connection", "Upgrade") .setHeader("Upgrade", "websocket") .setHeader("Sec-WebSocket-Accept", "magic") - .build() + .build(), ) webServer.enqueue( MockResponse.Builder() .socketPolicy(SocketPolicy.DisconnectAtStart) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertFailure( - 101, null, ProtocolException::class.java, - "Expected 'Sec-WebSocket-Accept' header value 'ujmZX4KXZqjwy6vi1aQFH5p4Ygk=' but was 'magic'" + 101, + null, + ProtocolException::class.java, + "Expected 'Sec-WebSocket-Accept' header value 'ujmZX4KXZqjwy6vi1aQFH5p4Ygk=' but was 'magic'", ) webSocket.cancel() } @@ -490,31 +537,34 @@ class WebSocketHttpTest { Request.Builder() .url(webServer.url("/")) .header("Sec-WebSocket-Extensions", "permessage-deflate") - .build() + .build(), ) clientListener.assertFailure( ProtocolException::class.java, - "Request header not permitted: 'Sec-WebSocket-Extensions'" + "Request header not permitted: 'Sec-WebSocket-Extensions'", ) } @Test fun webSocketAndApplicationInterceptors() { val interceptedCount = AtomicInteger() - client = client.newBuilder() - .addInterceptor(Interceptor { chain: Interceptor.Chain -> - assertThat(chain.request().body).isNull() - val response = chain.proceed(chain.request()) - assertThat(response.header("Connection")).isEqualTo("Upgrade") - assertThat(response.body).isInstanceOf() - interceptedCount.incrementAndGet() - response - }) - .build() + client = + client.newBuilder() + .addInterceptor( + Interceptor { chain: Interceptor.Chain -> + assertThat(chain.request().body).isNull() + val response = chain.proceed(chain.request()) + assertThat(response.header("Connection")).isEqualTo("Upgrade") + assertThat(response.body).isInstanceOf() + interceptedCount.incrementAndGet() + response + }, + ) + .build() webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -524,15 +574,18 @@ class WebSocketHttpTest { @Test fun webSocketAndNetworkInterceptors() { - client = client.newBuilder() - .addNetworkInterceptor(Interceptor { chain: Interceptor.Chain? -> - throw AssertionError() // Network interceptors don't execute. - }) - .build() + client = + client.newBuilder() + .addNetworkInterceptor( + Interceptor { chain: Interceptor.Chain? -> + throw AssertionError() // Network interceptors don't execute. + }, + ) + .build() webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -545,7 +598,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -582,7 +635,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val clientReason = repeat('C', 123) val serverReason = repeat('S', 123) @@ -602,7 +655,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() val server = serverListener.assertOpen() @@ -635,24 +688,26 @@ class WebSocketHttpTest { @Test fun wssScheme() { webServer.useHttps(handshakeCertificates.sslSocketFactory()) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() websocketScheme("wss") } @Test fun httpsScheme() { webServer.useHttps(handshakeCertificates.sslSocketFactory()) - client = client.newBuilder() - .sslSocketFactory( - handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager - ) - .hostnameVerifier(RecordingHostnameVerifier()) - .build() + client = + client.newBuilder() + .sslSocketFactory( + handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager, + ) + .hostnameVerifier(RecordingHostnameVerifier()) + .build() websocketScheme("https") } @@ -661,13 +716,13 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .socketPolicy(NoResponse) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertFailure( SocketTimeoutException::class.java, "timeout", - "Read timed out" + "Read timed out", ) assertThat(webSocket.close(1000, null)).isFalse() } @@ -679,21 +734,22 @@ class WebSocketHttpTest { */ @Test fun readTimeoutAppliesWithinFrames() { - webServer.dispatcher = object : Dispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse { - return upgradeResponse(request) - .body(Buffer().write("81".decodeHex())) // Truncated frame. - .removeHeader("Content-Length") - .socketPolicy(KeepOpen) - .build() + webServer.dispatcher = + object : Dispatcher() { + override fun dispatch(request: RecordedRequest): MockResponse { + return upgradeResponse(request) + .body(Buffer().write("81".decodeHex())) // Truncated frame. + .removeHeader("Content-Length") + .socketPolicy(KeepOpen) + .build() + } } - } val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() clientListener.assertFailure( SocketTimeoutException::class.java, "timeout", - "Read timed out" + "Read timed out", ) assertThat(webSocket.close(1000, null)).isFalse() } @@ -704,7 +760,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -720,13 +776,14 @@ class WebSocketHttpTest { @Test @Throws(Exception::class) fun clientPingsServerOnInterval() { - client = client.newBuilder() - .pingInterval(Duration.ofMillis(500)) - .build() + client = + client.newBuilder() + .pingInterval(Duration.ofMillis(500)) + .build() webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertOpen() @@ -756,7 +813,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertOpen() @@ -781,31 +838,37 @@ class WebSocketHttpTest { @Test fun unacknowledgedPingFailsConnection() { assumeNotWindows() - client = client.newBuilder() - .pingInterval(Duration.ofMillis(500)) - .build() + client = + client.newBuilder() + .pingInterval(Duration.ofMillis(500)) + .build() // Stall in onOpen to prevent pongs from being sent. val latch = CountDownLatch(1) webServer.enqueue( MockResponse.Builder() - .webSocketUpgrade(object : WebSocketListener() { - override fun onOpen(webSocket: WebSocket, response: Response) { - try { - latch.await() // The server can't respond to pings! - } catch (e: InterruptedException) { - throw AssertionError(e) + .webSocketUpgrade( + object : WebSocketListener() { + override fun onOpen( + webSocket: WebSocket, + response: Response, + ) { + try { + latch.await() // The server can't respond to pings! + } catch (e: InterruptedException) { + throw AssertionError(e) + } } - } - }) - .build() + }, + ) + .build(), ) val openAtNanos = System.nanoTime() newWebSocket() clientListener.assertOpen() clientListener.assertFailure( SocketTimeoutException::class.java, - "sent ping but didn't receive pong within 500ms (after 0 successful ping/pongs)" + "sent ping but didn't receive pong within 500ms (after 0 successful ping/pongs)", ) latch.countDown() val elapsedUntilFailure = System.nanoTime() - openAtNanos @@ -819,7 +882,7 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket = newWebSocket() clientListener.assertOpen() @@ -844,13 +907,14 @@ class WebSocketHttpTest { @Test fun webSocketsDontTriggerEventListener() { val listener = RecordingEventListener() - client = client.newBuilder() - .eventListenerFactory(clientTestRule.wrap(listener)) - .build() + client = + client.newBuilder() + .eventListenerFactory(clientTestRule.wrap(listener)) + .build() webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -872,13 +936,14 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .headersDelay(500, TimeUnit.MILLISECONDS) - .build() + .build(), ) - client = client.newBuilder() - .readTimeout(Duration.ZERO) - .writeTimeout(Duration.ZERO) - .callTimeout(Duration.ofMillis(100)) - .build() + client = + client.newBuilder() + .readTimeout(Duration.ZERO) + .writeTimeout(Duration.ZERO) + .callTimeout(Duration.ofMillis(100)) + .build() newWebSocket() clientListener.assertFailure(InterruptedIOException::class.java, "timeout") } @@ -886,13 +951,14 @@ class WebSocketHttpTest { @Test @Throws(Exception::class) fun callTimeoutDoesNotApplyOnceConnected() { - client = client.newBuilder() - .callTimeout(Duration.ofMillis(100)) - .build() + client = + client.newBuilder() + .callTimeout(Duration.ofMillis(100)) + .build() webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) val webSocket: WebSocket = newWebSocket() clientListener.assertOpen() @@ -912,21 +978,23 @@ class WebSocketHttpTest { @Throws(Exception::class) fun webSocketConnectionIsReleased() { // This test assumes HTTP/1.1 pooling semantics. - client = client.newBuilder() - .protocols(Arrays.asList(Protocol.HTTP_1_1)) - .build() + client = + client.newBuilder() + .protocols(Arrays.asList(Protocol.HTTP_1_1)) + .build() webServer.enqueue( MockResponse.Builder() .code(HttpURLConnection.HTTP_NOT_FOUND) .body("not found!") - .build() + .build(), ) webServer.enqueue(MockResponse()) newWebSocket() clientListener.assertFailure() - val regularRequest = Request.Builder() - .url(webServer.url("/")) - .build() + val regularRequest = + Request.Builder() + .url(webServer.url("/")) + .build() val response = client.newCall(regularRequest).execute() response.close() assertThat(webServer.takeRequest().sequenceNumber).isEqualTo(0) @@ -936,9 +1004,10 @@ class WebSocketHttpTest { /** https://github.com/square/okhttp/issues/5705 */ @Test fun closeWithoutSuccessfulConnect() { - val request = Request.Builder() - .url(webServer.url("/")) - .build() + val request = + Request.Builder() + .url(webServer.url("/")) + .build() val webSocket = client.newWebSocket(request, clientListener) webSocket.send("hello") webSocket.close(1000, null) @@ -954,23 +1023,29 @@ class WebSocketHttpTest { .bodyDelay(100, TimeUnit.MILLISECONDS) .body("Wrong endpoint") .code(401) - .build() + .build(), ) } - val request = Request.Builder() - .url(webServer.url("/")) - .build() + val request = + Request.Builder() + .url(webServer.url("/")) + .build() val attempts = CountDownLatch(20) val webSockets = Collections.synchronizedList(ArrayList()) - val reconnectOnFailure: WebSocketListener = object : WebSocketListener() { - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - if (attempts.count > 0) { - clientListener.setNextEventDelegate(this) - webSockets.add(client.newWebSocket(request, clientListener)) - attempts.countDown() + val reconnectOnFailure: WebSocketListener = + object : WebSocketListener() { + override fun onFailure( + webSocket: WebSocket, + t: Throwable, + response: Response?, + ) { + if (attempts.count > 0) { + clientListener.setNextEventDelegate(this) + webSockets.add(client.newWebSocket(request, clientListener)) + attempts.countDown() + } } } - } clientListener.setNextEventDelegate(reconnectOnFailure) webSockets.add(client.newWebSocket(request, clientListener)) attempts.await() @@ -1035,7 +1110,7 @@ class WebSocketHttpTest { MockResponse.Builder() .addHeader("Sec-WebSocket-Extensions", extensionsHeader) .webSocketUpgrade(serverListener) - .build() + .build(), ) val client: WebSocket = newWebSocket() clientListener.assertOpen() @@ -1082,7 +1157,7 @@ class WebSocketHttpTest { MockResponse.Builder() .addHeader("Sec-WebSocket-Extensions", extensionsHeader) .webSocketUpgrade(serverListener) - .build() + .build(), ) newWebSocket() clientListener.assertOpen() @@ -1110,11 +1185,12 @@ class WebSocketHttpTest { webServer.enqueue( MockResponse.Builder() .webSocketUpgrade(serverListener) - .build() + .build(), ) - val request = Request.Builder() - .url(scheme + "://" + webServer.hostName + ":" + webServer.port + "/") - .build() + val request = + Request.Builder() + .url(scheme + "://" + webServer.hostName + ":" + webServer.port + "/") + .build() val webSocket = newWebSocket(request) clientListener.assertOpen() val server = serverListener.assertOpen() @@ -1124,19 +1200,29 @@ class WebSocketHttpTest { } private fun newWebSocket( - request: Request = Request.Builder().get().url( - webServer.url("/") - ).build() + request: Request = + Request.Builder().get().url( + webServer.url("/"), + ).build(), ): RealWebSocket { - val webSocket = RealWebSocket( - TaskRunner.INSTANCE, request, clientListener, - random, client.pingIntervalMillis.toLong(), null, 0L - ) + val webSocket = + RealWebSocket( + TaskRunner.INSTANCE, + request, + clientListener, + random, + client.pingIntervalMillis.toLong(), + null, + 0L, + ) webSocket.connect(client) return webSocket } - private fun closeWebSockets(client: WebSocket, server: WebSocket) { + private fun closeWebSockets( + client: WebSocket, + server: WebSocket, + ) { server.close(1001, "") clientListener.assertClosing(1001, "") client.close(1000, "") diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketReaderTest.kt b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketReaderTest.kt index 1330b11e0fdc..d3f264333e08 100644 --- a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketReaderTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketReaderTest.kt @@ -19,7 +19,6 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.isEqualTo import assertk.assertions.matches -import assertk.fail import java.io.EOFException import java.io.IOException import java.net.ProtocolException @@ -41,34 +40,38 @@ class WebSocketReaderTest { private val random = Random(0) // Mutually exclusive. Use the one corresponding to the peer whose behavior you wish to test. - private val serverReader = WebSocketReader( - isClient = false, - source = data, - frameCallback = callback.asFrameCallback(), - perMessageDeflate = false, - noContextTakeover = false - ) - private val serverReaderWithCompression = WebSocketReader( - isClient = false, - source = data, - frameCallback = callback.asFrameCallback(), - perMessageDeflate = true, - noContextTakeover = false - ) - private val clientReader = WebSocketReader( - isClient = true, - source = data, - frameCallback = callback.asFrameCallback(), - perMessageDeflate = false, - noContextTakeover = false - ) - private val clientReaderWithCompression = WebSocketReader( - isClient = true, - source = data, - frameCallback = callback.asFrameCallback(), - perMessageDeflate = true, - noContextTakeover = false - ) + private val serverReader = + WebSocketReader( + isClient = false, + source = data, + frameCallback = callback.asFrameCallback(), + perMessageDeflate = false, + noContextTakeover = false, + ) + private val serverReaderWithCompression = + WebSocketReader( + isClient = false, + source = data, + frameCallback = callback.asFrameCallback(), + perMessageDeflate = true, + noContextTakeover = false, + ) + private val clientReader = + WebSocketReader( + isClient = true, + source = data, + frameCallback = callback.asFrameCallback(), + perMessageDeflate = false, + noContextTakeover = false, + ) + private val clientReaderWithCompression = + WebSocketReader( + isClient = true, + source = data, + frameCallback = callback.asFrameCallback(), + perMessageDeflate = true, + noContextTakeover = false, + ) @AfterEach fun tearDown() { callback.assertExhausted() @@ -138,7 +141,7 @@ class WebSocketReaderTest { } @Test fun serverSentFramesMustNotBeMasked() { - data.write("8180".decodeHex()) + data.write("8180".decodeHex()) assertFailsWith { clientReader.processNextFrame() }.also { expected -> @@ -211,7 +214,7 @@ class WebSocketReaderTest { clientReader.processNextFrame() }.also { expected -> assertThat(expected.message).isEqualTo( - "Frame length 0x8000000000000000 > 0x7FFFFFFFFFFFFFFF" + "Frame length 0x8000000000000000 > 0x7FFFFFFFFFFFFFFF", ) } } diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketRecorder.kt b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketRecorder.kt index 328331167f33..aaf819277989 100644 --- a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketRecorder.kt +++ b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketRecorder.kt @@ -41,7 +41,10 @@ class WebSocketRecorder( this.delegate = delegate } - override fun onOpen(webSocket: WebSocket, response: Response) { + override fun onOpen( + webSocket: WebSocket, + response: Response, + ) { Platform.get().log("[WS $name] onOpen", Platform.INFO, null) val delegate = delegate if (delegate != null) { @@ -52,7 +55,10 @@ class WebSocketRecorder( } } - override fun onMessage(webSocket: WebSocket, bytes: ByteString) { + override fun onMessage( + webSocket: WebSocket, + bytes: ByteString, + ) { Platform.get().log("[WS $name] onMessage", Platform.INFO, null) val delegate = delegate if (delegate != null) { @@ -63,7 +69,10 @@ class WebSocketRecorder( } } - override fun onMessage(webSocket: WebSocket, text: String) { + override fun onMessage( + webSocket: WebSocket, + text: String, + ) { Platform.get().log("[WS $name] onMessage", Platform.INFO, null) val delegate = delegate if (delegate != null) { @@ -74,7 +83,11 @@ class WebSocketRecorder( } } - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { + override fun onClosing( + webSocket: WebSocket, + code: Int, + reason: String, + ) { Platform.get().log("[WS $name] onClosing $code", Platform.INFO, null) val delegate = delegate if (delegate != null) { @@ -85,7 +98,11 @@ class WebSocketRecorder( } } - override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { + override fun onClosed( + webSocket: WebSocket, + code: Int, + reason: String, + ) { Platform.get().log("[WS $name] onClosed $code", Platform.INFO, null) val delegate = delegate if (delegate != null) { @@ -96,7 +113,11 @@ class WebSocketRecorder( } } - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + override fun onFailure( + webSocket: WebSocket, + t: Throwable, + response: Response?, + ) { Platform.get().log("[WS $name] onFailure", Platform.INFO, t) val delegate = delegate if (delegate != null) { @@ -128,11 +149,17 @@ class WebSocketRecorder( assertThat(nextEvent()).isEqualTo(Pong(payload)) } - fun assertClosing(code: Int, reason: String) { + fun assertClosing( + code: Int, + reason: String, + ) { assertThat(nextEvent()).isEqualTo(Closing(code, reason)) } - fun assertClosed(code: Int, reason: String) { + fun assertClosed( + code: Int, + reason: String, + ) { assertThat(nextEvent()).isEqualTo(Closed(code, reason)) } @@ -151,7 +178,10 @@ class WebSocketRecorder( assertThat(event.t).isSameAs(t) } - fun assertFailure(cls: Class?, vararg messages: String) { + fun assertFailure( + cls: Class?, + vararg messages: String, + ) { val event = nextEvent() as Failure assertThat(event.response).isNull() assertThat(event.t.javaClass).isEqualTo(cls) @@ -164,7 +194,12 @@ class WebSocketRecorder( nextEvent() as Failure } - fun assertFailure(code: Int, body: String?, cls: Class?, message: String?) { + fun assertFailure( + code: Int, + body: String?, + cls: Class?, + message: String?, + ) { val event = nextEvent() as Failure assertThat(event.response!!.code).isEqualTo(code) if (body != null) { @@ -175,27 +210,31 @@ class WebSocketRecorder( } /** Expose this recorder as a frame callback and shim in "ping" events. */ - fun asFrameCallback() = object : WebSocketReader.FrameCallback { - override fun onReadMessage(text: String) { - events.add(Message(string = text)) - } + fun asFrameCallback() = + object : WebSocketReader.FrameCallback { + override fun onReadMessage(text: String) { + events.add(Message(string = text)) + } - override fun onReadMessage(bytes: ByteString) { - events.add(Message(bytes = bytes)) - } + override fun onReadMessage(bytes: ByteString) { + events.add(Message(bytes = bytes)) + } - override fun onReadPing(payload: ByteString) { - events.add(Ping(payload)) - } + override fun onReadPing(payload: ByteString) { + events.add(Ping(payload)) + } - override fun onReadPong(payload: ByteString) { - events.add(Pong(payload)) - } + override fun onReadPong(payload: ByteString) { + events.add(Pong(payload)) + } - override fun onReadClose(code: Int, reason: String) { - events.add(Closing(code, reason)) + override fun onReadClose( + code: Int, + reason: String, + ) { + events.add(Closing(code, reason)) + } } - } internal class Open( val webSocket: WebSocket, @@ -206,10 +245,11 @@ class WebSocketRecorder( val t: Throwable, val response: Response?, ) { - val responseBody: String? = when { - response != null && response.code != 101 -> response.body.string() - else -> null - } + val responseBody: String? = + when { + response != null && response.code != 101 -> response.body.string() + else -> null + } override fun toString(): String { return when (response) { diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketWriterTest.kt b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketWriterTest.kt index 73644c53276b..bce1e7264bfb 100644 --- a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketWriterTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/ws/WebSocketWriterTest.kt @@ -18,6 +18,7 @@ package okhttp3.internal.ws import assertk.assertThat import assertk.assertions.isEqualTo import java.util.Random +import kotlin.test.assertFailsWith import okhttp3.TestUtil.repeat import okhttp3.internal.format import okhttp3.internal.ws.WebSocketProtocol.OPCODE_BINARY @@ -30,8 +31,6 @@ import okio.ByteString.Companion.EMPTY import okio.ByteString.Companion.decodeHex import okio.ByteString.Companion.encodeUtf8 import okio.ByteString.Companion.toByteString -import assertk.fail -import kotlin.test.assertFailsWith import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.AfterEachCallback import org.junit.jupiter.api.extension.ExtensionContext @@ -46,29 +45,32 @@ class WebSocketWriterTest { * exceptions thrown from the test do not cause this check to fail. */ @RegisterExtension - val noDataLeftBehind = AfterEachCallback { context: ExtensionContext -> - if (context.executionException.isPresent) return@AfterEachCallback - assertThat(data.readByteString().hex(), "Data not empty") - .isEqualTo("") - } + val noDataLeftBehind = + AfterEachCallback { context: ExtensionContext -> + if (context.executionException.isPresent) return@AfterEachCallback + assertThat(data.readByteString().hex(), "Data not empty") + .isEqualTo("") + } // Mutually exclusive. Use the one corresponding to the peer whose behavior you wish to test. - private val serverWriter = WebSocketWriter( - isClient = false, - sink = data, - random = random, - perMessageDeflate = false, - noContextTakeover = false, - minimumDeflateSize = 0L - ) - private val clientWriter = WebSocketWriter( - isClient = true, - sink = data, - random = random, - perMessageDeflate = false, - noContextTakeover = false, - minimumDeflateSize = 0L - ) + private val serverWriter = + WebSocketWriter( + isClient = false, + sink = data, + random = random, + perMessageDeflate = false, + noContextTakeover = false, + minimumDeflateSize = 0L, + ) + private val clientWriter = + WebSocketWriter( + isClient = true, + sink = data, + random = random, + perMessageDeflate = false, + noContextTakeover = false, + minimumDeflateSize = 0L, + ) @Test fun serverTextMessage() { serverWriter.writeMessageFrame(OPCODE_TEXT, "Hello".encodeUtf8()) @@ -76,9 +78,15 @@ class WebSocketWriterTest { } @Test fun serverCompressedTextMessage() { - val serverWriter = WebSocketWriter( - false, data, random, true, false, 0L - ) + val serverWriter = + WebSocketWriter( + false, + data, + random, + true, + false, + 0L, + ) serverWriter.writeMessageFrame(OPCODE_TEXT, "Hello".encodeUtf8()) assertData("c107f248cdc9c90700") } @@ -106,16 +114,25 @@ class WebSocketWriterTest { } @Test fun clientCompressedTextMessage() { - val clientWriter = WebSocketWriter( - false, data, random, true, false, 0L - ) + val clientWriter = + WebSocketWriter( + false, + data, + random, + true, + false, + 0L, + ) clientWriter.writeMessageFrame(OPCODE_TEXT, "Hello".encodeUtf8()) assertData("c107f248cdc9c90700") } @Test fun serverBinaryMessage() { - val payload = ("60b420bb3851d9d47acb933dbe70399bf6c92da33af01d4fb770e98c0325f41d3ebaf8986da71" + - "2c82bcd4d554bf0b54023c2").decodeHex() + val payload = + ( + "60b420bb3851d9d47acb933dbe70399bf6c92da33af01d4fb770e98c0325f41d3ebaf8986da71" + + "2c82bcd4d554bf0b54023c2" + ).decodeHex() serverWriter.writeMessageFrame(OPCODE_BINARY, payload) assertData("8232") assertData(payload) @@ -150,14 +167,17 @@ class WebSocketWriterTest { } @Test fun clientBinary() { - val payload = ("60b420bb3851d9d47acb933dbe70399bf6c92da33af01d4fb770e98c0325f41d3ebaf8986da71" + - "2c82bcd4d554bf0b54023c2").decodeHex() + val payload = + ( + "60b420bb3851d9d47acb933dbe70399bf6c92da33af01d4fb770e98c0325f41d3ebaf8986da71" + + "2c82bcd4d554bf0b54023c2" + ).decodeHex() clientWriter.writeMessageFrame(OPCODE_BINARY, payload) assertData("82b2") assertData("60b420bb") assertData( "0000000058e5f96f1a7fb386dec41920967d0d185a443df4d7c4c9376391d4a65e0ed8230d1332734b796dee2" + - "b4495fb4376" + "b4495fb4376", ) } @@ -257,7 +277,7 @@ class WebSocketWriterTest { serverWriter.writePing(binaryData(1000)) }.also { expected -> assertThat(expected.message).isEqualTo( - "Payload size must be less than or equal to 125" + "Payload size must be less than or equal to 125", ) } } @@ -267,7 +287,7 @@ class WebSocketWriterTest { serverWriter.writePong((binaryData(1000))) }.also { expected -> assertThat(expected.message).isEqualTo( - "Payload size must be less than or equal to 125" + "Payload size must be less than or equal to 125", ) } } @@ -278,7 +298,7 @@ class WebSocketWriterTest { serverWriter.writeClose(1000, longReason) }.also { expected -> assertThat(expected.message).isEqualTo( - "Payload size must be less than or equal to 125" + "Payload size must be less than or equal to 125", ) } } diff --git a/okhttp/src/test/java/okhttp3/osgi/OsgiTest.kt b/okhttp/src/test/java/okhttp3/osgi/OsgiTest.kt index 55c8d792e3e5..aba02d8b44a5 100644 --- a/okhttp/src/test/java/okhttp3/osgi/OsgiTest.kt +++ b/okhttp/src/test/java/okhttp3/osgi/OsgiTest.kt @@ -55,7 +55,7 @@ class OsgiTest { createBndRun(workspace).use { bndRun -> bndRun.resolve( false, - false + false, ) } } @@ -71,7 +71,7 @@ class OsgiTest { "${Constants.PLUGIN}.$REPO_NAME", LocalIndexedRepo::class.java.getName() + "; ${LocalIndexedRepo.PROP_NAME} = '$REPO_NAME'" + - "; ${LocalIndexedRepo.PROP_LOCAL_DIR} = '$repoDir'" + "; ${LocalIndexedRepo.PROP_LOCAL_DIR} = '$repoDir'", ) refresh() prepareWorkspace() @@ -89,14 +89,16 @@ class OsgiTest { private fun createBndRun(workspace: Workspace): Bndrun { // Creating the run require string. It will always use the latest version of each bundle // available in the repository. - val runRequireString = REQUIRED_BUNDLES.joinToString(separator = ",") { - "osgi.identity;filter:='(osgi.identity=$it)'" - } + val runRequireString = + REQUIRED_BUNDLES.joinToString(separator = ",") { + "osgi.identity;filter:='(osgi.identity=$it)'" + } - val bndEditModel = BndEditModel(workspace).apply { - // Temporary project to satisfy bnd API. - project = Project(workspace, workspaceDir.toFile()) - } + val bndEditModel = + BndEditModel(workspace).apply { + // Temporary project to satisfy bnd API. + project = Project(workspace, workspaceDir.toFile()) + } return Bndrun(bndEditModel).apply { setRunfw(RESOLVE_OSGI_FRAMEWORK) @@ -113,9 +115,10 @@ class OsgiTest { private fun RepositoryPlugin.deployClassPath() { val classpath = System.getProperty("java.class.path") - val entries = classpath.split(File.pathSeparator.toRegex()) - .dropLastWhile { it.isEmpty() } - .toTypedArray() + val entries = + classpath.split(File.pathSeparator.toRegex()) + .dropLastWhile { it.isEmpty() } + .toTypedArray() for (classPathEntry in entries) { deployFile(classPathEntry.toPath()) } @@ -141,20 +144,20 @@ class OsgiTest { val fileSystem = FileSystem.SYSTEM /** Each is the Bundle-SymbolicName of an OkHttp module's OSGi configuration. */ - private val REQUIRED_BUNDLES: List = mutableListOf( - "com.squareup.okhttp3", - "com.squareup.okhttp3.brotli", - "com.squareup.okhttp3.dnsoverhttps", - "com.squareup.okhttp3.logging", - "com.squareup.okhttp3.sse", - "com.squareup.okhttp3.tls", - "com.squareup.okhttp3.urlconnection" - ) + private val REQUIRED_BUNDLES: List = + mutableListOf( + "com.squareup.okhttp3", + "com.squareup.okhttp3.brotli", + "com.squareup.okhttp3.dnsoverhttps", + "com.squareup.okhttp3.logging", + "com.squareup.okhttp3.sse", + "com.squareup.okhttp3.tls", + "com.squareup.okhttp3.urlconnection", + ) /** Equinox must also be on the testing classpath. */ private const val RESOLVE_OSGI_FRAMEWORK = "org.eclipse.osgi" private const val RESOLVE_JAVA_VERSION = "JavaSE-1.8" private const val REPO_NAME = "OsgiTest" - } } diff --git a/regression-test/src/androidTest/java/okhttp/regression/compare/ApacheHttpClientHttp2Test.kt b/regression-test/src/androidTest/java/okhttp/regression/compare/ApacheHttpClientHttp2Test.kt index 5f8a1360317c..ebcac41be929 100644 --- a/regression-test/src/androidTest/java/okhttp/regression/compare/ApacheHttpClientHttp2Test.kt +++ b/regression-test/src/androidTest/java/okhttp/regression/compare/ApacheHttpClientHttp2Test.kt @@ -71,4 +71,4 @@ object LoggingCallback : FutureCallback { override fun cancelled() { println("Cancelled") } -} \ No newline at end of file +} diff --git a/regression-test/src/androidTest/java/okhttp/regression/compare/ApacheHttpClientTest.kt b/regression-test/src/androidTest/java/okhttp/regression/compare/ApacheHttpClientTest.kt index aa4c8cec4e03..275a70ac18ef 100644 --- a/regression-test/src/androidTest/java/okhttp/regression/compare/ApacheHttpClientTest.kt +++ b/regression-test/src/androidTest/java/okhttp/regression/compare/ApacheHttpClientTest.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp.regression.compare; +package okhttp.regression.compare import androidx.test.ext.junit.runners.AndroidJUnit4 import org.apache.hc.client5.http.classic.methods.HttpGet diff --git a/samples/compare/src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt b/samples/compare/src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt index 215749275621..bf1031a20a31 100644 --- a/samples/compare/src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt +++ b/samples/compare/src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt @@ -41,9 +41,11 @@ class ApacheHttpClientTest { } @Test fun get(server: MockWebServer) { - server.enqueue(MockResponse.Builder() + server.enqueue( + MockResponse.Builder() .body("hello, Apache HttpClient 5.x") - .build()) + .build(), + ) val request = HttpGet(server.url("/").toUri()) request.addHeader("Accept", "text/plain") @@ -54,9 +56,9 @@ class ApacheHttpClientTest { } val recorded = server.takeRequest() - assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") - assertThat(recorded.headers["Accept-Encoding"]).isEqualTo("gzip, x-gzip, deflate") - assertThat(recorded.headers["Connection"]).isEqualTo("keep-alive") - assertThat(recorded.headers["User-Agent"]!!).startsWith("Apache-HttpClient/") + assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") + assertThat(recorded.headers["Accept-Encoding"]).isEqualTo("gzip, x-gzip, deflate") + assertThat(recorded.headers["Connection"]).isEqualTo("keep-alive") + assertThat(recorded.headers["User-Agent"]!!).startsWith("Apache-HttpClient/") } } diff --git a/samples/compare/src/test/kotlin/okhttp3/compare/JavaHttpClientTest.kt b/samples/compare/src/test/kotlin/okhttp3/compare/JavaHttpClientTest.kt index 05ed1e6d5804..1cac2d6a8129 100644 --- a/samples/compare/src/test/kotlin/okhttp3/compare/JavaHttpClientTest.kt +++ b/samples/compare/src/test/kotlin/okhttp3/compare/JavaHttpClientTest.kt @@ -39,21 +39,26 @@ import org.junit.jupiter.api.extension.RegisterExtension * Baseline test if we ned to validate OkHttp behaviour against other popular clients. */ class JavaHttpClientTest { - @JvmField @RegisterExtension val platform = PlatformRule() + @JvmField @RegisterExtension + val platform = PlatformRule() @Test fun get(server: MockWebServer) { // Not available platform.expectFailureOnJdkVersion(8) - val httpClient = HttpClient.newBuilder() - .followRedirects(NORMAL) - .build() + val httpClient = + HttpClient.newBuilder() + .followRedirects(NORMAL) + .build() - server.enqueue(MockResponse.Builder() + server.enqueue( + MockResponse.Builder() .body("hello, Java HTTP Client") - .build()) + .build(), + ) - val request = HttpRequest.newBuilder(server.url("/").toUri()) + val request = + HttpRequest.newBuilder(server.url("/").toUri()) .header("Accept", "text/plain") .build() @@ -62,14 +67,14 @@ class JavaHttpClientTest { assertThat(response.body()).isEqualTo("hello, Java HTTP Client") val recorded = server.takeRequest() - assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") - assertThat(recorded.headers["Accept-Encoding"]).isNull() // No built-in gzip. - assertThat(recorded.headers["Connection"]).isEqualTo("Upgrade, HTTP2-Settings") - if (PlatformVersion.majorVersion < 19) { - assertThat(recorded.headers["Content-Length"]).isEqualTo("0") - } - assertThat(recorded.headers["HTTP2-Settings"]).isNotNull() - assertThat(recorded.headers["Upgrade"]).isEqualTo("h2c") // HTTP/2 over plaintext! - assertThat(recorded.headers["User-Agent"]!!).matches(Regex("Java-http-client/.*")) + assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") + assertThat(recorded.headers["Accept-Encoding"]).isNull() // No built-in gzip. + assertThat(recorded.headers["Connection"]).isEqualTo("Upgrade, HTTP2-Settings") + if (PlatformVersion.majorVersion < 19) { + assertThat(recorded.headers["Content-Length"]).isEqualTo("0") + } + assertThat(recorded.headers["HTTP2-Settings"]).isNotNull() + assertThat(recorded.headers["Upgrade"]).isEqualTo("h2c") // HTTP/2 over plaintext! + assertThat(recorded.headers["User-Agent"]!!).matches(Regex("Java-http-client/.*")) } } diff --git a/samples/compare/src/test/kotlin/okhttp3/compare/JettyHttpClientTest.kt b/samples/compare/src/test/kotlin/okhttp3/compare/JettyHttpClientTest.kt index cd167f3e31f4..50c376bbee84 100644 --- a/samples/compare/src/test/kotlin/okhttp3/compare/JettyHttpClientTest.kt +++ b/samples/compare/src/test/kotlin/okhttp3/compare/JettyHttpClientTest.kt @@ -47,16 +47,17 @@ class JettyHttpClientTest { @Test fun get(server: MockWebServer) { server.enqueue(MockResponse(body = "hello, Jetty HTTP Client")) - val request = client.newRequest(server.url("/").toUri()) + val request = + client.newRequest(server.url("/").toUri()) .header("Accept", "text/plain") val response = request.send() assertThat(response.status).isEqualTo(200) assertThat(response.contentAsString).isEqualTo("hello, Jetty HTTP Client") val recorded = server.takeRequest() - assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") - assertThat(recorded.headers["Accept-Encoding"]).isEqualTo("gzip") - assertThat(recorded.headers["Connection"]).isNull() - assertThat(recorded.headers["User-Agent"]!!).matches(Regex("Jetty/.*")) + assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") + assertThat(recorded.headers["Accept-Encoding"]).isEqualTo("gzip") + assertThat(recorded.headers["Connection"]).isNull() + assertThat(recorded.headers["User-Agent"]!!).matches(Regex("Jetty/.*")) } } diff --git a/samples/compare/src/test/kotlin/okhttp3/compare/OkHttpClientTest.kt b/samples/compare/src/test/kotlin/okhttp3/compare/OkHttpClientTest.kt index 9336dbc4fb21..23228a1dd1c8 100644 --- a/samples/compare/src/test/kotlin/okhttp3/compare/OkHttpClientTest.kt +++ b/samples/compare/src/test/kotlin/okhttp3/compare/OkHttpClientTest.kt @@ -32,14 +32,16 @@ import org.junit.jupiter.api.extension.RegisterExtension * https://square.github.io/okhttp/ */ class OkHttpClientTest { - @JvmField @RegisterExtension val platform = PlatformRule() + @JvmField @RegisterExtension + val platform = PlatformRule() @Test fun get(server: MockWebServer) { server.enqueue(MockResponse(body = "hello, OkHttp")) val client = OkHttpClient() - val request = Request.Builder() + val request = + Request.Builder() .url(server.url("/")) .header("Accept", "text/plain") .build() @@ -48,9 +50,9 @@ class OkHttpClientTest { assertThat(response.body.string()).isEqualTo("hello, OkHttp") val recorded = server.takeRequest() - assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") - assertThat(recorded.headers["Accept-Encoding"]).isEqualTo("gzip") - assertThat(recorded.headers["Connection"]).isEqualTo("Keep-Alive") - assertThat(recorded.headers["User-Agent"]!!).matches(Regex("okhttp/.*")) + assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") + assertThat(recorded.headers["Accept-Encoding"]).isEqualTo("gzip") + assertThat(recorded.headers["Connection"]).isEqualTo("Keep-Alive") + assertThat(recorded.headers["User-Agent"]!!).matches(Regex("okhttp/.*")) } } diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/AccessHeaders.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/AccessHeaders.kt index 076b4159577f..73b2de973639 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/AccessHeaders.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/AccessHeaders.kt @@ -23,7 +23,8 @@ class AccessHeaders { private val client = OkHttpClient() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("https://api.github.com/repos/square/okhttp/issues") .header("User-Agent", "OkHttp Headers.java") .addHeader("Accept", "application/json; q=0.5") diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/AsynchronousGet.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/AsynchronousGet.kt index eb74aad01d06..46a25c3aec27 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/AsynchronousGet.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/AsynchronousGet.kt @@ -26,27 +26,36 @@ class AsynchronousGet { private val client = OkHttpClient() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("http://publicobject.com/helloworld.txt") .build() - client.newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - e.printStackTrace() - } + client.newCall(request).enqueue( + object : Callback { + override fun onFailure( + call: Call, + e: IOException, + ) { + e.printStackTrace() + } - override fun onResponse(call: Call, response: Response) { - response.use { - if (!response.isSuccessful) throw IOException("Unexpected code $response") + override fun onResponse( + call: Call, + response: Response, + ) { + response.use { + if (!response.isSuccessful) throw IOException("Unexpected code $response") - for ((name, value) in response.headers) { - println("$name: $value") - } + for ((name, value) in response.headers) { + println("$name: $value") + } - println(response.body.string()) + println(response.body.string()) + } } - } - }) + }, + ) } } diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/Authenticate.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/Authenticate.kt index c24a56663044..bf24bcee4c0d 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/Authenticate.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/Authenticate.kt @@ -24,26 +24,33 @@ import okhttp3.Response import okhttp3.Route class Authenticate { - private val client = OkHttpClient.Builder() - .authenticator(object : Authenticator { - @Throws(IOException::class) - override fun authenticate(route: Route?, response: Response): Request? { - if (response.request.header("Authorization") != null) { - return null // Give up, we've already attempted to authenticate. - } + private val client = + OkHttpClient.Builder() + .authenticator( + object : Authenticator { + @Throws(IOException::class) + override fun authenticate( + route: Route?, + response: Response, + ): Request? { + if (response.request.header("Authorization") != null) { + return null // Give up, we've already attempted to authenticate. + } - println("Authenticating for response: $response") - println("Challenges: ${response.challenges()}") - val credential = Credentials.basic("jesse", "password1") - return response.request.newBuilder() + println("Authenticating for response: $response") + println("Challenges: ${response.challenges()}") + val credential = Credentials.basic("jesse", "password1") + return response.request.newBuilder() .header("Authorization", credential) .build() - } - }) + } + }, + ) .build() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("http://publicobject.com/secrets/hellosecret.txt") .build() diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/CacheResponse.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/CacheResponse.kt index 21f2353970fe..3f2ca38a7042 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/CacheResponse.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/CacheResponse.kt @@ -22,36 +22,42 @@ import okhttp3.OkHttpClient import okhttp3.Request class CacheResponse(cacheDirectory: File) { - private val client: OkHttpClient = OkHttpClient.Builder() - .cache(Cache( + private val client: OkHttpClient = + OkHttpClient.Builder() + .cache( + Cache( directory = cacheDirectory, // 1 MiB. - maxSize = 10L * 1024L * 1024L - )) + maxSize = 10L * 1024L * 1024L, + ), + ) .build() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("http://publicobject.com/helloworld.txt") .build() - val response1Body = client.newCall(request).execute().use { - if (!it.isSuccessful) throw IOException("Unexpected code $it") + val response1Body = + client.newCall(request).execute().use { + if (!it.isSuccessful) throw IOException("Unexpected code $it") - println("Response 1 response: $it") - println("Response 1 cache response: ${it.cacheResponse}") - println("Response 1 network response: ${it.networkResponse}") - return@use it.body.string() - } + println("Response 1 response: $it") + println("Response 1 cache response: ${it.cacheResponse}") + println("Response 1 network response: ${it.networkResponse}") + return@use it.body.string() + } - val response2Body = client.newCall(request).execute().use { - if (!it.isSuccessful) throw IOException("Unexpected code $it") + val response2Body = + client.newCall(request).execute().use { + if (!it.isSuccessful) throw IOException("Unexpected code $it") - println("Response 2 response: $it") - println("Response 2 cache response: ${it.cacheResponse}") - println("Response 2 network response: ${it.networkResponse}") - return@use it.body.string() - } + println("Response 2 response: $it") + println("Response 2 cache response: ${it.cacheResponse}") + println("Response 2 network response: ${it.networkResponse}") + return@use it.body.string() + } println("Response 2 equals Response 1? " + (response1Body == response2Body)) } diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/CancelCall.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/CancelCall.kt index a8cc366592aa..980f2b915712 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/CancelCall.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/CancelCall.kt @@ -26,7 +26,8 @@ class CancelCall { private val client = OkHttpClient() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. .build() @@ -43,12 +44,18 @@ class CancelCall { System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f) try { call.execute().use { response -> - System.out.printf("%.2f Call was expected to fail, but completed: %s%n", - (System.nanoTime() - startNanos) / 1e9f, response) + System.out.printf( + "%.2f Call was expected to fail, but completed: %s%n", + (System.nanoTime() - startNanos) / 1e9f, + response, + ) } } catch (e: IOException) { - System.out.printf("%.2f Call failed as expected: %s%n", - (System.nanoTime() - startNanos) / 1e9f, e) + System.out.printf( + "%.2f Call failed as expected: %s%n", + (System.nanoTime() - startNanos) / 1e9f, + e, + ) } } } diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/CertificatePinning.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/CertificatePinning.kt index 0716b5ca551c..8540f5fa5c40 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/CertificatePinning.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/CertificatePinning.kt @@ -21,15 +21,18 @@ import okhttp3.OkHttpClient import okhttp3.Request class CertificatePinning { - private val client = OkHttpClient.Builder() + private val client = + OkHttpClient.Builder() .certificatePinner( - CertificatePinner.Builder() - .add("publicobject.com", "sha256/Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=") - .build()) + CertificatePinner.Builder() + .add("publicobject.com", "sha256/Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=") + .build(), + ) .build() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("https://publicobject.com/robots.txt") .build() diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/ConfigureTimeouts.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/ConfigureTimeouts.kt index 366a8e0c1219..45a051ffcd4c 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/ConfigureTimeouts.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/ConfigureTimeouts.kt @@ -20,7 +20,8 @@ import okhttp3.OkHttpClient import okhttp3.Request class ConfigureTimeouts { - private val client: OkHttpClient = OkHttpClient.Builder() + private val client: OkHttpClient = + OkHttpClient.Builder() .connectTimeout(5, TimeUnit.SECONDS) .writeTimeout(5, TimeUnit.SECONDS) .readTimeout(5, TimeUnit.SECONDS) @@ -28,7 +29,8 @@ class ConfigureTimeouts { .build() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. .build() diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/CustomTrust.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/CustomTrust.kt index a060b43f202e..677cf651d939 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/CustomTrust.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/CustomTrust.kt @@ -27,7 +27,8 @@ class CustomTrust { // https://publicobject.com (Comodo) and https://squareup.com (Entrust). But they aren't // sufficient to connect to most HTTPS sites including https://godaddy.com and https://visa.com. // Typically developers will need to get a PEM file from their organization's TLS administrator. - val comodoRsaCertificationAuthority = """ + val comodoRsaCertificationAuthority = + """ -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G @@ -65,7 +66,8 @@ class CustomTrust { """.trimIndent().decodeCertificatePem() // CN=Entrust Root Certification Authority, OU="(c) 2006 Entrust, Inc.", OU=www.entrust.net/CPS is incorporated by reference, O="Entrust, Inc.", C=US - val entrustRootCertificateAuthority = """ + val entrustRootCertificateAuthority = + """ -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 @@ -96,7 +98,8 @@ class CustomTrust { """.trimIndent().decodeCertificatePem() // CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US - val letsEncryptCertificateAuthority = """ + val letsEncryptCertificateAuthority = + """ -----BEGIN CERTIFICATE----- MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT @@ -133,13 +136,14 @@ class CustomTrust { // instead read this from a resource file that gets bundled with the application. val certificates = HandshakeCertificates.Builder() - .addTrustedCertificate(letsEncryptCertificateAuthority) - .addTrustedCertificate(entrustRootCertificateAuthority) - .addTrustedCertificate(comodoRsaCertificationAuthority) - // Uncomment if standard certificates are also required. - // .addPlatformTrustedCertificates() - .build() - client = OkHttpClient.Builder() + .addTrustedCertificate(letsEncryptCertificateAuthority) + .addTrustedCertificate(entrustRootCertificateAuthority) + .addTrustedCertificate(comodoRsaCertificationAuthority) + // Uncomment if standard certificates are also required. + // .addPlatformTrustedCertificates() + .build() + client = + OkHttpClient.Builder() .sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager) .build() } @@ -152,21 +156,21 @@ class CustomTrust { private fun showUrl(url: String) { val request = Builder().url(url).build() client.newCall(request) - .execute() - .use { response -> - if (!response.isSuccessful) { - val responseHeaders = response.headers - for (i in 0 until responseHeaders.size) { - println(responseHeaders.name(i) + ": " + responseHeaders.value(i)) - } - throw IOException("Unexpected code $response") + .execute() + .use { response -> + if (!response.isSuccessful) { + val responseHeaders = response.headers + for (i in 0 until responseHeaders.size) { + println(responseHeaders.name(i) + ": " + responseHeaders.value(i)) } - println(response.body.string()) + throw IOException("Unexpected code $response") + } + println(response.body.string()) - for (peerCertificate in response.handshake?.peerCertificates.orEmpty()) { - println((peerCertificate as X509Certificate).subjectDN) - } + for (peerCertificate in response.handshake?.peerCertificates.orEmpty()) { + println((peerCertificate as X509Certificate).subjectDN) } + } } } diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/DevServer.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/DevServer.kt index a3c1b5812d0c..cce5a5bd9dcb 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/DevServer.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/DevServer.kt @@ -27,20 +27,25 @@ import okhttp3.tls.internal.TlsUtil class DevServer { val handshakeCertificates = TlsUtil.localhost() - val server = MockWebServer().apply { - useHttps(handshakeCertificates.sslSocketFactory(), false) + val server = + MockWebServer().apply { + useHttps(handshakeCertificates.sslSocketFactory(), false) - enqueue(MockResponse() - .setResponseCode(HTTP_MOVED_TEMP) - .setHeader("Location", "https://www.google.com/robots.txt")) - } + enqueue( + MockResponse() + .setResponseCode(HTTP_MOVED_TEMP) + .setHeader("Location", "https://www.google.com/robots.txt"), + ) + } - val clientCertificates = HandshakeCertificates.Builder() + val clientCertificates = + HandshakeCertificates.Builder() .addPlatformTrustedCertificates() .addInsecureHost(server.hostName) .build() - val client = OkHttpClient.Builder() + val client = + OkHttpClient.Builder() .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) .build() diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/ParseResponseWithMoshi.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/ParseResponseWithMoshi.kt index cf18735a355c..1cd22596758f 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/ParseResponseWithMoshi.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/ParseResponseWithMoshi.kt @@ -27,7 +27,8 @@ class ParseResponseWithMoshi { private val gistJsonAdapter = moshi.adapter(Gist::class.java) fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("https://api.github.com/gists/c2a7c39532239ff261be") .build() client.newCall(request).execute().use { response -> diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/PerCallSettings.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/PerCallSettings.kt index 90247ad828df..bfa7bdaa3228 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/PerCallSettings.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/PerCallSettings.kt @@ -24,12 +24,14 @@ class PerCallSettings { private val client = OkHttpClient() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay. .build() // Copy to customize OkHttp for this request. - val client1 = client.newBuilder() + val client1 = + client.newBuilder() .readTimeout(500, TimeUnit.MILLISECONDS) .build() try { @@ -41,7 +43,8 @@ class PerCallSettings { } // Copy to customize OkHttp for this request. - val client2 = client.newBuilder() + val client2 = + client.newBuilder() .readTimeout(3000, TimeUnit.MILLISECONDS) .build() try { diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/PostFile.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/PostFile.kt index a1f9f55a48f7..6daae2f92d5b 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/PostFile.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/PostFile.kt @@ -29,10 +29,11 @@ class PostFile { fun run() { val file = File("README.md") - val request = Request( - url = "https://api.github.com/markdown/raw".toHttpUrl(), - body = file.asRequestBody(MEDIA_TYPE_MARKDOWN), - ) + val request = + Request( + url = "https://api.github.com/markdown/raw".toHttpUrl(), + body = file.asRequestBody(MEDIA_TYPE_MARKDOWN), + ) client.newCall(request).execute().use { response -> if (!response.isSuccessful) throw IOException("Unexpected code $response") diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/PostForm.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/PostForm.kt index ed38886a9ca4..b539589f7417 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/PostForm.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/PostForm.kt @@ -25,13 +25,15 @@ class PostForm { private val client = OkHttpClient() fun run() { - val formBody = FormBody.Builder() + val formBody = + FormBody.Builder() .add("search", "Jurassic Park") .build() - val request = Request( - url = "https://en.wikipedia.org/w/index.php".toHttpUrl(), - body = formBody, - ) + val request = + Request( + url = "https://en.wikipedia.org/w/index.php".toHttpUrl(), + body = formBody, + ) client.newCall(request).execute().use { response -> if (!response.isSuccessful) throw IOException("Unexpected code $response") diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/PostMultipart.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/PostMultipart.kt index 926092da407b..311df9a86601 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/PostMultipart.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/PostMultipart.kt @@ -28,14 +28,19 @@ class PostMultipart { fun run() { // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image - val requestBody = MultipartBody.Builder() + val requestBody = + MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("title", "Square Logo") - .addFormDataPart("image", "logo-square.png", - File("docs/images/logo-square.png").asRequestBody(MEDIA_TYPE_PNG)) + .addFormDataPart( + "image", + "logo-square.png", + File("docs/images/logo-square.png").asRequestBody(MEDIA_TYPE_PNG), + ) .build() - val request = Request.Builder() + val request = + Request.Builder() .header("Authorization", "Client-ID $IMGUR_CLIENT_ID") .url("https://api.imgur.com/3/image") .post(requestBody) diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/PostPath.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/PostPath.kt index 976e1cedfabb..3e960cccad0e 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/PostPath.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/PostPath.kt @@ -34,7 +34,8 @@ class PostPath { writeUtf8("{}") } - val request = Request.Builder() + val request = + Request.Builder() .url("https://httpbin.org/anything") .put(path.asRequestBody(fileSystem, MEDIA_TYPE_JSON)) .build() diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/PostStreaming.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/PostStreaming.kt index 017b8a00f7c3..4328f4ce9275 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/PostStreaming.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/PostStreaming.kt @@ -27,30 +27,32 @@ class PostStreaming { private val client = OkHttpClient() fun run() { - val requestBody = object : RequestBody() { - override fun contentType() = MEDIA_TYPE_MARKDOWN + val requestBody = + object : RequestBody() { + override fun contentType() = MEDIA_TYPE_MARKDOWN - override fun writeTo(sink: BufferedSink) { - sink.writeUtf8("Numbers\n") - sink.writeUtf8("-------\n") - for (i in 2..997) { - sink.writeUtf8(String.format(" * $i = ${factor(i)}\n")) + override fun writeTo(sink: BufferedSink) { + sink.writeUtf8("Numbers\n") + sink.writeUtf8("-------\n") + for (i in 2..997) { + sink.writeUtf8(String.format(" * $i = ${factor(i)}\n")) + } } - } - private fun factor(n: Int): String { - for (i in 2 until n) { - val x = n / i - if (x * i == n) return "${factor(x)} × $i" + private fun factor(n: Int): String { + for (i in 2 until n) { + val x = n / i + if (x * i == n) return "${factor(x)} × $i" + } + return n.toString() } - return n.toString() } - } - val request = Request( - url = "https://api.github.com/markdown/raw".toHttpUrl(), - body = requestBody, - ) + val request = + Request( + url = "https://api.github.com/markdown/raw".toHttpUrl(), + body = requestBody, + ) client.newCall(request).execute().use { response -> if (!response.isSuccessful) throw IOException("Unexpected code $response") diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/PostString.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/PostString.kt index d2a6ac8c8b12..ab553ea94f3b 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/PostString.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/PostString.kt @@ -26,19 +26,22 @@ class PostString { private val client = OkHttpClient() fun run() { - val postBody = """ - |Releases - |-------- - | - | * _1.0_ May 6, 2013 - | * _1.1_ June 15, 2013 - | * _1.2_ August 11, 2013 - |""".trimMargin() - - val request = Request( - url = "https://api.github.com/markdown/raw".toHttpUrl(), - body = postBody.toRequestBody(MEDIA_TYPE_MARKDOWN), - ) + val postBody = + """ + |Releases + |-------- + | + | * _1.0_ May 6, 2013 + | * _1.1_ June 15, 2013 + | * _1.2_ August 11, 2013 + | + """.trimMargin() + + val request = + Request( + url = "https://api.github.com/markdown/raw".toHttpUrl(), + body = postBody.toRequestBody(MEDIA_TYPE_MARKDOWN), + ) client.newCall(request).execute().use { response -> if (!response.isSuccessful) throw IOException("Unexpected code $response") diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/SynchronousGet.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/SynchronousGet.kt index ed480456d396..5c316de091ea 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/SynchronousGet.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/SynchronousGet.kt @@ -23,7 +23,8 @@ class SynchronousGet { private val client = OkHttpClient() fun run() { - val request = Request.Builder() + val request = + Request.Builder() .url("https://publicobject.com/helloworld.txt") .build() diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/WiresharkExample.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/WiresharkExample.kt index 889fc93d361d..cfb08e789258 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/WiresharkExample.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/WiresharkExample.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "Since15") + package okhttp3.recipes.kt import java.io.File @@ -66,7 +67,7 @@ logFile = File("/tmp/key.log"), tlsVersions = tlsVersions, launch = launch)` class WireSharkListenerFactory( private val logFile: File, private val tlsVersions: List, - private val launch: Launch? = null + private val launch: Launch? = null, ) : EventListener.Factory { override fun create(call: Call): EventListener { return WireSharkKeyLoggerListener(logFile, launch == null) @@ -89,22 +90,24 @@ class WireSharkListenerFactory( } CommandLine -> { return ProcessBuilder( - "tshark", "-l", "-V", "-o", "tls.keylog_file:$logFile", "-Y", "http2", "-O", "http2,tls") - .redirectInput(File("/dev/null")) - .redirectOutput(Redirect.INHERIT) - .redirectError(Redirect.INHERIT) - .start() + "tshark", "-l", "-V", "-o", "tls.keylog_file:$logFile", "-Y", "http2", "-O", "http2,tls", + ) + .redirectInput(File("/dev/null")) + .redirectOutput(Redirect.INHERIT) + .redirectError(Redirect.INHERIT) + .start() } Gui -> { return ProcessBuilder( - "nohup", "wireshark", "-o", "tls.keylog_file:$logFile", "-S", "-l", "-Y", "http2", "-k") - .redirectInput(File("/dev/null")) - .redirectOutput(File("/dev/null")) - .redirectError(Redirect.INHERIT) - .start().also { - // Give it time to start collecting - Thread.sleep(2000) - } + "nohup", "wireshark", "-o", "tls.keylog_file:$logFile", "-S", "-l", "-Y", "http2", "-k", + ) + .redirectInput(File("/dev/null")) + .redirectOutput(File("/dev/null")) + .redirectError(Redirect.INHERIT) + .start().also { + // Give it time to start collecting + Thread.sleep(2000) + } } } @@ -113,61 +116,62 @@ class WireSharkListenerFactory( class WireSharkKeyLoggerListener( private val logFile: File, - private val verbose: Boolean = false + private val verbose: Boolean = false, ) : EventListener() { var random: String? = null lateinit var currentThread: Thread - private val loggerHandler = object : Handler() { - override fun publish(record: LogRecord) { - // Try to avoid multi threading issues with concurrent requests - if (Thread.currentThread() != currentThread) { - return - } - - // https://timothybasanov.com/2016/05/26/java-pre-master-secret.html - // https://security.stackexchange.com/questions/35639/decrypting-tls-in-wireshark-when-using-dhe-rsa-ciphersuites - // https://stackoverflow.com/questions/36240279/how-do-i-extract-the-pre-master-secret-using-an-openssl-based-client - - // TLSv1.2 Events - // Produced ClientHello handshake message - // Consuming ServerHello handshake message - // Consuming server Certificate handshake message - // Consuming server CertificateStatus handshake message - // Found trusted certificate - // Consuming ECDH ServerKeyExchange handshake message - // Consuming ServerHelloDone handshake message - // Produced ECDHE ClientKeyExchange handshake message - // Produced client Finished handshake message - // Consuming server Finished handshake message - // Produced ClientHello handshake message - // - // Raw write - // Raw read - // Plaintext before ENCRYPTION - // Plaintext after DECRYPTION - val message = record.message - val parameters = record.parameters - - if (parameters != null && !message.startsWith("Raw") && !message.startsWith("Plaintext")) { - if (verbose) { - println(record.message) - println(record.parameters[0]) + private val loggerHandler = + object : Handler() { + override fun publish(record: LogRecord) { + // Try to avoid multi threading issues with concurrent requests + if (Thread.currentThread() != currentThread) { + return } - // JSSE logs additional messages as parameters that are not referenced in the log message. - val parameter = parameters[0] as String + // https://timothybasanov.com/2016/05/26/java-pre-master-secret.html + // https://security.stackexchange.com/questions/35639/decrypting-tls-in-wireshark-when-using-dhe-rsa-ciphersuites + // https://stackoverflow.com/questions/36240279/how-do-i-extract-the-pre-master-secret-using-an-openssl-based-client + + // TLSv1.2 Events + // Produced ClientHello handshake message + // Consuming ServerHello handshake message + // Consuming server Certificate handshake message + // Consuming server CertificateStatus handshake message + // Found trusted certificate + // Consuming ECDH ServerKeyExchange handshake message + // Consuming ServerHelloDone handshake message + // Produced ECDHE ClientKeyExchange handshake message + // Produced client Finished handshake message + // Consuming server Finished handshake message + // Produced ClientHello handshake message + // + // Raw write + // Raw read + // Plaintext before ENCRYPTION + // Plaintext after DECRYPTION + val message = record.message + val parameters = record.parameters + + if (parameters != null && !message.startsWith("Raw") && !message.startsWith("Plaintext")) { + if (verbose) { + println(record.message) + println(record.parameters[0]) + } + + // JSSE logs additional messages as parameters that are not referenced in the log message. + val parameter = parameters[0] as String - if (message == "Produced ClientHello handshake message") { - random = readClientRandom(parameter) + if (message == "Produced ClientHello handshake message") { + random = readClientRandom(parameter) + } } } - } - override fun flush() {} + override fun flush() {} - override fun close() {} - } + override fun close() {} + } private fun readClientRandom(param: String): String? { val matchResult = randomRegex.find(param) @@ -187,7 +191,7 @@ class WireSharkListenerFactory( override fun secureConnectEnd( call: Call, - handshake: Handshake? + handshake: Handshake?, ) { logger.removeHandler(loggerHandler) } @@ -199,13 +203,14 @@ class WireSharkListenerFactory( override fun connectionAcquired( call: Call, - connection: Connection + connection: Connection, ) { if (random != null) { val sslSocket = connection.socket() as SSLSocket val session = sslSocket.session - val masterSecretHex = session.masterSecret?.encoded?.toByteString() + val masterSecretHex = + session.masterSecret?.encoded?.toByteString() ?.hex() if (masterSecretHex != null) { @@ -222,7 +227,8 @@ class WireSharkListenerFactory( } enum class Launch { - Gui, CommandLine + Gui, + CommandLine, } } @@ -230,7 +236,8 @@ class WireSharkListenerFactory( private lateinit var logger: Logger private val SSLSession.masterSecret: SecretKey? - get() = javaClass.getDeclaredField("masterSecret") + get() = + javaClass.getDeclaredField("masterSecret") .apply { isAccessible = true } @@ -241,7 +248,8 @@ class WireSharkListenerFactory( fun register() { // Enable JUL logging for SSL events, must be activated early or via -D option. System.setProperty("javax.net.debug", "") - logger = Logger.getLogger("javax.net.ssl") + logger = + Logger.getLogger("javax.net.ssl") .apply { level = Level.FINEST useParentHandlers = false @@ -254,13 +262,18 @@ class WireSharkListenerFactory( class WiresharkExample(tlsVersions: List, private val launch: Launch? = null) { private val connectionSpec = ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS) - .tlsVersions(*tlsVersions.toTypedArray()) - .build() + .tlsVersions(*tlsVersions.toTypedArray()) + .build() - private val eventListenerFactory = WireSharkListenerFactory( - logFile = File("/tmp/key.log"), tlsVersions = tlsVersions, launch = launch) + private val eventListenerFactory = + WireSharkListenerFactory( + logFile = File("/tmp/key.log"), + tlsVersions = tlsVersions, + launch = launch, + ) - val client = OkHttpClient.Builder() + val client = + OkHttpClient.Builder() .connectionSpecs(listOf(connectionSpec)) .eventListenerFactory(eventListenerFactory) .build() @@ -269,13 +282,16 @@ class WiresharkExample(tlsVersions: List, private val launch: Launch // Launch wireshark in the background val process = eventListenerFactory.launchWireShark() - val fbRequest = Request.Builder() + val fbRequest = + Request.Builder() .url("https://graph.facebook.com/robots.txt?s=fb") .build() - val twitterRequest = Request.Builder() + val twitterRequest = + Request.Builder() .url("https://api.twitter.com/robots.txt?s=tw") .build() - val googleRequest = Request.Builder() + val googleRequest = + Request.Builder() .url("https://www.google.com/robots.txt?s=g") .build() @@ -306,16 +322,17 @@ class WiresharkExample(tlsVersions: List, private val launch: Launch } client.newCall(request) - .execute() - .use { - val firstLine = it.body.string() - .lines() - .first() - if (this.launch != CommandLine) { - println("${it.code} ${it.request.url.host} $firstLine") - } - Unit + .execute() + .use { + val firstLine = + it.body.string() + .lines() + .first() + if (this.launch != CommandLine) { + println("${it.code} ${it.request.url.host} $firstLine") } + Unit + } } catch (e: IOException) { System.err.println(e) } diff --git a/samples/guide/src/main/java/okhttp3/recipes/kt/YubikeyClientAuth.kt b/samples/guide/src/main/java/okhttp3/recipes/kt/YubikeyClientAuth.kt index 0411474d15a3..466e5d62922e 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/kt/YubikeyClientAuth.kt +++ b/samples/guide/src/main/java/okhttp3/recipes/kt/YubikeyClientAuth.kt @@ -14,6 +14,7 @@ * limitations under the License. */ @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "Since15") + package okhttp3.recipes.kt import java.io.IOException @@ -61,12 +62,12 @@ class YubikeyClientAuth { val callbackHandler = ConsoleCallbackHandler - val builderList: List = listOf( - KeyStore.Builder.newInstance("PKCS11", null, KeyStore.CallbackHandlerProtection(callbackHandler)) - - // Example if you want to combine multiple keystore types - // KeyStore.Builder.newInstance("PKCS12", null, File("keystore.p12"), PasswordProtection("rosebud".toCharArray())) - ) + val builderList: List = + listOf( + KeyStore.Builder.newInstance("PKCS11", null, KeyStore.CallbackHandlerProtection(callbackHandler)), + // Example if you want to combine multiple keystore types + // KeyStore.Builder.newInstance("PKCS12", null, File("keystore.p12"), PasswordProtection("rosebud".toCharArray())) + ) val keyManagerFactory = KeyManagerFactory.getInstance("NewSunX509") keyManagerFactory.init(KeyStoreBuilderParameters(builderList)) @@ -77,12 +78,14 @@ class YubikeyClientAuth { val sslContext = SSLContext.getInstance("TLS") sslContext.init(arrayOf(keyManager), arrayOf(trustManager), SecureRandom()) - val client = OkHttpClient.Builder() + val client = + OkHttpClient.Builder() .sslSocketFactory(sslContext.socketFactory, trustManager) .build() // An example test URL that returns client certificate details. - val request = Request.Builder() + val request = + Request.Builder() .url("https://prod.idrix.eu/secure/") .build() diff --git a/samples/guide/src/test/kotlin/okhttp3/AllMainsTest.kt b/samples/guide/src/test/kotlin/okhttp3/AllMainsTest.kt index f08e24e32fd6..4c0e5000ba53 100644 --- a/samples/guide/src/test/kotlin/okhttp3/AllMainsTest.kt +++ b/samples/guide/src/test/kotlin/okhttp3/AllMainsTest.kt @@ -15,21 +15,22 @@ */ package okhttp3 +import java.io.File +import java.lang.reflect.InvocationTargetException import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Tag import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ArgumentsSource -import java.io.File -import java.lang.reflect.InvocationTargetException private val prefix = if (File("samples").exists()) "" else "../../" private fun mainFiles(): List { - val directories = listOf( - "$prefix/samples/guide/src/main/java/okhttp3/guide", - "$prefix/samples/guide/src/main/java/okhttp3/recipes", - "$prefix/samples/guide/src/main/java/okhttp3/recipes/kt" - ).map { File(it) } + val directories = + listOf( + "$prefix/samples/guide/src/main/java/okhttp3/guide", + "$prefix/samples/guide/src/main/java/okhttp3/recipes", + "$prefix/samples/guide/src/main/java/okhttp3/recipes/kt", + ).map { File(it) } return directories.flatMap { it.listFiles().orEmpty().filter { f -> f.isFile }.toList() @@ -56,7 +57,8 @@ class AllMainsTest { @ParameterizedTest @ArgumentsSource(MainTestProvider::class) fun runMain(className: String) { - val mainMethod = Class.forName(className) + val mainMethod = + Class.forName(className) .methods.find { it.name == "main" } try { if (mainMethod != null) { @@ -78,7 +80,7 @@ class AllMainsTest { @Suppress("UNUSED_PARAMETER") private fun expectedFailure( className: String, - cause: Throwable + cause: Throwable, ): Boolean { return when (className) { "okhttp3.recipes.CheckHandshake" -> true // by design diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/CipherSuiteSurvey.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/CipherSuiteSurvey.kt index 7ed5a4b9ea2a..51d61995842b 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/CipherSuiteSurvey.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/CipherSuiteSurvey.kt @@ -25,9 +25,8 @@ import okhttp3.survey.types.SuiteId class CipherSuiteSurvey( val clients: List, val ianaSuites: IanaSuites, - val orderBy: List + val orderBy: List, ) { - fun printGoogleSheet() { print("name") for (client in clients) { @@ -35,10 +34,11 @@ class CipherSuiteSurvey( print(client.nameAndVersion) } println() - val sortedSuites = ianaSuites.suites.sortedBy { ianaSuite -> - val index = orderBy.indexOfFirst { it.matches(ianaSuite) } - if (index == -1) Integer.MAX_VALUE else index - } + val sortedSuites = + ianaSuites.suites.sortedBy { ianaSuite -> + val index = orderBy.indexOfFirst { it.matches(ianaSuite) } + if (index == -1) Integer.MAX_VALUE else index + } for (suiteId in sortedSuites) { print(suiteId.name) for (client in clients) { diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Clients.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Clients.kt index d39eb603b054..ea3140619270 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Clients.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Clients.kt @@ -27,26 +27,29 @@ import okio.Path.Companion.toPath import org.conscrypt.Conscrypt fun currentOkHttp(ianaSuites: IanaSuites): Client { - val supportedSuites = buildList { - for (suite in ConnectionSpec.COMPATIBLE_TLS.cipherSuites!!) { - add(ianaSuites.fromJavaName(suite.javaName)) + val supportedSuites = + buildList { + for (suite in ConnectionSpec.COMPATIBLE_TLS.cipherSuites!!) { + add(ianaSuites.fromJavaName(suite.javaName)) + } } - } - val enabledSuites = buildList { - for (suite in ConnectionSpec.MODERN_TLS.cipherSuites!!) { - add(ianaSuites.fromJavaName(suite.javaName)) + val enabledSuites = + buildList { + for (suite in ConnectionSpec.MODERN_TLS.cipherSuites!!) { + add(ianaSuites.fromJavaName(suite.javaName)) + } } - } return Client("OkHttp", OkHttp.VERSION, null, enabledSuites, supportedSuites) } fun historicOkHttp(version: String): Client { - val enabled = FileSystem.RESOURCES.read("okhttp_${version.replace(".", "_")}.txt".toPath()) { - this.readUtf8().lines().filter { it.isNotBlank() }.map { - SuiteId(null, it.trim()) + val enabled = + FileSystem.RESOURCES.read("okhttp_${version.replace(".", "_")}.txt".toPath()) { + this.readUtf8().lines().filter { it.isNotBlank() }.map { + SuiteId(null, it.trim()) + } } - } return Client("OkHttp", version, null, enabled = enabled) } @@ -59,20 +62,26 @@ fun conscrypt(ianaSuites: IanaSuites): Client { return systemDefault("Conscrypt", "" + version.major() + "." + version.minor(), ianaSuites) } -fun systemDefault(name: String, version: String, ianaSuites: IanaSuites): Client { +fun systemDefault( + name: String, + version: String, + ianaSuites: IanaSuites, +): Client { return try { val socketFactory = SSLSocketFactory.getDefault() as SSLSocketFactory val sslSocket = socketFactory.createSocket() as SSLSocket - val supportedSuites = buildList { - for (suite in sslSocket.supportedCipherSuites) { - add(ianaSuites.fromJavaName(suite)) + val supportedSuites = + buildList { + for (suite in sslSocket.supportedCipherSuites) { + add(ianaSuites.fromJavaName(suite)) + } } - } - val enabledSuites = buildList { - for (suite in sslSocket.enabledCipherSuites) { - add(ianaSuites.fromJavaName(suite)) + val enabledSuites = + buildList { + for (suite in sslSocket.enabledCipherSuites) { + add(ianaSuites.fromJavaName(suite)) + } } - } Client(name, version, null, enabledSuites, supportedSuites) } catch (e: IOException) { diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Iana.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Iana.kt index 25410bdff25b..2b774f5ee822 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Iana.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Iana.kt @@ -35,7 +35,8 @@ fun parseIanaCsvRow(s: String): SuiteId? { } class IanaSuites( - val name: String, val suites: List + val name: String, + val suites: List, ) { fun fromJavaName(javaName: String): SuiteId { for (suiteId in suites) { @@ -53,12 +54,13 @@ suspend fun fetchIanaSuites(okHttpClient: OkHttpClient): IanaSuites { val call = okHttpClient.newCall(Request(url.toHttpUrl())) - val suites = call.executeAsync().use { - if (!it.isSuccessful) { - throw IOException("Failed ${it.code} ${it.message}") - } - it.body.string().lines() - }.mapNotNull { parseIanaCsvRow(it) } + val suites = + call.executeAsync().use { + if (!it.isSuccessful) { + throw IOException("Failed ${it.code} ${it.message}") + } + it.body.string().lines() + }.mapNotNull { parseIanaCsvRow(it) } return IanaSuites("current", suites) } diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/RunSurvey.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/RunSurvey.kt index 8e01caecb7fe..ced4cf205029 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/RunSurvey.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/RunSurvey.kt @@ -29,9 +29,10 @@ import org.conscrypt.Conscrypt suspend fun main() { val includeConscrypt = false - val client = OkHttpClient.Builder() - .cache(Cache("build/okhttp_cache".toPath(), 100_000_000, FileSystem.SYSTEM)) - .build() + val client = + OkHttpClient.Builder() + .cache(Cache("build/okhttp_cache".toPath(), 100_000_000, FileSystem.SYSTEM)) + .build() val sslLabsScraper = SslLabsScraper(client) @@ -63,35 +64,37 @@ suspend fun main() { val currentVm = currentVm(ianaSuitesNew) - val conscrypt = if (includeConscrypt) { - Security.addProvider(Conscrypt.newProvider()) - conscrypt(ianaSuitesNew) - } else { - Client("Conscrypt", "Disabled", null, listOf()) - } + val conscrypt = + if (includeConscrypt) { + Security.addProvider(Conscrypt.newProvider()) + conscrypt(ianaSuitesNew) + } else { + Client("Conscrypt", "Disabled", null, listOf()) + } - val clients = listOf( - okhttp, - chrome80, - firefox73, - android9, - safari12iOS, - conscrypt, - currentVm, - okHttp_3_9, - okHttp_3_11, - okHttp_3_13, - okHttp_3_14, - okHttp_4_10, - android5, - java7, - java12, - firefox34, - firefox53, - chrome33, - chrome57, - safari12Osx - ) + val clients = + listOf( + okhttp, + chrome80, + firefox73, + android9, + safari12iOS, + conscrypt, + currentVm, + okHttp_3_9, + okHttp_3_11, + okHttp_3_13, + okHttp_3_14, + okHttp_4_10, + android5, + java7, + java12, + firefox34, + firefox53, + chrome33, + chrome57, + safari12Osx, + ) val orderBy = okhttp.enabled + chrome80.enabled + safari12Osx.enabled + rest(clients) val survey = CipherSuiteSurvey(clients = clients, ianaSuites = ianaSuitesNew, orderBy = orderBy) diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/SslLabsScrape.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/SslLabsScrape.kt index 11138f56aefe..7b7c0168c08b 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/SslLabsScrape.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/SslLabsScrape.kt @@ -18,7 +18,6 @@ package okhttp3.survey.ssllabs import com.squareup.moshi.Moshi import okhttp3.Call import okhttp3.OkHttpClient -import okhttp3.survey.ssllabs.SslLabsService import okhttp3.survey.types.Client import okhttp3.survey.types.SuiteId import retrofit2.Retrofit @@ -31,11 +30,12 @@ class SslLabsScraper( private val moshiConverterFactory = MoshiConverterFactory.create(moshi) - private val retrofit = Retrofit.Builder() - .baseUrl(SslLabsService.BASE_URL) - .addConverterFactory(moshiConverterFactory) - .callFactory(callFactory) - .build() + private val retrofit = + Retrofit.Builder() + .baseUrl(SslLabsService.BASE_URL) + .addConverterFactory(moshiConverterFactory) + .callFactory(callFactory) + .build() private val api = retrofit.create(SslLabsService::class.java) diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/SslLabsService.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/SslLabsService.kt index fdb513dbba09..4715de7e7800 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/SslLabsService.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/SslLabsService.kt @@ -3,10 +3,10 @@ package okhttp3.survey.ssllabs import retrofit2.http.GET interface SslLabsService { - @GET("getClients") - suspend fun clients(): List + @GET("getClients") + suspend fun clients(): List - companion object { - const val BASE_URL = "https://api.ssllabs.com/api/v3/" - } + companion object { + const val BASE_URL = "https://api.ssllabs.com/api/v3/" + } } diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/UserAgentCapabilities.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/UserAgentCapabilities.kt index 04802e149ba2..26f61e4a9b6f 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/UserAgentCapabilities.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/ssllabs/UserAgentCapabilities.kt @@ -2,36 +2,35 @@ package okhttp3.survey.ssllabs import com.squareup.moshi.JsonClass - @JsonClass(generateAdapter = true) class UserAgentCapabilities( - val abortsOnUnrecognizedName: Boolean, - val alpnProtocols: List, - val ellipticCurves: List, - val handshakeFormat: String, - val hexHandshakeBytes: String, - val highestProtocol: Int, - val id: Int, - val isGrade0: Boolean, - val lowestProtocol: Int, - val maxDhBits: Int, - val maxRsaBits: Int, - val minDhBits: Int, - val minEcdsaBits: Int, - val minRsaBits: Int, - val name: String, - val npnProtocols: List, - val platform: String?, - val requiresSha2: Boolean, - val signatureAlgorithms: List, - val suiteIds: List, - val suiteNames: List, - val supportsCompression: Boolean, - val supportsNpn: Boolean, - val supportsRi: Boolean, - val supportsSni: Boolean, - val supportsStapling: Boolean, - val supportsTickets: Boolean, - val userAgent: String?, - val version: String + val abortsOnUnrecognizedName: Boolean, + val alpnProtocols: List, + val ellipticCurves: List, + val handshakeFormat: String, + val hexHandshakeBytes: String, + val highestProtocol: Int, + val id: Int, + val isGrade0: Boolean, + val lowestProtocol: Int, + val maxDhBits: Int, + val maxRsaBits: Int, + val minDhBits: Int, + val minEcdsaBits: Int, + val minRsaBits: Int, + val name: String, + val npnProtocols: List, + val platform: String?, + val requiresSha2: Boolean, + val signatureAlgorithms: List, + val suiteIds: List, + val suiteNames: List, + val supportsCompression: Boolean, + val supportsNpn: Boolean, + val supportsRi: Boolean, + val supportsSni: Boolean, + val supportsStapling: Boolean, + val supportsTickets: Boolean, + val userAgent: String?, + val version: String, ) diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/types/Client.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/types/Client.kt index b2e3f43f2047..2e592b77dfa5 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/types/Client.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/types/Client.kt @@ -20,7 +20,7 @@ data class Client( val version: String, val platform: String?, val enabled: List = listOf(), - val supported: List = listOf() + val supported: List = listOf(), ) { val nameAndVersion: String get() = "$userAgent/$version" diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/types/Record.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/types/Record.kt index 5f82b12c9e48..af4f05f4dd2f 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/types/Record.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/types/Record.kt @@ -15,5 +15,4 @@ */ package okhttp3.survey.types - data class Record(val java: String, val android: String)