=str #19293 fix issues in Sink.seq + minor doc fixes + use Sink.seq and limit in tests where appropriate

* Sink.seq (Scala DSL) now returns immutable.Seq rather than Seq
* Sink.seq will not silently truncate when incoming elements is > Int.MAX_VALUE
* minor doc fixes
* replacing various grouped(n) / Sink.head with limit(n) / Sink.seq in various tests
* fix inconsistent indentation in RequestParserSpec
This commit is contained in:
lolski 2016-02-12 01:36:21 +08:00
parent f042204d8b
commit 21381d5710
46 changed files with 330 additions and 217 deletions

View file

@ -252,7 +252,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
val parser = newParser
val result = multiParse(newParser)(Seq(prep(start + manyChunks)))
val HttpEntity.Chunked(_, chunks) = result.head.right.get.req.entity
val strictChunks = chunks.grouped(100000).runWith(Sink.head).awaitResult(awaitAtMost)
val strictChunks = chunks.limit(100000).runWith(Sink.seq).awaitResult(awaitAtMost)
strictChunks.size shouldEqual numChunks
}
}
@ -322,7 +322,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
"too-large chunk size" in new Test {
Seq(start,
"""1a2b3c4d5e
|""") should generalMultiParseTo(Right(baseRequest),
|""") should generalMultiParseTo(Right(baseRequest),
Left(EntityStreamError(ErrorInfo("HTTP chunk size exceeds the configured limit of 1048576 bytes"))))
closeAfterResponseCompletion shouldEqual Seq(false)
}
@ -360,10 +360,10 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
"two Content-Length headers" in new Test {
"""GET / HTTP/1.1
|Content-Length: 3
|Content-Length: 4
|
|foo""" should parseToError(BadRequest,
|Content-Length: 3
|Content-Length: 4
|
|foo""" should parseToError(BadRequest,
ErrorInfo("HTTP message must not contain more than one Content-Length header"))
}
@ -374,63 +374,63 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
"HTTP version 1.2" in new Test {
"""GET / HTTP/1.2
|""" should parseToError(HTTPVersionNotSupported,
|""" should parseToError(HTTPVersionNotSupported,
ErrorInfo("The server does not support the HTTP protocol version used in the request."))
}
"with an illegal char in a header name" in new Test {
"""GET / HTTP/1.1
|User@Agent: curl/7.19.7""" should parseToError(BadRequest, ErrorInfo("Illegal character '@' in header name"))
|User@Agent: curl/7.19.7""" should parseToError(BadRequest, ErrorInfo("Illegal character '@' in header name"))
}
"with a too-long header name" in new Test {
"""|GET / HTTP/1.1
|UserxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAgent: curl/7.19.7""" should parseToError(
|UserxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAgent: curl/7.19.7""" should parseToError(
BadRequest, ErrorInfo("HTTP header name exceeds the configured limit of 64 characters"))
}
"with a too-long header-value" in new Test {
"""|GET / HTTP/1.1
|Fancy: 123456789012345678901234567890123""" should parseToError(BadRequest,
|Fancy: 123456789012345678901234567890123""" should parseToError(BadRequest,
ErrorInfo("HTTP header value exceeds the configured limit of 32 characters"))
}
"with an invalid Content-Length header value" in new Test {
"""GET / HTTP/1.0
|Content-Length: 1.5
|
|abc""" should parseToError(BadRequest, ErrorInfo("Illegal `Content-Length` header value"))
|Content-Length: 1.5
|
|abc""" should parseToError(BadRequest, ErrorInfo("Illegal `Content-Length` header value"))
}
"with Content-Length > Long.MaxSize" in new Test {
// content-length = (Long.MaxValue + 1) * 10, which is 0 when calculated overflow
"""PUT /resource/yes HTTP/1.1
|Content-length: 92233720368547758080
|Host: x
|
|""" should parseToError(400: StatusCode, ErrorInfo("`Content-Length` header value must not exceed 63-bit integer range"))
|Content-length: 92233720368547758080
|Host: x
|
|""" should parseToError(400: StatusCode, ErrorInfo("`Content-Length` header value must not exceed 63-bit integer range"))
}
"with an illegal entity using CONNECT" in new Test {
"""CONNECT /resource/yes HTTP/1.1
|Transfer-Encoding: chunked
|Host: x
|
|""" should parseToError(422: StatusCode, ErrorInfo("CONNECT requests must not have an entity"))
|Transfer-Encoding: chunked
|Host: x
|
|""" should parseToError(422: StatusCode, ErrorInfo("CONNECT requests must not have an entity"))
}
"with an illegal entity using HEAD" in new Test {
"""HEAD /resource/yes HTTP/1.1
|Content-length: 3
|Host: x
|
|foo""" should parseToError(422: StatusCode, ErrorInfo("HEAD requests must not have an entity"))
|Content-length: 3
|Host: x
|
|foo""" should parseToError(422: StatusCode, ErrorInfo("HEAD requests must not have an entity"))
}
"with an illegal entity using TRACE" in new Test {
"""TRACE /resource/yes HTTP/1.1
|Transfer-Encoding: chunked
|Host: x
|
|""" should parseToError(422: StatusCode, ErrorInfo("TRACE requests must not have an entity"))
|Transfer-Encoding: chunked
|Host: x
|
|""" should parseToError(422: StatusCode, ErrorInfo("TRACE requests must not have an entity"))
}
}
}
@ -504,7 +504,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
}
}
.map(strictEqualify)
.grouped(100000).runWith(Sink.head)
.limit(100000).runWith(Sink.seq)
.awaitResult(awaitAtMost)
protected def parserSettings: ParserSettings = ParserSettings(system)
@ -517,7 +517,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
}
private def compactEntityChunks(data: Source[ChunkStreamPart, Any]): Future[Seq[ChunkStreamPart]] =
data.grouped(100000).runWith(Sink.head)
data.limit(100000).runWith(Sink.seq)
.fast.recover { case _: NoSuchElementException Nil }
def prep(response: String) = response.stripMarginWithNewline("\r\n")

View file

@ -306,7 +306,7 @@ class ResponseParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
}.concatSubstreams
def collectBlocking[T](source: Source[T, Any]): Seq[T] =
Await.result(source.grouped(100000).runWith(Sink.head), 500.millis)
Await.result(source.limit(100000).runWith(Sink.seq), 500.millis)
protected def parserSettings: ParserSettings = ParserSettings(system)
@ -323,7 +323,7 @@ class ResponseParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
}
private def compactEntityChunks(data: Source[ChunkStreamPart, Any]): Future[Source[ChunkStreamPart, Any]] =
data.grouped(100000).runWith(Sink.head)
data.limit(100000).runWith(Sink.seq)
.fast.map(source(_: _*))
.fast.recover { case _: NoSuchElementException source() }

View file

@ -325,7 +325,7 @@ class RequestRendererSpec extends FreeSpec with Matchers with BeforeAndAfterAll
def renderTo(expected: String): Matcher[HttpRequest] =
equal(expected.stripMarginWithNewline("\r\n")).matcher[String] compose { request
val byteStringSource = renderToSource(RequestRenderingContext(request, Host(serverAddress)))
val future = byteStringSource.grouped(1000).runWith(Sink.head).map(_.reduceLeft(_ ++ _).utf8String)
val future = byteStringSource.limit(1000).runWith(Sink.seq).map(_.reduceLeft(_ ++ _).utf8String)
Await.result(future, 250.millis)
}
}

View file

@ -394,7 +394,7 @@ class ClientServerSpec extends WordSpec with Matchers with BeforeAndAfterAll wit
private val HttpRequest(POST, uri, List(Accept(Seq(MediaRanges.`*/*`)), Host(_, _), `User-Agent`(_)),
Chunked(`chunkedContentType`, chunkStream), HttpProtocols.`HTTP/1.1`) = serverIn.expectNext()
uri shouldEqual Uri(s"http://$hostname:$port/chunked")
Await.result(chunkStream.grouped(5).runWith(Sink.head), 100.millis) shouldEqual chunks
Await.result(chunkStream.limit(5).runWith(Sink.seq), 100.millis) shouldEqual chunks
val serverOutSub = serverOut.expectSubscription()
serverOutSub.expectRequest()
@ -404,7 +404,7 @@ class ClientServerSpec extends WordSpec with Matchers with BeforeAndAfterAll wit
clientInSub.request(1)
val HttpResponse(StatusCodes.PartialContent, List(Age(42), Server(_), Date(_)),
Chunked(`chunkedContentType`, chunkStream2), HttpProtocols.`HTTP/1.1`) = clientIn.expectNext()
Await.result(chunkStream2.grouped(1000).runWith(Sink.head), 100.millis) shouldEqual chunks
Await.result(chunkStream2.limit(1000).runWith(Sink.seq), 100.millis) shouldEqual chunks
clientOutSub.sendComplete()
serverInSub.request(1)

View file

@ -155,7 +155,7 @@ class HttpEntitySpec extends FreeSpec with MustMatchers with BeforeAndAfterAll {
def collectBytesTo(bytes: ByteString*): Matcher[HttpEntity] =
equal(bytes.toVector).matcher[Seq[ByteString]].compose { entity
val future = entity.dataBytes.grouped(1000).runWith(Sink.head)
val future = entity.dataBytes.limit(1000).runWith(Sink.seq)
Await.result(future, 250.millis)
}