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.

Alex K
  • 854
  • 9
  • 16

3 Answers3

30

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.

Alex K
  • 854
  • 9
  • 16
  • 2
    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. – jrudolph Sep 27 '13 at 08:48
  • @jrudolph Still missing. http://spray.io/documentation/1.1.3/spray-routing/misc-directives/clientIP/#description 2 years, no pressure. – flavian Oct 15 '15 at 16:06
  • 1
    @jrudolph What's on with the documentation? I have spent lot of time to get to this answer, which is most voted, but not accepted. – mirelon Apr 12 '16 at 14:27
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.

4lex1v
  • 20,667
  • 6
  • 48
  • 81
  • 2
    That's a good way, however my answer below is also very relevant. That was actually the main problem for me. – Alex K Sep 27 '13 at 23:51
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

annedroiid
  • 4,071
  • 8
  • 25
  • 49