=htc #17348 don't render extra LastChunk at the and of Chunked entity
This commit is contained in:
parent
9125a719fe
commit
2bb7e029ef
4 changed files with 80 additions and 9 deletions
|
|
@ -57,19 +57,15 @@ private object RenderSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChunkTransformer extends StatefulStage[HttpEntity.ChunkStreamPart, ByteString] {
|
class ChunkTransformer extends StatefulStage[HttpEntity.ChunkStreamPart, ByteString] {
|
||||||
var lastChunkSeen = false
|
|
||||||
|
|
||||||
override def initial = new State {
|
override def initial = new State {
|
||||||
override def onPush(chunk: HttpEntity.ChunkStreamPart, ctx: Context[ByteString]): SyncDirective = {
|
override def onPush(chunk: HttpEntity.ChunkStreamPart, ctx: Context[ByteString]): SyncDirective = {
|
||||||
if (chunk.isLastChunk)
|
val bytes = renderChunk(chunk)
|
||||||
lastChunkSeen = true
|
if (chunk.isLastChunk) ctx.pushAndFinish(bytes)
|
||||||
ctx.push(renderChunk(chunk))
|
else ctx.push(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onUpstreamFinish(ctx: Context[ByteString]): TerminationDirective =
|
override def onUpstreamFinish(ctx: Context[ByteString]): TerminationDirective =
|
||||||
if (lastChunkSeen) super.onUpstreamFinish(ctx)
|
terminationEmit(Iterator.single(defaultLastChunkBytes), ctx)
|
||||||
else terminationEmit(Iterator.single(defaultLastChunkBytes), ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object CheckContentLengthTransformer {
|
object CheckContentLengthTransformer {
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
"POST request with custom Transfer-Encoding header" in new TestSetup() {
|
||||||
HttpRequest(POST, "/abc/xyz", List(`Transfer-Encoding`(TransferEncodings.Extension("fancy"))),
|
HttpRequest(POST, "/abc/xyz", List(`Transfer-Encoding`(TransferEncodings.Extension("fancy"))),
|
||||||
entity = Chunked(ContentTypes.`text/plain`, source("XXXX", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))) should renderTo {
|
entity = Chunked(ContentTypes.`text/plain`, source("XXXX", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))) should renderTo {
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,27 @@ class ResponseRendererSpec extends FreeSpec with Matchers with BeforeAndAfterAll
|
||||||
"with one chunk and an explicit LastChunk" in new TestSetup() {
|
"with one chunk and an explicit LastChunk" in new TestSetup() {
|
||||||
HttpResponse(entity = Chunked(ContentTypes.`text/plain(UTF-8)`,
|
HttpResponse(entity = Chunked(ContentTypes.`text/plain(UTF-8)`,
|
||||||
source(Chunk(ByteString("body123"), """key=value;another="tl;dr""""),
|
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
|
"""HTTP/1.1 200 OK
|
||||||
|Server: akka-http/1.0.0
|
|Server: akka-http/1.0.0
|
||||||
|Date: Thu, 25 Aug 2011 09:10:29 GMT
|
|Date: Thu, 25 Aug 2011 09:10:29 GMT
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,10 @@ class HttpEntitySpec extends FreeSpec with MustMatchers with BeforeAndAfterAll {
|
||||||
Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)) must
|
Chunked(tpe, source(Chunk(abc), Chunk(fgh), Chunk(ijk), LastChunk)) must
|
||||||
transformTo(Strict(tpe, doubleChars("abcfghijk") ++ trailer))
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue