=htc #17664 create Multipart.toEntity to simplify creation of multipart/formdata requests

This moves some functionality from marshallers in akka-http
directly to akka-http-core.
This commit is contained in:
Johannes Rudolph 2015-06-18 15:05:14 +02:00
parent b4272b77c2
commit e9674d3ff0
3 changed files with 54 additions and 25 deletions

View file

@ -5,6 +5,8 @@
package akka.http.impl.engine.rendering
import java.nio.charset.Charset
import akka.parboiled2.util.Base64
import scala.collection.immutable
import akka.event.LoggingAdapter
import akka.http.scaladsl.model._
@ -16,6 +18,8 @@ import akka.stream.stage._
import akka.util.ByteString
import HttpEntity._
import scala.concurrent.forkjoin.ThreadLocalRandom
/**
* INTERNAL API
*/
@ -110,4 +114,13 @@ private[http] object BodyPartRenderer {
case x r ~~ x ~~ CrLf
}
/**
* Creates a new random number of the given length and base64 encodes it (using a custom "safe" alphabet).
*/
def randomBoundary(length: Int = 18, random: java.util.Random = ThreadLocalRandom.current()): String = {
val array = new Array[Byte](length)
random.nextBytes(array)
Base64.custom.encodeToString(array, false)
}
}

View file

@ -4,15 +4,18 @@
package akka.http.scaladsl.model
import akka.event.{ NoLogging, LoggingAdapter }
import scala.collection.immutable.VectorBuilder
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.{ Future, ExecutionContext }
import scala.collection.immutable
import scala.util.{ Failure, Success, Try }
import akka.stream.FlowMaterializer
import akka.stream.scaladsl.Source
import akka.stream.scaladsl.{ FlattenStrategy, Source }
import akka.http.scaladsl.util.FastFuture
import akka.http.scaladsl.model.headers._
import akka.http.impl.engine.rendering.BodyPartRenderer
import FastFuture._
trait Multipart {
@ -25,12 +28,29 @@ trait Multipart {
* The Future is failed with an TimeoutException if one part isn't read completely after the given timeout.
*/
def toStrict(timeout: FiniteDuration)(implicit ec: ExecutionContext, fm: FlowMaterializer): Future[Multipart.Strict]
/**
* Creates an entity from this multipart object.
*/
def toEntity(charset: HttpCharset = HttpCharsets.`UTF-8`,
boundary: String = BodyPartRenderer.randomBoundary())(implicit log: LoggingAdapter = NoLogging): MessageEntity = {
val chunks =
parts
.transform(() BodyPartRenderer.streamed(boundary, charset.nioCharset, partHeadersSizeHint = 128, log))
.flatten(FlattenStrategy.concat)
HttpEntity.Chunked(mediaType withBoundary boundary, chunks)
}
}
object Multipart {
trait Strict extends Multipart {
def strictParts: immutable.Seq[BodyPart.Strict]
override def toEntity(charset: HttpCharset, boundary: String)(implicit log: LoggingAdapter = NoLogging): HttpEntity.Strict = {
val data = BodyPartRenderer.strict(strictParts, boundary, charset.nioCharset, partHeadersSizeHint = 128, log)
HttpEntity(mediaType withBoundary boundary, data)
}
}
trait BodyPart {