From a1d7c336635693106b495d0e0ba7d35a68d8f7e9 Mon Sep 17 00:00:00 2001 From: 2beaucoup Date: Wed, 10 Dec 2014 10:56:38 +0100 Subject: [PATCH] =htc simplify content negotiation --- .../scala/akka/http/marshalling/Marshal.scala | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/akka-http/src/main/scala/akka/http/marshalling/Marshal.scala b/akka-http/src/main/scala/akka/http/marshalling/Marshal.scala index d935230f54..980180f9c3 100644 --- a/akka-http/src/main/scala/akka/http/marshalling/Marshal.scala +++ b/akka-http/src/main/scala/akka/http/marshalling/Marshal.scala @@ -43,32 +43,27 @@ class Marshal[A](val value: A) { def qValueCS(charset: HttpCharset) = request.qValueForCharset(charset, charsetRanges) m(value).fast.map { marshallings ⇒ - def weight(mt: MediaType, cs: HttpCharset): Float = math.min(qValueMT(mt), qValueCS(cs)) - val defaultMarshallingWeight: MarshallingWeight = - new MarshallingWeight(0f, { () ⇒ - val supportedContentTypes = marshallings collect { - case Marshalling.WithFixedCharset(mt, cs, _) ⇒ ContentType(mt, cs) - case Marshalling.WithOpenCharset(mt, _) ⇒ ContentType(mt) - } - throw UnacceptableResponseContentTypeException(supportedContentTypes.toSet) - }) + val defaultMarshallingWeight = new MarshallingWeight(0f, { () ⇒ + val supportedContentTypes = marshallings collect { + case Marshalling.WithFixedCharset(mt, cs, _) ⇒ ContentType(mt, cs) + case Marshalling.WithOpenCharset(mt, _) ⇒ ContentType(mt) + } + throw UnacceptableResponseContentTypeException(supportedContentTypes.toSet) + }) + def choose(acc: MarshallingWeight, mt: MediaType, cs: HttpCharset, marshal: () ⇒ HttpResponse) = { + val weight = math.min(qValueMT(mt), qValueCS(cs)) + if (weight > acc.weight) new MarshallingWeight(weight, marshal) else acc + } val best = marshallings.foldLeft(defaultMarshallingWeight) { case (acc, Marshalling.WithFixedCharset(mt, cs, marshal)) ⇒ - val w = weight(mt, cs) - if (w > acc.weight) new MarshallingWeight(w, marshal) else acc - + choose(acc, mt, cs, marshal) case (acc, Marshalling.WithOpenCharset(mt, marshal)) ⇒ - def withCharset(cs: HttpCharset) = { - val w = weight(mt, cs) - if (w > acc.weight) new MarshallingWeight(w, () ⇒ marshal(cs)) else acc - } + def withCharset(cs: HttpCharset) = choose(acc, mt, cs, () ⇒ marshal(cs)) // logic for choosing the charset adapted from http://tools.ietf.org/html/rfc7231#section-5.3.3 if (qValueCS(`UTF-8`) == 1f) withCharset(`UTF-8`) // prefer UTF-8 if fully accepted - else charsetRanges match { // ranges are sorted by descending q-value, - case (HttpCharsetRange.One(cs, qValue)) :: _ ⇒ // so we only need to look at the first one - if (qValue == 1f) withCharset(cs) // if the client has high preference for this charset, pick it - else if (qValue > 0f) withCharset(cs) // ok, simply choose the first one if the client doesn't reject it - else acc + else charsetRanges match { + // pick the charset which the highest q-value (head of charsetRanges) if it isn't explicitly rejected + case (HttpCharsetRange.One(cs, qValue)) :: _ if qValue > 0f ⇒ withCharset(cs) case _ ⇒ acc }