=htc fix WS masking for empty frames on client side

This commit is contained in:
Johannes Rudolph 2015-10-06 14:37:06 +02:00
parent 5e0caf8fe1
commit 4cbbb7dbad
2 changed files with 46 additions and 8 deletions

View file

@ -51,12 +51,9 @@ private[http] object Masking {
def onPush(part: FrameEvent, ctx: Context[FrameEvent]): SyncDirective =
part match {
case start @ FrameStart(header, data)
if (header.length == 0) ctx.push(part)
else {
val mask = extractMask(header)
become(new Running(mask))
current.onPush(start.copy(header = setNewMask(header, mask)), ctx)
}
val mask = extractMask(header)
become(new Running(mask))
current.onPush(start.copy(header = setNewMask(header, mask)), ctx)
case _: FrameData
ctx.fail(new IllegalStateException("unexpected FrameData (need FrameStart first)"))
}

View file

@ -134,6 +134,13 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec {
sub.expectNext(ByteString("def", "ASCII"))
sub.expectComplete()
}
"unmask masked input on the server side for empty frame" in new ServerTestSetup {
val mask = Random.nextInt()
val header = frameHeader(Opcode.Binary, 0, fin = true, mask = Some(mask))
pushInput(header)
expectBinaryMessage(BinaryMessage.Strict(ByteString.empty))
}
}
"for text messages" - {
"empty message" in new ClientTestSetup {
@ -207,6 +214,13 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec {
sub.expectNext(ByteString("cdef€", "UTF-8"))
sub.expectComplete()
}
"unmask masked input on the server side for empty frame" in new ServerTestSetup {
val mask = Random.nextInt()
val header = frameHeader(Opcode.Text, 0, fin = true, mask = Some(mask))
pushInput(header)
expectTextMessage(TextMessage.Strict(""))
}
}
}
"render frames from messages" - {
@ -265,6 +279,10 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec {
sub.sendComplete()
expectFrameOnNetwork(Opcode.Continuation, ByteString.empty, fin = true)
}
"and mask input on the client side for empty frame" in new ClientTestSetup {
pushMessage(BinaryMessage(ByteString.empty))
expectMaskedFrameOnNetwork(Opcode.Binary, ByteString.empty, fin = true)
}
}
"for text messages" - {
"for a short strict message" in new ServerTestSetup {
@ -347,6 +365,10 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec {
sub.sendComplete()
expectFrameOnNetwork(Opcode.Continuation, ByteString.empty, fin = true)
}
"and mask input on the client side for empty frame" in new ClientTestSetup {
pushMessage(TextMessage(""))
expectMaskedFrameOnNetwork(Opcode.Text, ByteString.empty, fin = true)
}
}
}
"supply automatic low-level websocket behavior" - {
@ -440,7 +462,7 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec {
}
"after receiving close frame without close code" in new ServerTestSetup {
netInSub.expectRequest()
pushInput(frameHeader(Opcode.Close, 0, fin = true))
pushInput(frameHeader(Opcode.Close, 0, fin = true, mask = Some(Random.nextInt())))
messageIn.expectComplete()
messageOutSub.sendComplete()
@ -479,7 +501,7 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec {
netOutSub.request(10)
messageInSub.request(10)
pushInput(frameHeader(Protocol.Opcode.Binary, 0, fin = false))
pushInput(frameHeader(Protocol.Opcode.Binary, 0, fin = false, mask = Some(Random.nextInt())))
val dataSource = expectBinaryMessage().dataStream
val inSubscriber = TestSubscriber.manualProbe[ByteString]()
dataSource.runWith(Sink(inSubscriber))
@ -742,10 +764,23 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec {
pushInput(input)
expectProtocolErrorOnNetwork()
}
"unmasked input on the server side for empty frame" in new ServerTestSetup {
val input = frameHeader(Opcode.Binary, 0, fin = true)
pushInput(input)
expectProtocolErrorOnNetwork()
}
"masked input on the client side" in new ClientTestSetup {
val mask = Random.nextInt()
val input = frameHeader(Opcode.Binary, 6, fin = true, mask = Some(mask)) ++ maskedASCII("abcdef", mask)._1
pushInput(input)
expectProtocolErrorOnNetwork()
}
"masked input on the client side for empty frame" in new ClientTestSetup {
val mask = Random.nextInt()
val input = frameHeader(Opcode.Binary, 0, fin = true, mask = Some(mask))
pushInput(input)
expectProtocolErrorOnNetwork()
}
@ -813,9 +848,15 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec {
def expectBinaryMessage(): BinaryMessage =
expectMessage().asInstanceOf[BinaryMessage]
def expectBinaryMessage(message: BinaryMessage): Unit =
expectBinaryMessage() shouldEqual message
def expectTextMessage(): TextMessage =
expectMessage().asInstanceOf[TextMessage]
def expectTextMessage(message: TextMessage): Unit =
expectTextMessage() shouldEqual message
var inBuffer = ByteString.empty
@tailrec final def expectNetworkData(bytes: Int): ByteString =
if (inBuffer.size >= bytes) {