From 967c0ed2be5ff4c5ec626285bb337bcf0b3b95b9 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 5 Jun 2015 12:49:03 +0200 Subject: [PATCH] =htc #17404 fix generation of IPv6 Host headers --- .../akka/http/impl/model/parser/UriParser.scala | 14 +++++++++----- .../engine/rendering/RequestRendererSpec.scala | 10 ++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/akka-http-core/src/main/scala/akka/http/impl/model/parser/UriParser.scala b/akka-http-core/src/main/scala/akka/http/impl/model/parser/UriParser.scala index 7e3272c391..c8f32e45a4 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/model/parser/UriParser.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/model/parser/UriParser.scala @@ -46,7 +46,7 @@ private[http] class UriParser(val input: ParserInput, } def parseHost(): Host = - rule(host ~ EOI).run() match { + rule(relaxedHost ~ EOI).run() match { case Right(_) => _host case Left(error) => fail(error, "URI host") } @@ -122,9 +122,10 @@ private[http] class UriParser(val input: ParserInput, def `hostAndPort-pushed` = rule { hostAndPort ~ push(_host) ~ push(_port) } - def host = rule { - `IP-literal` | capture(`ip-v4-address`) ~ &(colonSlashEOI) ~> ((b, a) => _host = IPv4Host(b, a)) | `reg-name` - } + def host = rule { `IP-literal` | ipv4Host | `reg-name` } + + /** A relaxed host rule to use in `parseHost` that also recognizes IPv6 address without the brackets. */ + def relaxedHost = rule { `IP-literal` | ipv6Host | ipv4Host | `reg-name` } def port = rule { DIGIT ~ run(_port = lastChar - '0') ~ optional( @@ -134,7 +135,10 @@ private[http] class UriParser(val input: ParserInput, DIGIT ~ run(_port = 10 * _port + lastChar - '0'))))) } - def `IP-literal` = rule { '[' ~ capture(`ip-v6-address`) ~ ']' ~> ((b, a) => _host = IPv6Host(b, a)) } // IPvFuture not currently recognized + def `IP-literal` = rule { '[' ~ ipv6Host ~ ']' } // IPvFuture not currently recognized + + def ipv4Host = rule { capture(`ip-v4-address`) ~ &(colonSlashEOI) ~> ((b, a) => _host = IPv4Host(b, a)) } + def ipv6Host = rule { capture(`ip-v6-address`) ~> ((b, a) => _host = IPv6Host(b, a)) } def `reg-name` = rule( clearSBForDecoding() ~ oneOrMore(`lower-reg-name-char` ~ appendSB() | UPPER_ALPHA ~ appendLowered() | `pct-encoded`) ~ diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/RequestRendererSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/RequestRendererSpec.scala index 6af7b20043..928ee4cfd5 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/RequestRendererSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/RequestRendererSpec.scala @@ -52,6 +52,16 @@ class RequestRendererSpec extends FreeSpec with Matchers with BeforeAndAfterAll } } + "GET request to a literal IPv6 address" in new TestSetup(serverAddress = new InetSocketAddress("[::1]", 8080)) { + HttpRequest(GET, uri = "/abc") should renderTo { + """GET /abc HTTP/1.1 + |Host: [0:0:0:0:0:0:0:1]:8080 + |User-Agent: akka-http/1.0.0 + | + |""" + } + } + "POST request, a few headers (incl. a custom Host header) and no body" in new TestSetup() { HttpRequest(POST, "/abc/xyz", List( RawHeader("X-Fancy", "naa"),