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 static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.REQUESTED_URL;
025
026import javax.servlet.ServletRequest;
027import javax.servlet.http.HttpServletRequest;
028
029import org.apache.commons.lang.StringUtils;
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032import org.nuxeo.runtime.api.Framework;
033
034public class VirtualHostHelper {
035
036    private static final int HTTP_PORT_NUMBER = 80;
037
038    private static final int HTTPS_PORT_NUMBER = 443;
039
040    private static final Log log = LogFactory.getLog(VirtualHostHelper.class);
041
042    private static final String X_FORWARDED_HOST = "x-forwarded-host";
043
044    private static final String X_FORWARDED_PROTO = "x-forwarded-proto";
045
046    private static final String X_FORWARDED_PORT = "x-forwarded-port";
047
048    private static final String VH_HEADER = "nuxeo-virtual-host";
049
050    private static final String VH_PARAM = "nuxeo.virtual.host";
051
052    // Utility class.
053    private VirtualHostHelper() {
054    }
055
056    private static HttpServletRequest getHttpServletRequest(ServletRequest request) {
057        if (request instanceof HttpServletRequest) {
058            return (HttpServletRequest) request;
059        }
060        return null;
061    }
062
063    /**
064     * @return WebApp name : ie : nuxeo
065     */
066    public static String getWebAppName(ServletRequest request) {
067        return getContextPath(request).replace("/", "");
068    }
069
070    /**
071     * @return Server URL as : protocol://serverName:port/
072     */
073    public static String getServerURL(ServletRequest request) {
074        return getServerURL(request, false);
075    }
076
077    private static String getServerUrl(String scheme, String serverName, int serverPort) {
078        StringBuilder sbaseURL = new StringBuilder();
079        sbaseURL.append(scheme);
080        sbaseURL.append("://");
081        sbaseURL.append(serverName);
082        if (serverPort != 0) {
083            if ("http".equals(scheme) && serverPort != HTTP_PORT_NUMBER || "https".equals(scheme)
084                    && serverPort != HTTPS_PORT_NUMBER) {
085                sbaseURL.append(':');
086                sbaseURL.append(serverPort);
087            }
088        }
089        sbaseURL.append('/');
090        return sbaseURL.toString();
091    }
092
093    /**
094     * @return Server URL as : protocol://serverName:port/
095     */
096    public static String getServerURL(ServletRequest request, boolean local) {
097        String baseURL = null;
098        HttpServletRequest httpRequest = getHttpServletRequest(request);
099        if (httpRequest != null) {
100            // Detect Nuxeo specific header for VH
101            String nuxeoVH = httpRequest.getHeader(VH_HEADER);
102            if (nuxeoVH == null) {
103                nuxeoVH = Framework.getProperty(VH_PARAM);
104            }
105            if (!local && nuxeoVH != null && nuxeoVH.contains("http")) {
106                baseURL = nuxeoVH;
107            } else {
108                // default values
109                String serverName = httpRequest.getServerName();
110                int serverPort = httpRequest.getServerPort();
111                String scheme = httpRequest.getScheme();
112
113                if (!local) {
114                    String forwardedPort = httpRequest.getHeader(X_FORWARDED_PORT);
115
116                    if (forwardedPort != null) {
117                        try {
118                            serverPort = Integer.parseInt(forwardedPort);
119                        } catch (NumberFormatException e) {
120                            log.error("Unable to get forwarded port from header", e);
121                        }
122                    }
123
124                    String forwardedProto = httpRequest.getHeader(X_FORWARDED_PROTO);
125                    if (forwardedProto != null) {
126                        scheme = forwardedProto;
127                    }
128
129                    // Detect virtual hosting based in standard header
130                    String forwardedHost = httpRequest.getHeader(X_FORWARDED_HOST);
131                    if (forwardedHost != null) {
132                        if (forwardedHost.contains(":")) {
133                            serverName = forwardedHost.split(":")[0];
134                            serverPort = Integer.valueOf(forwardedHost.split(":")[1]);
135                        } else {
136                            serverName = forwardedHost;
137                            serverPort = "https".equals(scheme) ? HTTPS_PORT_NUMBER : HTTP_PORT_NUMBER;
138                        }
139                    }
140                }
141
142                baseURL = getServerUrl(scheme, serverName, serverPort);
143            }
144        }
145        if (baseURL == null) {
146            log.error("Could not retrieve base url correctly");
147            log.debug("Could not retrieve base url correctly", new Throwable());
148        }
149        return baseURL;
150    }
151
152    /**
153     * @return base URL as protocol://serverName:port/webappName/
154     */
155    public static String getBaseURL(ServletRequest request) {
156        String baseURL = null;
157        String serverUrl = getServerURL(request, false);
158        if (serverUrl != null) {
159            String webAppName = getWebAppName(request);
160
161            baseURL = StringUtils.isNotBlank(webAppName) ? serverUrl + webAppName + '/' : serverUrl;
162
163        }
164        return baseURL;
165    }
166
167    /**
168     * Returns the context path of the application. Try to get it from the {@code ServletRequest} and then from the
169     * {@code org.nuxeo.ecm.contextPath} system property. Fallback on default context path {@code /nuxeo}.
170     */
171    public static String getContextPath(ServletRequest request) {
172        HttpServletRequest httpRequest = getHttpServletRequest(request);
173        String contextPath = null;
174        if (httpRequest != null) {
175            contextPath = httpRequest.getContextPath();
176        }
177        return contextPath != null ? contextPath : getContextPathProperty();
178    }
179
180    public static String getContextPathProperty() {
181        return Framework.getProperty("org.nuxeo.ecm.contextPath", "/nuxeo");
182    }
183
184    /**
185     * Computes the url to be redirected when logging out
186     * 
187     * @return redirect URL as protocol://serverName:port/webappName/...
188     * @since 9.1
189     */
190    public static String getRedirectUrl(HttpServletRequest request) {
191        String redirectURL = getBaseURL(request);
192        if (request.getAttribute(REQUESTED_URL) != null) {
193            redirectURL += request.getAttribute(REQUESTED_URL);
194        } else if (request.getParameter(REQUESTED_URL) != null) {
195            redirectURL += request.getParameter(REQUESTED_URL);
196        } else {
197            redirectURL = request.getRequestURL().toString();
198            String queryString = request.getQueryString();
199            if (queryString != null) {
200                redirectURL += '?' + queryString;
201            }
202        }
203        return redirectURL;
204    }
205
206}