From 90bf221f67a031724ef08c95e83032fecf019e68 Mon Sep 17 00:00:00 2001 From: Michael Lagutko Date: Fri, 12 Aug 2011 22:19:32 +0300 Subject: [PATCH] httpheader X-Cluster-Client-Ip is added --- src/main/scala/blueeyes/core/http/HttpHeader.scala | 9 +++++++++ .../scala/blueeyes/core/service/HttpClient.scala | 2 +- .../core/service/engines/NettyConverters.scala | 5 +++-- .../core/service/engines/NettyConvertersSpec.scala | 13 +++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main/scala/blueeyes/core/http/HttpHeader.scala b/src/main/scala/blueeyes/core/http/HttpHeader.scala index 13b9bf2ef..dfa145ad3 100644 --- a/src/main/scala/blueeyes/core/http/HttpHeader.scala +++ b/src/main/scala/blueeyes/core/http/HttpHeader.scala @@ -77,6 +77,7 @@ object HttpHeaderField { `X-Content-Type-Options`, `X-Requested-With`, `X-Forwarded-For`, + `X-Cluster-Client-Ip`, `X-Forwarded-Proto`, `X-Powered-By`, `Access-Control-Allow-Origin`, @@ -634,6 +635,14 @@ object HttpHeaders { def unapply(t: (String, String)) = parse(t).map(_.ips) } + case class `X-Cluster-Client-Ip`(ips: HttpIp*) extends HttpHeaderRequest { + def value = ips.map(_.toString).mkString(", ") + } + implicit case object `X-Cluster-Client-Ip` extends HttpHeaderField[`X-Cluster-Client-Ip`] { + override def parse(s: String) = Some(apply(HttpIps.parseHttpIps(s): _*)) + def unapply(t: (String, String)) = parse(t).map(_.ips) + } + case class `X-Forwarded-Proto`(proto: String) extends HttpHeaderRequest { def value = proto } diff --git a/src/main/scala/blueeyes/core/service/HttpClient.scala b/src/main/scala/blueeyes/core/service/HttpClient.scala index 2c32be6e3..a10e51368 100644 --- a/src/main/scala/blueeyes/core/service/HttpClient.scala +++ b/src/main/scala/blueeyes/core/service/HttpClient.scala @@ -51,7 +51,7 @@ trait HttpClient[A] extends HttpRequestHandler[A] { self => request.copy(headers = request.headers + Tuple2("Cookie", cookieEncoder.encode())) } - def remoteHost(host: InetAddress) = buildClient { request => HttpRequest(request.method, request.uri, request.parameters, request.headers + Tuple2("X-Forwarded-For", host.getHostAddress()), request.content, Some(host), request.version)} + def remoteHost(host: InetAddress) = buildClient { request => HttpRequest(request.method, request.uri, request.parameters, request.headers + Tuple2("X-Forwarded-For", host.getHostAddress) + Tuple2("X-Cluster-Client-Ip", host.getHostAddress) , request.content, Some(host), request.version)} def header(name: String, value: String): HttpClient[A] = header((name, value)) diff --git a/src/main/scala/blueeyes/core/service/engines/NettyConverters.scala b/src/main/scala/blueeyes/core/service/engines/NettyConverters.scala index bb2495c90..e0608795d 100644 --- a/src/main/scala/blueeyes/core/service/engines/NettyConverters.scala +++ b/src/main/scala/blueeyes/core/service/engines/NettyConverters.scala @@ -53,8 +53,9 @@ trait NettyConverters{ val headers = buildHeaders(request.getHeaders) val content = fromNettyContent(request.getContent, () => None) - val xforwarded = headers.header(`X-Forwarded-For`) - val remoteHost = xforwarded.flatMap(_.ips.toList.headOption.map(_.ip)).orElse(Some(remoteAddres).collect { case x: InetSocketAddress => x.getAddress }) + val xforwarded = headers.header(`X-Forwarded-For`).flatMap(_.ips.toList.headOption.map(_.ip)) + val remoteIp = xforwarded.orElse(headers.header(`X-Cluster-Client-Ip`).flatMap(_.ips.toList.headOption.map(_.ip))) + val remoteHost = remoteIp.orElse(Some(remoteAddres).collect { case x: InetSocketAddress => x.getAddress }) HttpRequest(request.getMethod, URI(request.getUri), parameters, headers, content, remoteHost, fromNettyVersion(request.getProtocolVersion)) } diff --git a/src/test/scala/blueeyes/core/service/engines/NettyConvertersSpec.scala b/src/test/scala/blueeyes/core/service/engines/NettyConvertersSpec.scala index 8248f33c1..a5dfee8cf 100644 --- a/src/test/scala/blueeyes/core/service/engines/NettyConvertersSpec.scala +++ b/src/test/scala/blueeyes/core/service/engines/NettyConvertersSpec.scala @@ -79,6 +79,19 @@ class NettyConvertersSpec extends Specification with PendingUntilFixed with Nett request.version mustEqual(`HTTP/1.0`) request.remoteHost mustEqual(Some(forwardedAddress.getAddress)) } + "convert netty NettyHttpRequest to service NettyHttpRequest, modifying ip if X-Cluster-Client-Ip header present" in { + val nettyRequest = new DefaultHttpRequest(NettyHttpVersion.HTTP_1_0, NettyHttpMethod.GET, "http://foo/bar?param1=value1") + nettyRequest.setHeader("X-Cluster-Client-Ip", "111.11.11.1, 121.21.2.2") + + val address = new InetSocketAddress("127.0.0.0", 8080) + val forwardedAddress = new InetSocketAddress("111.11.11.1", 8080) + val request = fromNettyRequest(nettyRequest, address) + + request.method mustEqual(HttpMethods.GET) + request.uri mustEqual(URI("http://foo/bar?param1=value1")) + request.headers.raw mustEqual(Map("X-Cluster-Client-Ip" -> "111.11.11.1, 121.21.2.2")) + request.remoteHost mustEqual(Some(forwardedAddress.getAddress)) + } "does not use host name from Host header" in { val nettyRequest = new DefaultHttpRequest(NettyHttpVersion.HTTP_1_0, NettyHttpMethod.GET, "http://foo/bar?param1=value1")