Java tutorial
/******************************************************************************* * Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved. * * This file is part of the OpenWGA server platform. * * OpenWGA 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. * * In addition, a special exception is granted by the copyright holders * of OpenWGA called "OpenWGA plugin exception". You should have received * a copy of this exception along with OpenWGA in file COPYING. * If not, see <http://www.openwga.com/gpl-plugin-exception>. * * OpenWGA 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 OpenWGA in file COPYING. * If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package de.innovationgate.wgpublisher; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.httpclient.URIException; import de.innovationgate.utils.Base64; import de.innovationgate.utils.WGUtils; import de.innovationgate.webgate.api.WGAPIException; import de.innovationgate.webgate.api.WGContent; import de.innovationgate.webgate.api.WGDatabase; import de.innovationgate.webgate.api.WGException; import de.innovationgate.webgate.api.WGLanguage; import de.innovationgate.webgate.api.WGScriptModule; import de.innovationgate.webgate.api.WGTMLModule; import de.innovationgate.webgate.api.WGUnavailableException; import de.innovationgate.wga.common.beans.csconfig.v1.MediaKey; import de.innovationgate.wga.config.VirtualHost; import de.innovationgate.wgpublisher.WGPDispatcher.URLID; import de.innovationgate.wgpublisher.filter.WGAFilter; import de.innovationgate.wgpublisher.filter.WGAVirtualHostingFilter; import de.innovationgate.wgpublisher.lang.LanguageBehaviour; import de.innovationgate.wgpublisher.lang.LanguageBehaviourTools; import de.innovationgate.wgpublisher.lang.RequestLanguageChooser; import de.innovationgate.wgpublisher.url.TitlePathManager; import de.innovationgate.wgpublisher.url.TitlePathManager.RemainingPathElementException; import de.innovationgate.wgpublisher.url.TitlePathManager.TitlePath; import de.innovationgate.wgpublisher.webtml.utils.HttpErrorException; public class WGPRequestPath { public static final String PATHCMD_JOBLOG = "joblog"; public static final String PATHCMD_WEBTML_DEBUGGER = "tmldebug"; public static final String PATHCMD_ADMIN_TML = "admintml"; public static final String PATHCMD_STATIC_TML = "statictml"; public static final String PATHCMD_STATIC_RESOURCE = "static"; public static final String PATHCMD_STARTPAGE = "start"; public static final String PATHCMD_TMLFORM = "tmlform"; public static final int TYPE_INVALID = -1; public static final int TYPE_INVALID_DB = -2; public static final int TYPE_UNAVAILABLE_DB = -3; public static final int TYPE_UNKNOWN = 0; public static final int TYPE_TML = 2; public static final int TYPE_RESOURCE = 3; public static final int TYPE_FILE = 4; public static final int TYPE_TMLFORM = 5; public static final int TYPE_CSS = 6; public static final int TYPE_REDIRECT = 7; public static final int TYPE_STATICTML = 8; public static final int TYPE_LOGOUT = 9; public static final int TYPE_TMLDEBUG = 10; public static final int TYPE_JOBLOG = 11; public static final int TYPE_GOTO_HOMEPAGE = 12; public static final int TYPE_FAVICON = 13; public static final int TYPE_TITLE_PATH = 14; public static final int TYPE_UNDEFINED_HOMEPAGE = 15; public static final int TYPE_JS = 16; public static final int TYPE_UNKNOWN_CONTENT = 17; // Working variables private URL completeURL = null; private String basePath = null; private List<String> pathElements = new ArrayList<String>(); // Results private int pathType = 0; private String databaseKey = null; private MediaKey mediaKey = null; private String layoutKey = null; private String contentKey = null; private String cssjsKey = null; private String containerKey = null; private String fileName = null; private String derivateName = null; private String resourcePath = null; private WGDatabase database = null; private String queryString = null; private String publisherURL = null; private TitlePathManager.TitlePath titlePathURL = null; private boolean appendQueryString = true; private boolean completePath = true; private String requestLanguage = null; private boolean permanentRedirect = false; private String pathCommand = null; private boolean masterLogin = false; private boolean proceedRequest = true; private WGACore core; private WGContent content; public static final String PATHCMD_TEMP_DOWNLOAD = "tempdwn"; public static final String REQATTRIB_HTTPLOGIN = "HttpLogin"; protected WGPRequestPath(HttpServletRequest request, HttpServletResponse response, WGPDispatcher dispatcher) throws HttpErrorException, WGException, IOException, URIException { this.core = dispatcher.getCore(); this.queryString = request.getQueryString(); this.completeURL = buildCompleteURL(request); this.publisherURL = WGPDispatcher.getPublisherURL(request); // Extract the base part of the path - Redirect to start.jsp if no path information given this.basePath = this.getBasePath(request, dispatcher); if (this.basePath.equals("") || this.basePath.equals("/")) { if (core.getWgaConfiguration().getDefaultDatabase() == null) { this.pathType = TYPE_REDIRECT; this.resourcePath = this.publisherURL + this.core.getStartPageURL(); return; } else { this.basePath = "/" + core.getWgaConfiguration().getDefaultDatabase(); } } // Tokenize Path int tildeTokenPos = -1; java.util.StringTokenizer pathTokens = new StringTokenizer(this.basePath, "/"); String token; while (pathTokens.hasMoreTokens()) { token = pathTokens.nextToken(); this.pathElements.add(token); if (token.charAt(0) == '~') { tildeTokenPos = this.pathElements.size() - 1; } } if (this.pathElements.size() < 1) { this.pathType = TYPE_INVALID; return; } // Resolve database this.databaseKey = ((String) this.pathElements.get(0)).toLowerCase(); ; this.database = (WGDatabase) core.getContentdbs().get(this.databaseKey); // if no database under this key, try to recognize a special path command if (this.database == null) { determineSpecialPathCommand(); if (this.database == null) { return; } } // Check if we need to enforce secure app mode URL secureURL = enforceSecureAppMode(database, request); if (secureURL != null) { pathType = TYPE_REDIRECT; resourcePath = secureURL.toString(); return; } // check if db is accessed via right protocol, host and port - Must be before login so it may get redirected to some certauth port URL currentURL = new URL(request.getRequestURL().toString()); URL redirectURL = enforceRedirectionRules(database, currentURL); // currentURL differs from redirectURL - redirect necessary if (redirectURL != null && !dispatcher.isBrowserInterface(request.getSession())) { pathType = TYPE_REDIRECT; resourcePath = redirectURL.toString(); return; } // Handle special db commands "login" and "logout". The only one not requiring to login to the database if (this.pathElements.size() == 2) { if ("login".equals(this.pathElements.get(1))) { this.pathType = TYPE_REDIRECT; String sourceURL = (request.getParameter("redirect") != null ? dispatcher.getCore().getURLEncoder().decode(request.getParameter("redirect")) : WGPDispatcher.getPublisherURL(request) + "/" + this.databaseKey); this.resourcePath = dispatcher.getLoginURL(request, database, sourceURL); this.appendQueryString = false; return; } else if ("logout".equals(this.pathElements.get(1))) { this.pathType = TYPE_LOGOUT; if (request.getParameter("redirect") != null) { this.resourcePath = request.getParameter("redirect"); this.appendQueryString = false; } else { this.resourcePath = WGPDispatcher.getPublisherURL(request) + "/" + this.databaseKey; } return; } } // Open the database try { if (pathType == TYPE_STATICTML && "admintml".equals(getPathCommand()) && dispatcher.isAdminLoggedIn(request)) { this.masterLogin = true; } // Prepare HTTP credentials if available String credentials = request.getHeader("Authorization"); if (credentials != null && credentials.trim().toLowerCase().startsWith("basic")) { DBLoginInfo loginInfo = DBLoginInfo.createFromHttpCredentials(credentials); if (loginInfo != null) { // Look if ANY media key uses HTTP login. Only if so we accept this login if (isHttpLoginUsed(database)) { request.setAttribute(REQATTRIB_HTTPLOGIN, loginInfo); } } } this.database = core.openContentDB(database, request, this.masterLogin); } catch (WGUnavailableException e) { throw new HttpErrorException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "The website is currently unavailable: " + e.getMessage(), getDatabaseKey()); } catch (de.innovationgate.wgpublisher.AuthenticationException e) { throw new HttpErrorException(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage(), null); } catch (AccessException e) { throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, e.getMessage(), null); } if (!database.isSessionOpen()) { handleLoginFailure(request, response, dispatcher); this.proceedRequest = false; return; } // If request is static/admin tml we are done here if (pathType == TYPE_STATICTML) { return; } // If only database given, go to home page if (this.pathElements.size() == 1) { this.pathType = TYPE_GOTO_HOMEPAGE; setPermanentRedirect(core.getWgaConfiguration().isUsePermanentRedirect()); return; } // Process tilde tokens if (tildeTokenPos != -1) { String tildeToken = (String) this.pathElements.get(tildeTokenPos); // Url to file attachment via ~file-Syntax if (tildeToken.equalsIgnoreCase("~file")) { this.pathType = TYPE_FILE; List<String> preTildeTokenElems = this.pathElements.subList(1, tildeTokenPos); this.containerKey = (String) preTildeTokenElems.get(preTildeTokenElems.size() - 1); this.fileName = WGUtils.serializeCollection( this.pathElements.subList(tildeTokenPos + 1, this.pathElements.size()), "/"); return; } } // Catch special db-related urls String elem1 = ((String) this.pathElements.get(1)).toLowerCase(); int elementsSize = this.pathElements.size(); if (elementsSize >= 3 && (elem1.equals("css"))) { this.pathType = TYPE_CSS; this.cssjsKey = this.database.toLowerCaseMeta( WGUtils.serializeCollection(this.pathElements.subList(2, this.pathElements.size()), "/")); return; } else if (elementsSize >= 3 && (elem1.equals("js"))) { this.pathType = TYPE_JS; this.cssjsKey = this.database.toLowerCaseMeta( WGUtils.serializeCollection(this.pathElements.subList(2, this.pathElements.size()), "/")); return; } else if (elementsSize >= 3 && elem1.equals("file")) { this.pathType = TYPE_FILE; int fileNameIndex = determineFileNameIndex(this.pathElements, 2); this.containerKey = this.database .toLowerCaseMeta(WGUtils.serializeCollection(this.pathElements.subList(2, fileNameIndex), ":")); this.fileName = WGUtils.serializeCollection(this.pathElements.subList(fileNameIndex, elementsSize), "/"); return; } // Find out if we have a title path URL TitlePathManager tpm = (TitlePathManager) database.getAttribute(WGACore.DBATTRIB_TITLEPATHMANAGER); if (tpm != null && tpm.isGenerateTitlePathURLs()) { TitlePathManager.TitlePath url = tpm.parseTitlePathURL(pathElements.subList(1, pathElements.size())); if (url != null) { this.pathType = TYPE_TITLE_PATH; this.titlePathURL = url; this.mediaKey = core.getMediaKey(url.getMediaKey()); if (url.getLanguage() == null) { completePath = false; } } } // Path identified as normal TML request, read media and layout key if (pathType == TYPE_UNKNOWN) { pathType = TYPE_TML; int elementIdx = this.readMediaKey(core, this.pathElements, 1); elementIdx = this.readLayoutKey(core, this.pathElements, elementIdx); if (elementIdx < this.pathElements.size()) { this.contentKey = this.database.toLowerCaseMeta((String) this.pathElements.get(elementIdx)); } if (this.layoutKey == null && this.contentKey == null) { this.pathType = TYPE_INVALID; } } // Retrieve the content if (getPathType() == WGPRequestPath.TYPE_TITLE_PATH) { this.content = getContentByTitlePath(request); if (this.content == null) { pathType = TYPE_UNKNOWN_CONTENT; } // If content was retrieved with struct key we check if the title path is correct. If not we force redirection to the correct version (#00003145) else if (getTitlePathURL().getStructKey() != null) { List<String> correctTitlePath = tpm.buildTitlePath(this.content, mediaKey.getKey(), new RequestLanguageChooser(this.database, request)); if (correctTitlePath == null || !correctTitlePath.equals(getTitlePathURL().getEncodedTitles())) { completePath = false; } } // If title path is configured to include keys but the current tp has no key we force redirection to the version including a key (#00003304). else if (tpm.isIncludeKeys()) { completePath = false; } } else if (getPathType() == TYPE_TML) { if (this.contentKey != null) { URLID contentid = new URLID(this.contentKey, this.database); boolean isBI = WGPDispatcher.isBrowserInterface(request.getSession()) || WGPDispatcher.isAuthoringMode(database.getDbReference(), request.getSession()); this.content = WGPDispatcher.getContentByAnyKey(contentid, database, new RequestLanguageChooser(database, request), isBI); if (this.content != null) { // Look if we really used the parsed content URLID information. if (!contentid.isCompleteFormat()) { completePath = false; } this.requestLanguage = content.getLanguage().getName(); } else { pathType = TYPE_UNKNOWN_CONTENT; } } // Contextless request. If we have no request language we have no complete path and we must determine a language else { if (requestLanguage == null) { completePath = false; LanguageBehaviour langBehaviour = LanguageBehaviourTools.retrieve(database); WGLanguage lang = langBehaviour.requestSelectDatabaseLanguage(database, request); if (lang != null) { this.requestLanguage = lang.getName(); } // Fallback to the database default language else { this.requestLanguage = database.getDefaultLanguage(); } } } } } public static URL buildCompleteURL(HttpServletRequest request) throws MalformedURLException, URIException { StringBuffer url = new StringBuffer(); url.append((String) request.getAttribute(WGAFilter.REQATTRIB_ORIGINAL_URL)); String qs = request.getQueryString(); if (qs != null) { url.append("?").append(qs); } return new URL(url.toString()); } private int determineFileNameIndex(List<String> pathElements, int startElement) { // The path element denoting the file name is either the one having ".zip" suffix (for links into the zip archive) or the last element for (int idx = startElement; idx < pathElements.size(); idx++) { String elem = pathElements.get(idx); if (elem.toLowerCase().endsWith(".zip")) { return idx; } } return pathElements.size() - 1; } private void handleLoginFailure(HttpServletRequest request, HttpServletResponse response, WGPDispatcher dispatcher) throws HttpErrorException, IOException, UnsupportedEncodingException, WGException { // Look if there is a login for that domain. If so, user has no // access to this db if (!this.core.allowLoginRetry(database, request.getSession())) { throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, "You have no access to application '" + getDatabaseKey() + "'", getDatabaseKey()); } // Try to login, if no login for this domain String dbAttribHttpLogin = (String) database.getAttribute(WGACore.DBATTRIB_HTTPLOGIN); if (dbAttribHttpLogin == null) { dbAttribHttpLogin = "false"; } // Try to determine media key from URL, to see if we should do HTTP Login. This will only work with standard URLs. if (this.pathElements.size() >= 2) { readMediaKey(core, this.pathElements, 1); if (mediaKey != null && mediaKey.isHttpLogin() || dbAttribHttpLogin.equals("true")) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setHeader("WWW-Authenticate", "Basic realm=\"" + database.getAttribute(WGACore.DBATTRIB_DOMAIN) + "\""); return; } } else if (dbAttribHttpLogin.equals("true")) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setHeader("WWW-Authenticate", "Basic realm=\"" + database.getAttribute(WGACore.DBATTRIB_DOMAIN) + "\""); return; } // Redirect to login facility if (request.getParameter("$ajaxInfo") == null) { dispatcher.sendRedirect(request, response, dispatcher.getLoginURL(request, database, getCompleteURL())); } else { // this is an ajax call without login information - redirect to jsp and fire event LoginRequired String loginRequiredEvent = de.innovationgate.wgpublisher.webtml.portlet.PortletEvent.LOGIN_REQUIRED_EVENT .toJavaScriptObject(); String encodedEvent = Base64.encodeWeb(loginRequiredEvent.getBytes()); dispatcher.sendRedirect(request, response, this.publisherURL + "/fireSystemEvent.jsp?event=" + encodedEvent); } } private void determineSpecialPathCommand() { this.pathCommand = databaseKey; this.databaseKey = null; if (this.pathCommand.equalsIgnoreCase(PATHCMD_TMLFORM)) { if (this.pathElements.size() >= 3) { this.pathType = TYPE_TMLFORM; this.containerKey = this.pathElements.get(1); this.fileName = this.pathElements.get(2); } else { this.pathType = TYPE_INVALID; } } else if (this.pathCommand.equalsIgnoreCase(PATHCMD_STARTPAGE) && core.getWgaConfiguration().isStartPageEnabled()) { this.pathType = TYPE_REDIRECT; this.resourcePath = this.publisherURL + core.getStartPageURL(); } else if (this.pathCommand.equalsIgnoreCase("wgadmin") || this.pathCommand.equalsIgnoreCase("admin")) { this.pathType = TYPE_REDIRECT; this.resourcePath = this.publisherURL + "/plugin-admin"; } else if (this.pathCommand.equalsIgnoreCase("wga4admin")) { this.pathType = TYPE_REDIRECT; this.resourcePath = this.publisherURL + "/wgadmin.jsp"; } else if (this.pathCommand.equals(PATHCMD_STATIC_RESOURCE) || this.pathCommand.equals(PATHCMD_TEMP_DOWNLOAD)) { this.pathType = TYPE_RESOURCE; this.resourcePath = this.basePath; } else if (this.pathCommand.equals(PATHCMD_STATIC_TML) || this.pathCommand.equals(PATHCMD_ADMIN_TML)) { this.pathType = TYPE_STATICTML; if (this.pathElements.size() >= 3) { this.databaseKey = (String) this.pathElements.get(1); this.database = core.getContentdbs().get(this.databaseKey); this.resourcePath = "/static/tml/" + ((String) this.pathElements.get(2)); if (this.pathElements.size() >= 4) { this.contentKey = (String) this.pathElements.get(3); } } else { this.pathType = TYPE_INVALID; } } else if (this.pathCommand.equals(WGACore.WGASERVICES_WSDL_URL)) { this.pathType = TYPE_STATICTML; this.resourcePath = "/wgaservices"; this.databaseKey = null; } else if (this.pathCommand.equals(PATHCMD_WEBTML_DEBUGGER)) { this.pathType = TYPE_TMLDEBUG; } else if (this.pathCommand.equals(PATHCMD_JOBLOG)) { this.pathType = TYPE_JOBLOG; } else if (this.pathCommand.equals("favicon.ico")) { this.pathType = TYPE_FAVICON; } else if (this.pathCommand.equalsIgnoreCase("contentmanager")) { this.pathType = TYPE_REDIRECT; String defaultAuthoringApp = core.getWgaConfiguration().getServerOptions() .get(WGACore.SERVEROPTION_DEFAULT_AUTHORING_APP); if (defaultAuthoringApp == null) defaultAuthoringApp = "plugin-contentmanager"; this.resourcePath = this.publisherURL + "/" + defaultAuthoringApp; } else { this.databaseKey = this.pathCommand; this.pathType = TYPE_INVALID_DB; } } private int readMediaKey(WGACore core, List<String> elements, int elementIdx) { String mediaKeyCandidate = null; int contentKeyCutPosition = -1; int addToIdx = 0; mediaKeyCandidate = ((String) elements.get(elementIdx)).toLowerCase(); addToIdx = 1; if (core.isMediaKeyDefined(mediaKeyCandidate)) { elementIdx += addToIdx; } else { mediaKeyCandidate = null; this.completePath = false; } if (mediaKeyCandidate != null) { this.mediaKey = core.getMediaKey(mediaKeyCandidate); } return elementIdx; } private int readLayoutKey(WGACore core, List<String> elements, int elementIdx) throws WGAPIException { if (elementIdx >= elements.size()) { return elementIdx; } String designDBKey = core.getDesignDatabaseKey(this.databaseKey); WGDatabase originalDesignDB = (WGDatabase) core.getContentdbs().get(designDBKey); String layoutKeyCandidate = ((String) elements.get(elementIdx)).toLowerCase(); if (layoutKeyCandidate.equals("default")) { layoutKeyCandidate = null; elementIdx++; } else { String mediaKeyStr = this.mediaKey != null ? this.mediaKey.getKey() : (String) this.database.getAttribute(WGACore.DBATTRIB_DEFAULT_MEDIAKEY); String requestLanguageCandidate = null; boolean moduleFound = false; // Try to interpret as complete URLID if (elementIdx == elements.size() - 1) { WGPDispatcher.URLID urlid = new URLID(layoutKeyCandidate, database); if (urlid.getSuffix() != null && urlid.getSuffix().equals(mediaKeyStr)) { if (urlid.getLanguage() != null) { requestLanguageCandidate = urlid.getLanguage(); } moduleFound = isTMLModuleName(originalDesignDB, mediaKeyStr, urlid.getResourceId()); if (moduleFound) { layoutKeyCandidate = urlid.getResourceId(); } } } // Try again with full layout key candidate if (!moduleFound) { moduleFound = isTMLModuleName(originalDesignDB, mediaKeyStr, layoutKeyCandidate); } if (moduleFound) { elementIdx++; this.requestLanguage = requestLanguageCandidate; } else { layoutKeyCandidate = null; completePath = false; } } this.layoutKey = layoutKeyCandidate; return elementIdx; } private boolean isTMLModuleName(WGDatabase db, String mediaKeyStr, String layoutKeyCandidate) throws WGAPIException { if (db == null) { return false; } String deploymentKey = WGTMLModule.createDeploymentKey(db.getDbReference(), layoutKeyCandidate, mediaKeyStr); // We use this as layout key, if there is a layout of this name known to the deployer // Or if the design db is not yet connected (what would make it impossible for the deployer to know the layout) boolean moduleFound = false; if (this.core.isDeploymentKeyDefined(deploymentKey) || (db != null && !db.isConnected())) { moduleFound = true; } // Try to retrieve the module directly from the open database else { WGTMLModule module = database.getTMLModule(layoutKeyCandidate, mediaKeyStr); if (module != null) { moduleFound = true; } WGScriptModule scriptModule = database.getScriptModule(layoutKeyCandidate + ".renderer", WGScriptModule.CODETYPE_TMLSCRIPT); if (scriptModule != null) { moduleFound = true; } } return moduleFound; } /** * Gets the basePath * @return Returns a String */ public String getBasePath() { return basePath; } /** * Gets the containerKey * @return Returns a String */ public String getContainerKey() { return containerKey; } /** * Gets the contentKey * @return Returns a String */ public String getContentKey() { return contentKey; } /** * Gets the fileName * @return Returns a String */ public String getFileName() { return fileName; } /** * Gets the queryString * @return Returns a String */ public String getQueryString() { return queryString; } /** * Gets the layoutKey * @return Returns a String */ public String getLayoutKey() { return layoutKey; } /** * Gets the pathType * @return Returns a int */ public int getPathType() { return pathType; } /** * Gets the resourcePath * @return Returns a String */ public String getResourcePath() { return resourcePath; } /** * Gets the databaseKey * @return Returns a String */ public String getDatabaseKey() { return databaseKey; } /** * Gets the mediaKey * @return Returns a String */ public String getMediaKey() { if (mediaKey != null) { return mediaKey.getKey(); } else { return null; } } public MediaKey getMediaKeyDefinition() { return mediaKey; } /** * Returns the complete and original URL that was used to call this request */ public String getCompleteURL() { return completeURL.toExternalForm(); } /** * Gets the cssjsKey * @return Returns a String */ public String getCssjsKey() { return cssjsKey; } private String getBasePath(javax.servlet.http.HttpServletRequest request, WGPDispatcher dispatcher) throws URIException { // Build basepath from servlet path and path info // getServletPath/getPathInfo is decoded by the container. Since WGA encodes Links with UTF-8 (per default) // this will lead to wrong results with containers, that decode by some other scheme (e.g. Tomcat5). // Encoding of Links is configurable via manager /*StringBuffer pathBuf = new StringBuffer(); if (request.getServletPath() != null) { pathBuf.append(request.getServletPath()); } if (request.getPathInfo() != null) { pathBuf.append(request.getPathInfo()); } String path = pathBuf.toString(); */ String undecodedPath = request.getRequestURI(); String contextPath = request.getContextPath(); if (!contextPath.equals("")) { undecodedPath = undecodedPath.substring(contextPath.length()); } String path = dispatcher.getCore().getURLEncoder().decode(undecodedPath); int semiPos = path.indexOf(";"); if (semiPos != -1) { path = path.substring(0, semiPos); } return path; } /** * Returns the appendQueryString. * @return boolean */ public boolean appendQueryString() { return appendQueryString; } public void setAppendQueryString(boolean appendQueryString) { this.appendQueryString = appendQueryString; } public String expandToCompletePath(HttpServletRequest req) throws WGAPIException, UnsupportedEncodingException { if (this.pathType != TYPE_TITLE_PATH && this.pathType != TYPE_TML) { return null; } String defaultDbKey = null; VirtualHost vhost = (VirtualHost) req.getAttribute(WGAVirtualHostingFilter.REQUESTATTRIB_VIRTUAL_HOST); if (vhost != null && vhost.isHideDefaultDatabaseInURL()) defaultDbKey = WGAVirtualHostingFilter.getDefaultDBKey(core, vhost); StringBuffer path = new StringBuffer(this.publisherURL); path.append("/"); if (defaultDbKey == null || !defaultDbKey.equals(this.databaseKey)) path.append(this.databaseKey).append("/"); // Determine the path to create from the title path configuration of the app (#00004183) TitlePathManager tpm = (TitlePathManager) this.database.getAttribute(WGACore.DBATTRIB_TITLEPATHMANAGER); if (tpm != null && this.content != null && tpm.isTitlePathAllowed(this.content) && (this.mediaKey == null || this.mediaKey.getKey().equals("html")) && (layoutKey == null || layoutKey.equals("default"))) { this.pathType = TYPE_TITLE_PATH; } else { this.pathType = TYPE_TML; } // Title path URL if (this.pathType == TYPE_TITLE_PATH) { if (mediaKey == null) { mediaKey = core.getMediaKey("html"); } List<String> titlePath = tpm.buildTitlePath(this.content, mediaKey.getKey(), new RequestLanguageChooser(this.database, req)); if (titlePath != null) { path.append(WGUtils.serializeCollection(titlePath, "/")); } // Cannot build a title path. We use a normal content path instead. else { this.pathType = TYPE_TML; } } // Regular URL if (this.pathType == TYPE_TML) { MediaKey mediaKey = (this.mediaKey != null ? this.mediaKey : core.getMediaKey((String) this.database.getAttribute(WGACore.DBATTRIB_DEFAULT_MEDIAKEY))); String layoutKey = (this.layoutKey != null ? this.layoutKey : "default"); path.append(mediaKey.getKey()).append("/"); if (this.content != null) { path.append(layoutKey).append("/"); path.append(WGPDispatcher.buildContentURLID(content, mediaKey.getKey(), WGPDispatcher.isBrowserInterface(req.getSession()))); } else { path.append(WGPDispatcher.buildLayoutURLID(this.database, layoutKey, this.requestLanguage, mediaKey.getKey())); } } if (this.queryString != null) { path = path.append("?").append(this.queryString); } return path.toString(); } /** * Returns the completePath. * @return boolean */ public boolean isCompletePath() { return completePath; } /** * Returns the publisherURL. * @return String */ public String getPublisherURL() { return publisherURL; } /** * Sets the resourcePath. * @param resourcePath The resourcePath to set */ public void setResourcePath(String resourcePath) { this.resourcePath = resourcePath; } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return getCompleteURL(); } /** * @return Returns the pathCommand. */ public String getPathCommand() { return pathCommand; } protected TitlePathManager.TitlePath getTitlePathURL() { return titlePathURL; } public boolean isPermanentRedirect() { return permanentRedirect; } public void setPermanentRedirect(boolean permanentRedirect) { this.permanentRedirect = permanentRedirect; } public boolean isMasterLogin() { return masterLogin; } public boolean isProceedRequest() { return proceedRequest; } public WGDatabase getDatabase() { return database; } private void testGeneralAccess(javax.servlet.http.HttpServletRequest request) throws HttpErrorException, AdminLoginNeededException { Boolean updated = (Boolean) database.getAttribute(WGDatabase.ATTRIB_UPDATED); if (updated != null) { if (updated.booleanValue() == true) { throw new HttpErrorException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "This application is currently being updated. Please try again later.", getDatabaseKey()); } } boolean allowPublishing = database.getBooleanAttribute(WGACore.DBATTRIB_ALLOW_PUBLISHING, true); if (!allowPublishing) { throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, "The application '" + database.getDbReference() + "' is not published", null); } boolean authoringApp = database.getBooleanAttribute(WGACore.DBATTRIB_AUTHORING_APP, false); if (authoringApp && !core.isAuthoringPort(request.getLocalPort())) { throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, "Access to authoring applications is disabled", null); } boolean adminApp = database.getBooleanAttribute(WGACore.DBATTRIB_ADMIN_APP, false); if (adminApp) { if (!core.isAdministrativePort(request.getLocalPort())) { throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, "Access to administrative applications is disabled", null); } if (!core.isAdminLoggedIn(request)) { throw new AdminLoginNeededException(); } } if (this.pathType != TYPE_CSS && this.pathType != TYPE_JS && this.pathType != TYPE_FILE) { if (!database.getSessionContext().getUserAccess().mayAccessDirectly()) { throw new IllegalDirectAccessException(database.getDbReference()); } } } private URL enforceSecureAppMode(WGDatabase db, HttpServletRequest req) throws MalformedURLException { boolean secureAppMode = db.getBooleanAttribute(WGACore.DBATTRIB_SECURE_APP, false); if (secureAppMode && !req.isSecure()) { URL currentURL = new URL(req.getRequestURL().toString()); int redirectPort = 443; String defaultPortHTTPS = (String) db.getAttribute(WGACore.DBATTRIB_DEFAULTPORT_HTTPS); if (defaultPortHTTPS != null) { try { redirectPort = Integer.valueOf(defaultPortHTTPS); } catch (NumberFormatException e) { core.getLog().error("Exception parsing default HTTPS port as integer: " + defaultPortHTTPS + ". Will use 443 instead."); } } URL redirectURL; if (redirectPort != 443) { redirectURL = new URL("https", currentURL.getHost(), redirectPort, currentURL.getFile()); } else { redirectURL = new URL("https", currentURL.getHost(), currentURL.getFile()); } return redirectURL; } return null; } /** * * @param db * @param currentURL * @return the redirect url if redirect is necessary - null otherwise * @throws MalformedURLException */ private URL enforceRedirectionRules(WGDatabase db, URL currentURL) throws MalformedURLException { String redirectProtocol = (String) db.getAttribute(WGACore.DBATTRIB_REDIRECTPROTOCOL); String redirectHost = (String) db.getAttribute(WGACore.DBATTRIB_REDIRECTHOST); String redirectPort = (String) db.getAttribute(WGACore.DBATTRIB_REDIRECTPORT); if (redirectProtocol == null && redirectHost == null && redirectPort == null) { // no redirect configured return null; } return determineRedirectionURL(currentURL, redirectProtocol, redirectHost, redirectPort); } public static URL determineRedirectionURL(URL currentURL, String redirectProtocol, String redirectHost, String redirectPort) throws MalformedURLException { // determine current protocol, host and port String currentProtocol = currentURL.getProtocol(); String currentHost = currentURL.getHost(); String currentPort = null; if (currentURL.getPort() != -1) { currentPort = new Integer(currentURL.getPort()).toString(); } else if ("http".equals(currentProtocol)) { currentPort = "80"; } else if ("https".equals(currentProtocol)) { currentPort = "443"; } //build redirectURL boolean redirectNecessary = false; StringBuffer redirectURLBuffer = new StringBuffer(); if (redirectProtocol != null) { if (!currentProtocol.equalsIgnoreCase(redirectProtocol)) { redirectURLBuffer.append(redirectProtocol); redirectNecessary = true; } else { redirectURLBuffer.append(currentProtocol); } } else { redirectURLBuffer.append(currentProtocol); } redirectURLBuffer.append("://"); if (redirectHost != null) { if (!currentHost.equalsIgnoreCase(redirectHost)) { redirectURLBuffer.append(redirectHost); redirectNecessary = true; } else { redirectURLBuffer.append(currentHost); } } else { redirectURLBuffer.append(currentHost); } if (redirectPort != null && currentPort != null) { if (!currentPort.equalsIgnoreCase(redirectPort)) { redirectURLBuffer.append(":" + redirectPort); redirectNecessary = true; } else { redirectURLBuffer.append(":" + currentPort); } } else if (currentPort != null) { redirectURLBuffer.append(":" + currentPort); } redirectURLBuffer.append(currentURL.getPath()); if (currentURL.getQuery() != null) { redirectURLBuffer.append("?").append(currentURL.getQuery()); } if (redirectNecessary) { URL redirectURL = new URL(redirectURLBuffer.toString()); return redirectURL; } else { return null; } } protected void setTitlePathURL(TitlePathManager.TitlePath titlePathURL) { this.titlePathURL = titlePathURL; } protected String getRequestLanguage() { return requestLanguage; } public WGContent getContentByTitlePath(HttpServletRequest request) throws WGAPIException, UnsupportedEncodingException { TitlePathManager tpm = (TitlePathManager) database.getAttribute(WGACore.DBATTRIB_TITLEPATHMANAGER); TitlePath titlePathURL = getTitlePathURL(); WGContent pathContent = null; try { pathContent = tpm.findContentByTitlePath(titlePathURL, database, new RequestLanguageChooser(database, request), TitlePathManager.MODE_URL); } catch (RemainingPathElementException e) { // Cannot happen with MODE_URL of title path manager } return pathContent; } protected WGContent getContent() { return content; } private boolean isHttpLoginUsed(WGDatabase db) { if (db.getAttribute(WGACore.DBATTRIB_HTTPLOGIN) != null && db.getAttribute(WGACore.DBATTRIB_HTTPLOGIN).equals("true")) { return true; } else { for (String mediaKeyStr : core.getMediaKeys()) { MediaKey mediaKey = core.getMediaKey(mediaKeyStr); if (mediaKey != null && mediaKey.isHttpLogin()) { return true; } } } return false; } public static WGPRequestPath parseRequest(WGPDispatcher dispatcher, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws HttpErrorException, WGException, IOException { WGPRequestPath path = new WGPRequestPath(request, response, dispatcher); if (!path.isMasterLogin() && path.getDatabase() != null && path.getDatabase().isSessionOpen()) { try { path.testGeneralAccess(request); } catch (AdminLoginNeededException e) { if (request.getParameter("$ajaxInfo") == null) { dispatcher.sendRedirect(request, response, dispatcher.getAdminLoginURL(request, path.getCompleteURL())); } else { // this is an ajax call without login information - redirect to jsp and fire event LoginRequired String loginRequiredEvent = de.innovationgate.wgpublisher.webtml.portlet.PortletEvent.SESSION_IS_NEW_EVENT .toJavaScriptObject(); String encodedEvent = Base64.encodeWeb(loginRequiredEvent.getBytes()); dispatcher.sendRedirect(request, response, path.publisherURL + "/fireSystemEvent.jsp?event=" + encodedEvent); } path.proceedRequest = false; } catch (IllegalDirectAccessException e) { path.handleLoginFailure(request, response, dispatcher); path.proceedRequest = false; } } return path; } public String getDerivateName() { return derivateName; } protected void setPathType(int pathType) { this.pathType = pathType; } protected void setMediaKey(MediaKey mediaKey) { this.mediaKey = mediaKey; } }