10

I have a Web Application that users deploy on their own Java Web Servers (e.g. Tomcat). The Java side of Web Application needs to report the URL of the Web Application itself (e.g. http://aServer.com:8080/MyApp or https://blah.blahSever/MyApp). However since a number of users use port-forwarding and other network techniques, the Web Application often reports the wrong name.

I have tried the following techniques but often they don't actually produce what the user requires.

Note (request is an HttpServletRequest)

request.getLocalAddr();    // Returns: 127.0.0.1
request.getLocalName();    // Returns: localhost
request.getServerName();   // Returns: localhost
request.getServerPort();   // Returns: 8080
request.getContextPath();  // Returns: /MyApp

request.getScheme();       // Returns: http

InetAddress.getLocalHost().getHostName();           // Returns: serverXXX-XXX-XXX-XX.xxxx-xxxxxxx.net
InetAddress.getLocalHost().getHostAddress();        // Returns: xxx.xxx.xxx.xxx (ip address)
InetAddress.getLocalHost().getCanonicalHostName();  // Returns: serverXXX-XXX-XXX-XX.xxxx-xxxxxxx.net

The use of InetAddress gets close to what I want but since we are using Server Aliases and ProxyPass in our Apache2 server, the value from InetAddress is the actual values of the server rather than the Alias.

The only technique I can think of to get round this, is that the user provides a property in a properties file, which the Web Application reads on startup. If the property is set, this value is used to return the full web application path (e.g. serverUrl = https://blah.blahServer/MyApp) . This technique would work, but involves more deployment work for my customers.

Does anyone have any ideas as to how I can achieve a more elegant solution?

Thanks, Phil

Phil
  • 1,897
  • 4
  • 25
  • 48
  • 1
    Put the address in a system property and use that. If you put it on a different server, modify the property. Make the app refuse startup if the property isn't set. – Kayaman Jan 31 '14 at 14:11
  • Have you tried `request.getRequestURL()`? – Mustafa Genç Jan 31 '14 at 14:15
  • @Mustafa Genc - Unfortunately getRequestUrl simply returns: http://localhost:8080/MyApp/ - which is nice and complete (it includes http and the port and the Web App name), but unfortunately returns "localhost" ! – Phil Jan 31 '14 at 15:18
  • @Kayaman - I think that your approach may be the one I go for! – Phil Jan 31 '14 at 15:21
  • @Phil It's definitely the easiest (and works well, unless you often switch domain names) approach. – Kayaman Jan 31 '14 at 16:01

3 Answers3

7

Check the 'host' request header. Most client add that header to indicate the host they're trying to contact.

This is the same header that's used for VirtualHosts, so it's pretty standard. It's also obligatory in HTTP1.1 requests.

In fact, you cannot get the value purely from the server side, since it's possible that the user has defined its own hostname for your server.

request.getHeader("Host")

If your server is behind an apache reserve proxy, use the ProxyPreserveHost directive to make sure the Host header is kept intact. I'm sure other reverse proxies have similar options.

Joeri Hendrickx
  • 16,947
  • 4
  • 41
  • 53
  • I tried getHeader("Host") and it simply returns "localhost:8080". I really want a solution that doesn't involve informing the customers that they have to modify their Apache, proxies, whatever. I think what I am asking for (in terms of Pure Java) is actually impossible. – Phil Jan 31 '14 at 15:20
  • If the client doesnt send you the hostname it used to contact you, there is no way for you to know it, since it can differ per client. Of course if you want to define a canonical name then it's different en you should just use some configuration property (lots of apps do it this way). As for the localhost, check with Firebug (or similar) which header was sent in the request. If it's really localhost, that means somehow your browser switched your hostname with localhost, or of course, you really used 'localhost' in the url :) – Joeri Hendrickx Feb 02 '14 at 09:36
  • 4
    The `host` request header is unsafe to use, as it can be altered by anyone – deiga Jan 02 '17 at 11:28
  • @deiga Any header can be altered by anyone in the chain -- still, as there is no such thing as a single name for a host, the closest thing to a reliable source on what the client used as a hostname to contact you, is the client itself. You'll just have to take the risk. – Joeri Hendrickx Jan 02 '17 at 21:30
  • "You'll just have to take the risk." is some of the worst advice I've ever read. NOBODY should use this method to determine their server name. The most secure way is to just set the value you need as a configuration property and read it from your context/environment when needed. Not the most efficient way, sure, but at least you're not blatantly exposing your users to some pretty serious security threats. – Wrinn Dec 19 '18 at 18:42
  • @Wrinn Well sure, but that assumes you 'need' a specific value (as you say yourself). I suppose in the large majority of the cases (i.e. on the internet) you have a canonical hostname and you prefer to answer that - but for the general case you cannot know how the client resolved your name without asking it (which dns did it use, or was it a private hostfile?). Also if you're going to distrust the host header, you can throw any sort of vhost config (which is fairly common) out the window... – Joeri Hendrickx Dec 28 '18 at 15:23
4

This solved the issue for me:

InetAddress.getLocalHost().getHostName();
Vasudev
  • 803
  • 1
  • 7
  • 16
0

i think your problem is not the java api to access the values you need.

In tomcat for example there is a server.xml file containing a pair of lines like

<Engine name="Catalina" defaultHost="**localhost**">

<Host name="**localhost**"  appBase="webapps"  ...

if you replace localhost with the name you want like "myhost.com" and the host where tomcat runs knows its own host name, then when you retrieve the url with the specified hostname , it will show the name you ask for

Regards