+doc #20192 explain need of draining entities in server/client HTTP (#20852)

* +doc #20192 explain need of draining entities in server/client HTTP

* missing javadsl for Connection header

* Update HttpClientExampleDocTest.java
This commit is contained in:
Konrad Malawski 2016-07-08 14:47:29 +02:00 committed by GitHub
parent 9683e4bc58
commit 60fb163331
20 changed files with 766 additions and 16 deletions

View file

@ -5,11 +5,13 @@
package docs.http.scaladsl
import akka.event.LoggingAdapter
import akka.http.scaladsl.model.{ RequestEntity, StatusCodes }
import akka.stream.scaladsl.Sink
import akka.testkit.TestActors
import docs.CompileOnlySpec
import org.scalatest.{ Matchers, WordSpec }
import scala.language.postfixOps
import scala.language.postfixOps
import scala.concurrent.{ ExecutionContext, Future }
class HttpServerExampleSpec extends WordSpec with Matchers
@ -159,7 +161,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers
val httpEcho = Flow[HttpRequest]
.via(reactToConnectionFailure)
.map { request =>
// simple text "echo" response:
// simple streaming (!) "echo" response:
HttpResponse(entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, request.entity.dataBytes))
}
@ -195,7 +197,8 @@ class HttpServerExampleSpec extends WordSpec with Matchers
case HttpRequest(GET, Uri.Path("/crash"), _, _, _) =>
sys.error("BOOM!")
case _: HttpRequest =>
case r: HttpRequest =>
r.discardEntityBytes() // important to drain incoming HTTP Entity stream
HttpResponse(404, entity = "Unknown resource!")
}
@ -237,7 +240,8 @@ class HttpServerExampleSpec extends WordSpec with Matchers
case HttpRequest(GET, Uri.Path("/crash"), _, _, _) =>
sys.error("BOOM!")
case _: HttpRequest =>
case r: HttpRequest =>
r.discardEntityBytes() // important to drain incoming HTTP Entity stream
HttpResponse(404, entity = "Unknown resource!")
}
@ -553,6 +557,126 @@ class HttpServerExampleSpec extends WordSpec with Matchers
}
//#actor-interaction
}
"consume entity using entity directive" in compileOnlySpec {
//#consume-entity-directive
import akka.actor.ActorSystem
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.stream.ActorMaterializer
import spray.json.DefaultJsonProtocol._
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext = system.dispatcher
final case class Bid(userId: String, bid: Int)
// these are from spray-json
implicit val bidFormat = jsonFormat2(Bid)
val route =
path("bid") {
put {
entity(as[Bid]) { bid =>
// incoming entity is fully consumed and converted into a Bid
complete("The bid was: " + bid)
}
}
}
//#consume-entity-directive
}
"consume entity using raw dataBytes to file" in compileOnlySpec {
//#consume-raw-dataBytes
import akka.actor.ActorSystem
import akka.stream.scaladsl.FileIO
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import java.io.File
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext = system.dispatcher
val route =
(put & path("lines")) {
withoutSizeLimit {
extractDataBytes { bytes =>
val finishedWriting = bytes.runWith(FileIO.toPath(new File("/tmp/example.out").toPath))
// we only want to respond once the incoming data has been handled:
onComplete(finishedWriting) { ioResult =>
complete("Finished writing data: " + ioResult)
}
}
}
}
//#consume-raw-dataBytes
}
"drain entity using request#discardEntityBytes" in compileOnlySpec {
//#discard-discardEntityBytes
import akka.actor.ActorSystem
import akka.stream.scaladsl.FileIO
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import akka.http.scaladsl.model.HttpRequest
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext = system.dispatcher
val route =
(put & path("lines")) {
withoutSizeLimit {
extractRequest { r: HttpRequest =>
val finishedWriting = r.discardEntityBytes().future
// we only want to respond once the incoming data has been handled:
onComplete(finishedWriting) { done =>
complete("Drained all data from connection... (" + done + ")")
}
}
}
}
//#discard-discardEntityBytes
}
"discard entity manually" in compileOnlySpec {
//#discard-close-connections
import akka.actor.ActorSystem
import akka.stream.scaladsl.Sink
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.model.headers.Connection
import akka.stream.ActorMaterializer
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext = system.dispatcher
val route =
(put & path("lines")) {
withoutSizeLimit {
extractDataBytes { data =>
// Closing connections, method 1 (eager):
// we deem this request as illegal, and close the connection right away:
data.runWith(Sink.cancelled) // "brutally" closes the connection
// Closing connections, method 2 (graceful):
// consider draining connection and replying with `Connection: Close` header
// if you want the client to close after this request/reply cycle instead:
respondWithHeader(Connection("close"))
complete(StatusCodes.Forbidden -> "Not allowed!")
}
}
}
//#discard-close-connections
}
}