=htc #17348 don't render extra LastChunk at the and of Chunked entity

This commit is contained in:
Johannes Rudolph 2015-05-04 10:17:35 +02:00
parent 9125a719fe
commit 2bb7e029ef
4 changed files with 80 additions and 9 deletions

View file

@ -57,19 +57,15 @@ private object RenderSupport {
}
class ChunkTransformer extends StatefulStage[HttpEntity.ChunkStreamPart, ByteString] {
var lastChunkSeen = false
override def initial = new State {
override def onPush(chunk: HttpEntity.ChunkStreamPart, ctx: Context[ByteString]): SyncDirective = {
if (chunk.isLastChunk)
lastChunkSeen = true
ctx.push(renderChunk(chunk))
val bytes = renderChunk(chunk)
if (chunk.isLastChunk) ctx.pushAndFinish(bytes)
else ctx.push(bytes)
}
}
override def onUpstreamFinish(ctx: Context[ByteString]): TerminationDirective =
if (lastChunkSeen) super.onUpstreamFinish(ctx)
else terminationEmit(Iterator.single(defaultLastChunkBytes), ctx)
terminationEmit(Iterator.single(defaultLastChunkBytes), ctx)
}
object CheckContentLengthTransformer {

View file

@ -150,6 +150,57 @@ class RequestRendererSpec extends FreeSpec with Matchers with BeforeAndAfterAll
}
}
"POST request with chunked body and explicit LastChunk" in new TestSetup() {
val chunks =
List(
ChunkStreamPart("XXXX"),
ChunkStreamPart("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
LastChunk)
HttpRequest(POST, "/abc/xyz", entity = Chunked(ContentTypes.`text/plain`,
Source(chunks))) should renderTo {
"""POST /abc/xyz HTTP/1.1
|Host: test.com:8080
|User-Agent: spray-can/1.0.0
|Transfer-Encoding: chunked
|Content-Type: text/plain
|
|4
|XXXX
|1a
|ABCDEFGHIJKLMNOPQRSTUVWXYZ
|0
|
|"""
}
}
"POST request with chunked body and extra LastChunks at the end (which should be ignored)" in new TestSetup() {
val chunks =
List(
ChunkStreamPart("XXXX"),
ChunkStreamPart("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
LastChunk,
LastChunk)
HttpRequest(POST, "/abc/xyz", entity = Chunked(ContentTypes.`text/plain`,
Source(chunks))) should renderTo {
"""POST /abc/xyz HTTP/1.1
|Host: test.com:8080
|User-Agent: spray-can/1.0.0
|Transfer-Encoding: chunked
|Content-Type: text/plain
|
|4
|XXXX
|1a
|ABCDEFGHIJKLMNOPQRSTUVWXYZ
|0
|
|"""
}
}
"POST request with custom Transfer-Encoding header" in new TestSetup() {
HttpRequest(POST, "/abc/xyz", List(`Transfer-Encoding`(TransferEncodings.Extension("fancy"))),
entity = Chunked(ContentTypes.`text/plain`, source("XXXX", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))) should renderTo {

View file

@ -286,7 +286,27 @@ class ResponseRendererSpec extends FreeSpec with Matchers with BeforeAndAfterAll
"with one chunk and an explicit LastChunk" in new TestSetup() {
HttpResponse(entity = Chunked(ContentTypes.`text/plain(UTF-8)`,
source(Chunk(ByteString("body123"), """key=value;another="tl;dr""""),
LastChunk("foo=bar", List(Age(30), RawHeader("Cache-Control", "public")))))) should renderTo {
LastChunk("foo=bar", List(Age(30), RawHeader("Cache-Control", "public")))).via(printEvent("source")))) should renderTo {
"""HTTP/1.1 200 OK
|Server: akka-http/1.0.0
|Date: Thu, 25 Aug 2011 09:10:29 GMT
|Transfer-Encoding: chunked
|Content-Type: text/plain; charset=UTF-8
|
|7;key=value;another="tl;dr"
|body123
|0;foo=bar
|Age: 30
|Cache-Control: public
|
|"""
}
}
"with one chunk and and extra LastChunks at the end (which should be ignored)" in new TestSetup() {
HttpResponse(entity = Chunked(ContentTypes.`text/plain(UTF-8)`,
source(Chunk(ByteString("body123"), """key=value;another="tl;dr""""),
LastChunk("foo=bar", List(Age(30), RawHeader("Cache-Control", "public"))), LastChunk))) should renderTo {
"""HTTP/1.1 200 OK
|Server: akka-http/1.0.0
|Date: Thu, 25 Aug 2011 09:10:29 GMT

View file

@ -98,6 +98,10 @@ class HttpEntitySpec extends FreeSpec with MustMatchers with BeforeAndAfterAll {
Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)) must
transformTo(Strict(tpe, doubleChars("abcfghijk") ++ trailer))
}
"Chunked with extra LastChunk" in {
Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk, LastChunk)) must
transformTo(Strict(tpe, doubleChars("abcfghijk") ++ trailer))
}
}
}