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 c6d6e45eb8..c94582d416 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 @@ -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 diff --git a/akka-http-core/src/main/scala/akka/http/model/parser/CommonActions.scala b/akka-http-core/src/main/scala/akka/http/model/parser/CommonActions.scala index d4cbd6d128..b03916b4aa 100644 --- a/akka-http-core/src/main/scala/akka/http/model/parser/CommonActions.scala +++ b/akka-http-core/src/main/scala/akka/http/model/parser/CommonActions.scala @@ -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)) } \ No newline at end of file diff --git a/akka-http-core/src/main/scala/akka/http/model/parser/CommonRules.scala b/akka-http-core/src/main/scala/akka/http/model/parser/CommonRules.scala index 9fb4e4ebda..d7db5252d2 100644 --- a/akka-http-core/src/main/scala/akka/http/model/parser/CommonRules.scala +++ b/akka-http-core/src/main/scala/akka/http/model/parser/CommonRules.scala @@ -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) } } } diff --git a/akka-http-core/src/test/scala/akka/http/model/SerializabilitySpec.scala b/akka-http-core/src/test/scala/akka/http/model/SerializabilitySpec.scala index 3756e2d0fa..07b1412f0b 100644 --- a/akka-http-core/src/test/scala/akka/http/model/SerializabilitySpec.scala +++ b/akka-http-core/src/test/scala/akka/http/model/SerializabilitySpec.scala @@ -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 diff --git a/akka-http-core/src/test/scala/akka/http/model/parser/HttpHeaderSpec.scala b/akka-http-core/src/test/scala/akka/http/model/parser/HttpHeaderSpec.scala index 3ef2c08807..4bb1fc8bb3 100644 --- a/akka-http-core/src/test/scala/akka/http/model/parser/HttpHeaderSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/model/parser/HttpHeaderSpec.scala @@ -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\"" =!=