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