-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CIO server HTTPS support on JVM #2929
base: main
Are you sure you want to change the base?
Conversation
TODO: test failed - HttpServerCommonTestSuite.testProxyHeaders
ktor-network/ktor-network-tls/jvm/src/io/ktor/network/tls/SSLEngineSocket.kt
Show resolved
Hide resolved
ktor-network/ktor-network-tls/jvm/src/io/ktor/network/tls/SSLEngineUnwrapper.kt
Show resolved
Hide resolved
d084312
to
1ae2c1f
Compare
Please change the target branch to 2.1 |
@@ -145,7 +145,7 @@ public class CIOApplicationEngine( | |||
|
|||
try { | |||
environment.connectors.forEach { connectorSpec -> | |||
if (connectorSpec.type == ConnectorType.HTTPS) { | |||
if (connectorSpec.type == ConnectorType.HTTPS && !PlatformUtils.IS_JVM) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would extract a condition to check if the platform supports tls
@@ -50,3 +51,8 @@ public suspend fun Socket.tls( | |||
*/ | |||
public actual suspend fun Socket.tls(coroutineContext: CoroutineContext, block: TLSConfigBuilder.() -> Unit): Socket = | |||
tls(coroutineContext, TLSConfigBuilder().apply(block).build()) | |||
|
|||
@InternalAPI | |||
public fun Socket.tls(coroutineContext: CoroutineContext, engine: SSLEngine): Socket { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add KDoc
private val wrapLock = Mutex() | ||
private var wrapDestination = bufferAllocator.allocatePacket(0) | ||
|
||
suspend fun wrapAndWrite(wrapSource: ByteBuffer): SSLEngineResult = wrapLock.withLock { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you tell me why do we need a lock here?
} | ||
|
||
@Suppress("BlockingMethodInNonBlockingContext") | ||
private suspend fun wrapAndWriteX(wrapSource: ByteBuffer): SSLEngineResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrapAndWriteSuspend
return result | ||
} | ||
|
||
suspend fun close(cause: Throwable?): SSLEngineResult = wrapLock.withLock { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suspend close is not a good idea, I would try avoiding this
} | ||
val reader = socket.openReadChannel() | ||
repeat(3) { | ||
println("CCC: ${assertNotNull(reader.readUTF8Line())}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please drop printlns
while (true) { | ||
when (status) { | ||
SSLEngineResult.HandshakeStatus.NEED_TASK -> { | ||
coroutineScope { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
coroutineScope will create a new job for every NEED_TASK
status.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can remove this, but delegatedTask
is potentially blocking task, and then, we should make sure, that when creating TLS socket, we don't provide Dispatchers.Default or other non IO dispatcher to it constructor.
coroutineScope { | ||
while (true) { | ||
val task = engine.delegatedTask ?: break | ||
launch(Dispatchers.IO) { task.run() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
} | ||
|
||
private suspend fun doClose(cause: Throwable?) = lock.withLock { | ||
if (closed.compareAndSet(expect = false, update = true)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!closed.compareAndSet(expect = false, update = true)) return
buffer: ByteBuffer, | ||
flip: Boolean, | ||
allocate: (length: Int) -> ByteBuffer | ||
): ByteBuffer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we just make large enough buffers upfront and use a regular pool? the maximum packet size is limited by the protocol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sslengine max buffer size is 16K, and we need up to 4 such buffers for every TLS socket implementation, so 64K per socket.
For client side - it's ok, as there will not so much active sockets at the same time, but for server side it can cause memory issues with a lot of clients.
Note: most of the time, those 16K are not fully used, and buffer of smaller size is enough to perform TLS operations
Subsystem
Server, CIO, Network
Motivation
Fixes https://youtrack.jetbrains.com/issue/KTOR-694
Solution
Sses JDK SSLEngine for TLS implementation
Also, supports client TLS, but not used for now
TODO: