=hco don't reject headers that refer to charsets or methods not available on the current platform

This commit is contained in:
Johannes Rudolph 2014-09-23 17:39:23 +02:00
parent 4ba1ce9149
commit dc2737d186
5 changed files with 20 additions and 15 deletions

View file

@ -4,11 +4,12 @@
package akka.http.model
import java.lang.{ Iterable JIterable }
import language.implicitConversions
import scala.collection.immutable
import scala.util.Try
import java.nio.charset.Charset
import akka.http.util._
import java.lang.{ Iterable JIterable }
/**
* A charset range as encountered in `Accept-Charset`. Can either be a single charset, or `*`
@ -52,12 +53,14 @@ object HttpCharsetRange {
final case class HttpCharset private[http] (override val value: String)(val aliases: immutable.Seq[String])
extends japi.HttpCharset with SingletonValueRenderable with WithQValue[HttpCharsetRange] {
@transient private[this] var _nioCharset: Charset = Charset.forName(value)
def nioCharset: Charset = _nioCharset
@transient private[this] var _nioCharset: Try[Charset] = HttpCharset.findNioCharset(value)
/** Returns the Charset for this charset if available or throws an exception otherwise */
def nioCharset: Charset = _nioCharset.get
private def readObject(in: java.io.ObjectInputStream): Unit = {
in.defaultReadObject()
_nioCharset = Charset.forName(value)
_nioCharset = HttpCharset.findNioCharset(value)
}
def withQValue(qValue: Float): HttpCharsetRange = HttpCharsetRange(this, qValue.toFloat)
@ -70,12 +73,10 @@ final case class HttpCharset private[http] (override val value: String)(val alia
}
object HttpCharset {
def custom(value: String, aliases: String*): Option[HttpCharset] =
try Some(HttpCharset(value)(immutable.Seq(aliases: _*)))
catch {
// per documentation all exceptions thrown by `Charset.forName` are IllegalArgumentExceptions
case e: IllegalArgumentException None
}
def custom(value: String, aliases: String*): HttpCharset =
HttpCharset(value)(immutable.Seq(aliases: _*))
private[http] def findNioCharset(name: String): Try[Charset] = Try(Charset.forName(name))
}
// see http://www.iana.org/assignments/character-sets

View file

@ -35,6 +35,5 @@ private[parser] trait CommonActions {
def getCharset(name: String): HttpCharset =
HttpCharsets
.getForKeyCaseInsensitive(name)
.orElse(HttpCharset.custom(name))
.getOrElse(throw new ParsingException("Unsupported charset", name))
.getOrElse(HttpCharset.custom(name))
}

View file

@ -408,7 +408,7 @@ private[parser] trait CommonRules { this: Parser with StringBuilding ⇒
token ~> { s
HttpMethods.getForKey(s) match {
case Some(m) m
case None throw new ParsingException("Unknown HTTP method", s)
case None HttpMethod.custom(s)
}
}
}

View file

@ -31,7 +31,7 @@ class SerializabilitySpec extends WordSpec with Matchers {
}
"with accept-charset" in {
HttpRequest().withHeaders(`Accept-Charset`(HttpCharsets.`UTF-16`)) should beSerializable
HttpRequest().withHeaders(`Accept-Charset`(HttpCharset.custom("utf8").get)) should beSerializable
HttpRequest().withHeaders(`Accept-Charset`(HttpCharset.custom("utf8"))) should beSerializable
}
"with accepted encodings" in {
HttpRequest().withHeaders(`Accept-Encoding`(HttpEncodings.chunked)) should beSerializable

View file

@ -18,6 +18,7 @@ import HttpMethods._
class HttpHeaderSpec extends FreeSpec with Matchers {
val `application/vnd.spray` = MediaType.custom("application/vnd.spray")
val PROPFIND = HttpMethod.custom("PROPFIND")
"The HTTP header model must correctly parse and render the headers" - {
@ -49,6 +50,7 @@ class HttpHeaderSpec extends FreeSpec with Matchers {
`Accept-Charset`(`ISO-8859-1`, `UTF-16` withQValue 0, HttpCharsetRange.`*` withQValue 0.8).renderedTo(
"ISO-8859-1, UTF-16;q=0.0, *;q=0.8")
`Accept-Charset`(`UTF-16` withQValue 0.234567).toString shouldEqual "Accept-Charset: UTF-16;q=0.235"
"Accept-Charset: UTF-16, unsupported42" =!= `Accept-Charset`(`UTF-16`, HttpCharset.custom("unsupported42"))
}
"Access-Control-Allow-Credentials" in {
@ -61,6 +63,7 @@ class HttpHeaderSpec extends FreeSpec with Matchers {
"Access-Control-Allow-Methods" in {
"Access-Control-Allow-Methods: GET, POST" =!= `Access-Control-Allow-Methods`(GET, POST)
"Access-Control-Allow-Methods: GET, PROPFIND, POST" =!= `Access-Control-Allow-Methods`(GET, PROPFIND, POST)
}
"Access-Control-Allow-Origin" in {
@ -85,6 +88,7 @@ class HttpHeaderSpec extends FreeSpec with Matchers {
"Access-Control-Request-Method" in {
"Access-Control-Request-Method: POST" =!= `Access-Control-Request-Method`(POST)
"Access-Control-Request-Method: PROPFIND" =!= `Access-Control-Request-Method`(PROPFIND)
}
"Accept-Ranges" in {
@ -113,6 +117,7 @@ class HttpHeaderSpec extends FreeSpec with Matchers {
"Allow" in {
"Allow: " =!= Allow()
"Allow: GET, PUT" =!= Allow(GET, PUT)
"Allow: GET, PROPFIND, PUT" =!= Allow(GET, PROPFIND, PUT)
}
"Authorization" in {
@ -177,7 +182,7 @@ class HttpHeaderSpec extends FreeSpec with Matchers {
"Content-Type: text/xml; version=3; charset=windows-1252" =!=
`Content-Type`(ContentType(MediaType.custom("text", "xml", params = Map("version" -> "3")), HttpCharsets.getForKey("windows-1252")))
"Content-Type: text/plain; charset=fancy-pants" =!=
ErrorInfo("Illegal HTTP header 'Content-Type': Unsupported charset", "fancy-pants")
`Content-Type`(ContentType(`text/plain`, HttpCharset.custom("fancy-pants")))
"Content-Type: multipart/mixed; boundary=ABC123" =!=
`Content-Type`(ContentType(`multipart/mixed` withBoundary "ABC123"))
"Content-Type: multipart/mixed; boundary=\"ABC/123\"" =!=