Correctly calculate base url in the case a proxy server is present

Signed-off-by: Andrew DeMaria <lostonamountain@gmail.com>
master
Andrew DeMaria 8 years ago
parent 0c629abd4f
commit 190208debc
No known key found for this signature in database
GPG Key ID: 0A3F5E91F8364EDF
  1. 20
      documentation/PROXY.md
  2. 58
      libresonic-main/src/main/java/org/libresonic/player/service/NetworkService.java

@ -49,6 +49,23 @@ libresonic.war, you do not need to change anything.
## Reverse proxy configuration ## Reverse proxy configuration
#### How it works
Libresonic expects proxies to provide information about their incoming URL so that Libresonic can craft it when needed.
To do so, Libresonic looks for the following HTTP headers:
- `X-Forwarded-Host`
- Provides server name and optionally port in the case that the proxy is on a non-standard port
- `X-Forwarded-Proto`
- Tells Libresonic whether to craft an HTTP or HTTPS url
- `X-Forwarded-Server`
- This is only a fallback in the case that `X-Forwarded-Host` is not available
Currently this is used wherever, `NetworkService#getBaseUrl` is called. A couple notable places include:
- Stream urls
- Share urls
- Coverart urls
### Nginx ### Nginx
The following configuration works for Nginx (HTTPS with HTTP redirection): The following configuration works for Nginx (HTTPS with HTTP redirection):
@ -74,6 +91,7 @@ server {
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_max_temp_file_size 0; proxy_max_temp_file_size 0;
proxy_pass http://127.0.0.1:4040; proxy_pass http://127.0.0.1:4040;
@ -98,6 +116,8 @@ The following configuration works for Apache (without HTTPS):
### HAProxy ### HAProxy
**OUTDATED since `X-Forwarded-Host`/`X-FORWARDED-PROTO` change**
The following configuration works for HAProxy (HTTP and HTTPS): The following configuration works for HAProxy (HTTP and HTTPS):
```haproxy ```haproxy

@ -19,6 +19,8 @@
*/ */
package org.libresonic.player.service; package org.libresonic.player.service;
import org.apache.commons.lang3.StringUtils;
import org.libresonic.player.Logger;
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -28,22 +30,62 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
public class NetworkService { public class NetworkService {
private static UrlPathHelper urlPathHelper = new UrlPathHelper();
private static final String X_FORWARDED_SERVER = "X-Forwarded-Server";
private static final String X_FORWARDED_PROTO = "X-Forwarded-Proto";
private static final String X_FORWARDED_HOST = "X-Forwarded-Host";
private final static Logger LOG = Logger.getLogger(NetworkService.class);
public static String getBaseUrl(HttpServletRequest request) { public static String getBaseUrl(HttpServletRequest request) {
try { try {
UrlPathHelper urlPathHelper = new UrlPathHelper(); URI uri;
URL url = new URL(request.getRequestURL().toString()); try {
String host = url.getHost(); uri = calculateProxyUri(request);
String userInfo = url.getUserInfo(); } catch (Exception e) {
String scheme = url.getProtocol(); LOG.debug("Could not calculate proxy uri", e);
int port = url.getPort(); uri = calculateNonProxyUri(request);
}
URI uri = new URI(scheme, userInfo, host, port, urlPathHelper.getContextPath(request), null, null); String baseUrl = uri.toString() + "/";
return uri.toString() + "/"; LOG.debug("Calculated base url to " + baseUrl);
return baseUrl;
} catch (MalformedURLException | URISyntaxException e) { } catch (MalformedURLException | URISyntaxException e) {
throw new RuntimeException("Could not calculate base url", e); throw new RuntimeException("Could not calculate base url", e);
} }
} }
private static URI calculateProxyUri(HttpServletRequest request) throws URISyntaxException {
String xForardedHost = request.getHeader(X_FORWARDED_HOST);
if(!isValidXForwardedHost(xForardedHost)) {
xForardedHost = request.getHeader(X_FORWARDED_SERVER);
if(!isValidXForwardedHost(xForardedHost)) {
throw new RuntimeException("Cannot calculate proxy uri without HTTP header " + X_FORWARDED_HOST);
}
}
URI proxyHost = new URI("ignored://" + xForardedHost);
String host = proxyHost.getHost();
int port = proxyHost.getPort();
String scheme = request.getHeader(X_FORWARDED_PROTO);
return new URI(scheme, null, host, port, urlPathHelper.getContextPath(request), null, null);
}
private static boolean isValidXForwardedHost(String xForardedHost) {
return StringUtils.isNotBlank(xForardedHost) && !StringUtils.equals("null", xForardedHost);
}
private static URI calculateNonProxyUri(HttpServletRequest request) throws MalformedURLException, URISyntaxException {
URL url = new URL(request.getRequestURL().toString());
String host = url.getHost();
String scheme = url.getProtocol();
int port = url.getPort();
String userInfo = url.getUserInfo();
return new URI(scheme, userInfo, host, port, urlPathHelper.getContextPath(request), null, null);
}
} }

Loading…
Cancel
Save