How to get incoming IP address in Spray framework
Asked Answered
S

3

16

I am looking at headers that are coming in, but no IP seems to be there:

HttpRequest(GET,http://127.0.0.1:8080/track/check,List(Accept-Language: uk-UA, 
uk, ru, en-US, en, Encoding: gzip, deflate, sdch, User-Agent: Mozilla/5.0 
(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29
Safari/537.36, Accept: text/html, application/xhtml+xml, application/xml;q=0.9, 
*/*;q=0.8, Connection: keep-alive, Host: 127.0.0.1:8080),EmptyEntity,HTTP/1.1)

This is a request I did from browser. Basically I am looking in:

path("check") {
       get {
         implicit request => {
           val a = 5
         }
       }
     } ~

Here request object doesn't have any information about the IP address. Any help is very appreciated. thanks.

Shope answered 27/9, 2013 at 2:0 Comment(0)
O
17

If you are using spray routing, then there is a directive for extracting client ip called clientIP =) To use it just write:

(path("somepath") & get) {
  clientIP { ip =>
    complete(s"ip is $ip")
  }
}

more then simple, but you need still need to add explicit configuration to get IP from request. And a little comment, maybe i didn't get something but in spray there is no implicit request. Actually incoming request percolates through your routing structure, if you take a look into the routing library you'll see that route is just an alias: type Route = RequestContext => Unit. So if you need to get access to the context at some point just write:

(path("somepath") & get) {
  clientIP { ip => 
    reqCont => reqCont.complete(s"ip is $ip")
  }
}

But remember about static route part and dynamic part.

Oberstone answered 27/9, 2013 at 5:21 Comment(1)
That's a good way, however my answer below is also very relevant. That was actually the main problem for me.Shope
S
29

The problem was in configuration, this is not documented well. Adding this:

# spray-can config
spray.can {
  server {
    remote-address-header = on
  }
}

forces spray to add remote IP header to the main headers. Address header will have name Remote-Address.

Shope answered 27/9, 2013 at 3:25 Comment(3)
Yes, you are right, it's currently underdocumented. Once we get to documenting the clientIp directive it will contain exactly that documentation. Sorry, that you had to find out the hard way.Alkane
@Alkane Still missing. spray.io/documentation/1.1.3/spray-routing/misc-directives/… 2 years, no pressure.Illene
@Alkane What's on with the documentation? I have spent lot of time to get to this answer, which is most voted, but not accepted.Thin
O
17

If you are using spray routing, then there is a directive for extracting client ip called clientIP =) To use it just write:

(path("somepath") & get) {
  clientIP { ip =>
    complete(s"ip is $ip")
  }
}

more then simple, but you need still need to add explicit configuration to get IP from request. And a little comment, maybe i didn't get something but in spray there is no implicit request. Actually incoming request percolates through your routing structure, if you take a look into the routing library you'll see that route is just an alias: type Route = RequestContext => Unit. So if you need to get access to the context at some point just write:

(path("somepath") & get) {
  clientIP { ip => 
    reqCont => reqCont.complete(s"ip is $ip")
  }
}

But remember about static route part and dynamic part.

Oberstone answered 27/9, 2013 at 5:21 Comment(1)
That's a good way, however my answer below is also very relevant. That was actually the main problem for me.Shope
J
0

You need both what Alex K and 4lex1v have posted.

The below config forces spray to add remote IP header to the main headers. Address header will have name Remote-Address.

# spray-can config
spray.can {
  server {
    remote-address-header = on
  }
}

You will then need to add the clientIP directive around the route.

(path("somepath") & get) {
  clientIP { ip =>
    complete(s"ip is $ip")
  }
}

This will return an object of type RemoteAddress, from which you can extract the IP.

remoteAddress.toOption.map(_.getHostAddress).getOrElse("Unknown")

The clientIP directive will extract the IP if it exists, however the header that it extracts the value from will not be recorded unless you set the remote-address-header flag to on. It defaults to off.

More info can now be found in the Spray documentation. http://spray.io/documentation/1.2.4/spray-routing/misc-directives/clientIP/#example

Jost answered 23/8, 2019 at 12:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.