/* This file is part of Libresonic. Libresonic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Libresonic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Libresonic. If not, see <http://www.gnu.org/licenses/>. Copyright 2016 (C) Libresonic Authors Based upon Subsonic, Copyright 2009 (C) Sindre Mehus */ package org.libresonic.player.service; import org.apache.commons.lang3.StringUtils; import org.libresonic.player.Logger; import org.springframework.web.util.UrlPathHelper; import javax.servlet.http.HttpServletRequest; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; 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) { try { URI uri; try { uri = calculateProxyUri(request); } catch (Exception e) { LOG.debug("Could not calculate proxy uri: " + e.getMessage()); uri = calculateNonProxyUri(request); } String baseUrl = uri.toString() + "/"; LOG.debug("Calculated base url to " + baseUrl); return baseUrl; } catch (MalformedURLException | URISyntaxException e) { throw new RuntimeException("Could not calculate base url: " + e.getMessage()); } } private static URI calculateProxyUri(HttpServletRequest request) throws URISyntaxException { String xForardedHost = request.getHeader(X_FORWARDED_HOST); // If the request has been through multiple reverse proxies, // We need to return the original Host that the client used if (xForardedHost != null) { xForardedHost = xForardedHost.split(",")[0]; } if(!isValidXForwardedHost(xForardedHost)) { xForardedHost = request.getHeader(X_FORWARDED_SERVER); // If the request has been through multiple reverse proxies, // We need to return the original Host that the client used if (xForardedHost != null) { xForardedHost = xForardedHost.split(",")[0]; } 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); if(StringUtils.isBlank(scheme)) { throw new RuntimeException("Scheme not provided"); } 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); } }