diff --git a/akka-http-core/src/main/scala/akka/http/model/ContentType.scala b/akka-http-core/src/main/scala/akka/http/model/ContentType.scala index 5ce944a83f..ec1c672fdb 100644 --- a/akka-http-core/src/main/scala/akka/http/model/ContentType.scala +++ b/akka-http-core/src/main/scala/akka/http/model/ContentType.scala @@ -15,13 +15,23 @@ final case class ContentTypeRange(mediaRange: MediaRange, charsetRange: HttpChar case HttpCharsetRange.`*` ⇒ r ~~ mediaRange case x ⇒ r ~~ mediaRange ~~ ContentType.`; charset=` ~~ x } + + /** + * Returns a [[ContentType]] instance which fits this range. + */ + def specimen: ContentType = ContentType(mediaRange.specimen, charsetRange.specimen) } object ContentTypeRange { val `*` = ContentTypeRange(MediaRanges.`*/*`) - implicit def apply(mediaType: MediaType): ContentTypeRange = apply(MediaRange(mediaType), HttpCharsetRange.`*`) + implicit def apply(mediaType: MediaType): ContentTypeRange = apply(mediaType, HttpCharsetRange.`*`) implicit def apply(mediaRange: MediaRange): ContentTypeRange = apply(mediaRange, HttpCharsetRange.`*`) + implicit def apply(contentType: ContentType): ContentTypeRange = + contentType.definedCharset match { + case Some(charset) ⇒ apply(contentType.mediaType, charset) + case None ⇒ ContentTypeRange(contentType.mediaType) + } } final case class ContentType(mediaType: MediaType, definedCharset: Option[HttpCharset]) extends japi.ContentType with ValueRenderable { diff --git a/akka-http-core/src/main/scala/akka/http/model/FormData.scala b/akka-http-core/src/main/scala/akka/http/model/FormData.scala index 8348b77407..30d731cf33 100644 --- a/akka-http-core/src/main/scala/akka/http/model/FormData.scala +++ b/akka-http-core/src/main/scala/akka/http/model/FormData.scala @@ -5,14 +5,16 @@ package akka.http.model /** - * Model for `application/x-www-form-urlencoded` form data. + * Simple model for `application/x-www-form-urlencoded` form data. */ -final case class FormData(fields: Uri.Query) { - type FieldType = (String, String) -} +final case class FormData(fields: Uri.Query) object FormData { val Empty = FormData(Uri.Query.Empty) + def apply(fields: Map[String, String]): FormData = if (fields.isEmpty) Empty else FormData(Uri.Query(fields)) + + def apply(fields: (String, String)*): FormData = + if (fields.isEmpty) Empty else FormData(Uri.Query(fields: _*)) } \ No newline at end of file diff --git a/akka-http-core/src/main/scala/akka/http/model/HttpCharset.scala b/akka-http-core/src/main/scala/akka/http/model/HttpCharset.scala index f1bb65e1fb..f405fba42f 100644 --- a/akka-http-core/src/main/scala/akka/http/model/HttpCharset.scala +++ b/akka-http-core/src/main/scala/akka/http/model/HttpCharset.scala @@ -19,6 +19,11 @@ sealed abstract class HttpCharsetRange extends japi.HttpCharsetRange with ValueR def qValue: Float def matches(charset: HttpCharset): Boolean + /** + * Returns a [[HttpCharset]] instance which fits this range. + */ + def specimen: HttpCharset + /** Java API */ def matches(charset: japi.HttpCharset): Boolean = { import japi.JavaMapping.Implicits._ @@ -32,7 +37,7 @@ object HttpCharsetRange { final def render[R <: Rendering](r: R): r.type = if (qValue < 1.0f) r ~~ "*;q=" ~~ qValue else r ~~ '*' def matches(charset: HttpCharset) = true def matchesAll: Boolean = true - + def specimen = HttpCharsets.`UTF-8` def withQValue(qValue: Float) = if (qValue == 1.0f) `*` else if (qValue != this.qValue) `*`(qValue.toFloat) else this } @@ -42,7 +47,7 @@ object HttpCharsetRange { require(0.0f <= qValue && qValue <= 1.0f, "qValue must be >= 0 and <= 1.0") def matches(charset: HttpCharset) = this.charset.value.equalsIgnoreCase(charset.value) def matchesAll: Boolean = false - + def specimen = charset def withQValue(qValue: Float) = One(charset, qValue) def render[R <: Rendering](r: R): r.type = if (qValue < 1.0f) r ~~ charset ~~ ";q=" ~~ qValue else r ~~ charset } diff --git a/akka-http-core/src/main/scala/akka/http/model/HttpMessage.scala b/akka-http-core/src/main/scala/akka/http/model/HttpMessage.scala index d71ed5c0af..8e1e8fbd17 100644 --- a/akka-http-core/src/main/scala/akka/http/model/HttpMessage.scala +++ b/akka-http-core/src/main/scala/akka/http/model/HttpMessage.scala @@ -250,7 +250,8 @@ final case class HttpRequest(method: HttpMethod = HttpMethods.GET, override def withMethod(method: akka.http.model.japi.HttpMethod): HttpRequest = copy(method = method.asInstanceOf[HttpMethod]) override def withProtocol(protocol: akka.http.model.japi.HttpProtocol): HttpRequest = copy(protocol = protocol.asInstanceOf[HttpProtocol]) - override def withUri(path: String): HttpRequest = copy(uri = Uri(path)) + override def withUri(path: String): HttpRequest = withUri(Uri(path)) + def withUri(uri: Uri): HttpRequest = copy(uri = uri) /** Java API */ override def getUri: japi.Uri = japi.Accessors.Uri(uri) diff --git a/akka-http-core/src/main/scala/akka/http/model/MediaType.scala b/akka-http-core/src/main/scala/akka/http/model/MediaType.scala index bf8f3cce11..85f2d694ac 100644 --- a/akka-http-core/src/main/scala/akka/http/model/MediaType.scala +++ b/akka-http-core/src/main/scala/akka/http/model/MediaType.scala @@ -34,6 +34,11 @@ sealed abstract class MediaRange extends japi.MediaRange with Renderable with Wi */ def withCharset(charsetRange: HttpCharsetRange): ContentTypeRange = ContentTypeRange(this, charsetRange) + /** + * Returns a [[MediaType]] instance which fits this range. + */ + def specimen: MediaType + /** Java API */ def getParams: util.Map[String, String] = { import collection.JavaConverters._ @@ -72,6 +77,7 @@ object MediaRange { override def isMultipart = mainType == "multipart" override def isText = mainType == "text" override def isVideo = mainType == "video" + def specimen = MediaType.custom(mainType, "custom") } def custom(mainType: String, params: Map[String, String] = Map.empty, qValue: Float = 1.0f): MediaRange = { @@ -95,6 +101,7 @@ object MediaRange { def withParams(params: Map[String, String]) = copy(mediaType = mediaType.withParams(params)) def withQValue(qValue: Float) = copy(qValue = qValue) def render[R <: Rendering](r: R): r.type = if (qValue < 1.0f) r ~~ mediaType ~~ ";q=" ~~ qValue else r ~~ mediaType + def specimen = mediaType } implicit def apply(mediaType: MediaType): MediaRange = apply(mediaType, 1.0f) @@ -114,34 +121,42 @@ object MediaRanges extends ObjectRegistry[String, MediaRange] { val `*/*` = new PredefinedMediaRange("*/*") { def matches(mediaType: MediaType) = true + def specimen = MediaTypes.`text/plain` } val `application/*` = new PredefinedMediaRange("application/*") { def matches(mediaType: MediaType) = mediaType.isApplication - override def isApplication: Boolean = true + override def isApplication = true + def specimen = MediaTypes.`application/json` } val `audio/*` = new PredefinedMediaRange("audio/*") { def matches(mediaType: MediaType) = mediaType.isAudio - override def isAudio: Boolean = true + override def isAudio = true + def specimen = MediaTypes.`audio/ogg` } val `image/*` = new PredefinedMediaRange("image/*") { def matches(mediaType: MediaType) = mediaType.isImage - override def isImage: Boolean = true + override def isImage = true + def specimen = MediaTypes.`image/png` } val `message/*` = new PredefinedMediaRange("message/*") { def matches(mediaType: MediaType) = mediaType.isMessage - override def isMessage: Boolean = true + override def isMessage = true + def specimen = MediaTypes.`message/rfc822` } val `multipart/*` = new PredefinedMediaRange("multipart/*") { def matches(mediaType: MediaType) = mediaType.isMultipart - override def isMultipart: Boolean = true + override def isMultipart = true + def specimen = MediaTypes.`multipart/form-data` } val `text/*` = new PredefinedMediaRange("text/*") { def matches(mediaType: MediaType) = mediaType.isText - override def isText: Boolean = true + override def isText = true + def specimen = MediaTypes.`text/plain` } val `video/*` = new PredefinedMediaRange("video/*") { def matches(mediaType: MediaType) = mediaType.isVideo - override def isVideo: Boolean = true + override def isVideo = true + def specimen = MediaTypes.`video/mp4` } } diff --git a/akka-http-core/src/main/scala/akka/http/model/Multipart.scala b/akka-http-core/src/main/scala/akka/http/model/Multipart.scala index 08ccce6cc1..c37ade5304 100644 --- a/akka-http-core/src/main/scala/akka/http/model/Multipart.scala +++ b/akka-http-core/src/main/scala/akka/http/model/Multipart.scala @@ -198,7 +198,7 @@ object Multipart { def additionalDispositionParams = _additionalDispositionParams def additionalHeaders = _additionalHeaders def entity = _entity - override def toString = s"FormData.BodyPart(${_name}, ${_entity}, ${_additionalDispositionParams}, ${_additionalHeaders})" + override def toString = s"FormData.BodyPart($name, $entity, $additionalDispositionParams, $additionalHeaders)" } def unapply(value: BodyPart): Option[(String, BodyPartEntity, Map[String, String], immutable.Seq[HttpHeader])] = @@ -266,7 +266,7 @@ object Multipart { def entity = _entity def rangeUnit = _rangeUnit def additionalHeaders = _additionalHeaders - override def toString = s"ByteRanges.BodyPart(${_contentRange}, ${_entity}, ${_rangeUnit}, ${_additionalHeaders})" + override def toString = s"ByteRanges.BodyPart($contentRange, $entity, $rangeUnit, $additionalHeaders)" } def unapply(value: BodyPart): Option[(ContentRange, BodyPartEntity, RangeUnit, immutable.Seq[HttpHeader])] =