001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 * $Id$
018 */
019
020package org.nuxeo.ecm.platform.web.common.vh;
021
022import javax.servlet.ServletRequest;
023import javax.servlet.http.HttpServletRequest;
024
025import org.apache.commons.lang.StringUtils;
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028import org.nuxeo.runtime.api.Framework;
029
030public class VirtualHostHelper {
031
032    private static final int HTTP_PORT_NUMBER = 80;
033
034    private static final int HTTPS_PORT_NUMBER = 443;
035
036    private static final Log log = LogFactory.getLog(VirtualHostHelper.class);
037
038    private static final String X_FORWARDED_HOST = "x-forwarded-host";
039
040    private static final String X_FORWARDED_PROTO = "x-forwarded-proto";
041
042    private static final String X_FORWARDED_PORT = "x-forwarded-port";
043
044    private static final String VH_HEADER = "nuxeo-virtual-host";
045
046    private static final String VH_PARAM = "nuxeo.virtual.host";
047
048    // Utility class.
049    private VirtualHostHelper() {
050    }
051
052    private static HttpServletRequest getHttpServletRequest(ServletRequest request) {
053        if (request instanceof HttpServletRequest) {
054            return (HttpServletRequest) request;
055        }
056        return null;
057    }
058
059    /**
060     * @return WebApp name : ie : nuxeo
061     */
062    public static String getWebAppName(ServletRequest request) {
063        return getContextPath(request).replace("/", "");
064    }
065
066    /**
067     * @return Server URL as : protocol://serverName:port/
068     */
069    public static String getServerURL(ServletRequest request) {
070        return getServerURL(request, false);
071    }
072
073    private static String getServerUrl(String scheme, String serverName, int serverPort) {
074        StringBuilder sbaseURL = new StringBuilder();
075        sbaseURL.append(scheme);
076        sbaseURL.append("://");
077        sbaseURL.append(serverName);
078        if (serverPort != 0) {
079            if ("http".equals(scheme) && serverPort != HTTP_PORT_NUMBER || "https".equals(scheme)
080                    && serverPort != HTTPS_PORT_NUMBER) {
081                sbaseURL.append(':');
082                sbaseURL.append(serverPort);
083            }
084        }
085        sbaseURL.append('/');
086        return sbaseURL.toString();
087    }
088
089    /**
090     * @return Server URL as : protocol://serverName:port/
091     */
092    public static String getServerURL(ServletRequest request, boolean local) {
093        String baseURL = null;
094        HttpServletRequest httpRequest = getHttpServletRequest(request);
095        if (httpRequest != null) {
096            // Detect Nuxeo specific header for VH
097            String nuxeoVH = httpRequest.getHeader(VH_HEADER);
098            if (nuxeoVH == null) {
099                nuxeoVH = Framework.getProperty(VH_PARAM);
100            }
101            if (!local && nuxeoVH != null && nuxeoVH.contains("http")) {
102                baseURL = nuxeoVH;
103            } else {
104                // default values
105                String serverName = httpRequest.getServerName();
106                int serverPort = httpRequest.getServerPort();
107                String scheme = httpRequest.getScheme();
108
109                if (!local) {
110                    String forwardedPort = httpRequest.getHeader(X_FORWARDED_PORT);
111
112                    if (forwardedPort != null) {
113                        try {
114                            serverPort = Integer.parseInt(forwardedPort);
115                        } catch (NumberFormatException e) {
116                            log.error("Unable to get forwarded port from header", e);
117                        }
118                    }
119
120                    String forwardedProto = httpRequest.getHeader(X_FORWARDED_PROTO);
121                    if (forwardedProto != null) {
122                        scheme = forwardedProto;
123                    }
124
125                    // Detect virtual hosting based in standard header
126                    String forwardedHost = httpRequest.getHeader(X_FORWARDED_HOST);
127                    if (forwardedHost != null) {
128                        if (forwardedHost.contains(":")) {
129                            serverName = forwardedHost.split(":")[0];
130                            serverPort = Integer.valueOf(forwardedHost.split(":")[1]);
131                        } else {
132                            serverName = forwardedHost;
133                            serverPort = "https".equals(scheme) ? HTTPS_PORT_NUMBER : HTTP_PORT_NUMBER;
134                        }
135                    }
136                }
137
138                baseURL = getServerUrl(scheme, serverName, serverPort);
139            }
140        }
141        if (baseURL == null) {
142            log.error("Could not retrieve base url correctly");
143            log.debug("Could not retrieve base url correctly", new Throwable());
144        }
145        return baseURL;
146    }
147
148    /**
149     * @return base URL as protocol://serverName:port/webappName/
150     */
151    public static String getBaseURL(ServletRequest request) {
152        String baseURL = null;
153        String serverUrl = getServerURL(request, false);
154        if (serverUrl != null) {
155            String webAppName = getWebAppName(request);
156
157            baseURL = StringUtils.isNotBlank(webAppName) ? serverUrl + webAppName + '/' : serverUrl;
158
159        }
160        return baseURL;
161    }
162
163    /**
164     * Returns the context path of the application. Try to get it from the {@code ServletRequest} and then from the
165     * {@code org.nuxeo.ecm.contextPath} system property. Fallback on default context path {@code /nuxeo}.
166     */
167    public static String getContextPath(ServletRequest request) {
168        HttpServletRequest httpRequest = getHttpServletRequest(request);
169        String contextPath = null;
170        if (httpRequest != null) {
171            contextPath = httpRequest.getContextPath();
172        }
173        return contextPath != null ? contextPath : getContextPathProperty();
174    }
175
176    public static String getContextPathProperty() {
177        return Framework.getProperty("org.nuxeo.ecm.contextPath", "/nuxeo");
178    }
179
180}