@@ -219,5 +219,60 @@ class TLSSocketSuite extends TLSSuite {
219
219
.to(Chunk )
220
220
.assertEquals(msg)
221
221
}
222
+
223
+ test(" endOfOutput during handshake results in termination" ) {
224
+ val msg = Chunk .array((" Hello, world! " * 20000 ).getBytes)
225
+
226
+ def limitWrites (raw : Socket [IO ], limit : Int ): Socket [IO ] = new Socket [IO ] {
227
+ def endOfInput = raw.endOfInput
228
+ def endOfOutput = raw.endOfOutput
229
+ def isOpen = raw.isOpen
230
+ def localAddress = raw.localAddress
231
+ def read (maxBytes : Int ) = raw.read(maxBytes)
232
+ def readN (numBytes : Int ) = raw.readN(numBytes)
233
+ def reads = raw.reads
234
+ def remoteAddress = raw.remoteAddress
235
+ def writes = raw.writes
236
+
237
+ private var totalWritten : Int = 0
238
+ def write (bytes : Chunk [Byte ]) =
239
+ if (totalWritten >= limit) endOfOutput
240
+ else {
241
+ val b = bytes.take(limit - totalWritten)
242
+ raw.write(b) >> IO (totalWritten += b.size) >> IO (totalWritten >= limit)
243
+ .ifM(endOfOutput, IO .unit)
244
+ }
245
+ }
246
+
247
+ // Setup an HTTPS echo server & a client that starts a TLS handshake but only sends the first few bytes and then signals no more output
248
+ // Doing so should not cause the server to peg a CPU
249
+ val setup = for {
250
+ tlsContext <- Resource .eval(testTlsContext)
251
+ addressAndConnections <- Network [IO ].serverResource(Some (ip " 127.0.0.1 " ))
252
+ (serverAddress, server) = addressAndConnections
253
+ echoServer =
254
+ server
255
+ .flatMap(s => Stream .resource(tlsContext.serverBuilder(s).withLogger(logger).build))
256
+ .map { socket =>
257
+ socket.reads.chunks.foreach(socket.write)
258
+ }
259
+ .parJoinUnbounded
260
+ client <- Network [IO ].client(serverAddress).flatMap { rawClient =>
261
+ tlsContext.client(limitWrites(rawClient, 10 ))
262
+ }
263
+ } yield echoServer -> client
264
+
265
+ Stream
266
+ .resource(setup)
267
+ .flatMap { case (echoServer, clientSocket) =>
268
+ val client =
269
+ Stream .exec(clientSocket.write(msg)).onFinalize(clientSocket.endOfOutput) ++
270
+ clientSocket.reads.take(msg.size.toLong)
271
+
272
+ client.concurrently(echoServer)
273
+ }
274
+ .compile
275
+ .drain
276
+ }
222
277
}
223
278
}
0 commit comments