package er.extensions.appserver; import com.webobjects.appserver.WOActionResults; import com.webobjects.appserver.WOApplication; import com.webobjects.appserver.WOComponent; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WORequest; import com.webobjects.appserver.WORequestHandler; import com.webobjects.appserver.WOResponse; import com.webobjects.appserver.WOSession; import com.webobjects.appserver.WOStatisticsStore; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSLog; import com.webobjects.foundation.NSMutableDictionary; import com.webobjects.foundation.NSNotificationCenter; import er.extensions.foundation.ERXProperties; /** * Patch to prevent direct access to components via /wo/pagename.wo URLs * @property ERXDirectComponentAccessAllowed set to true to restore the original behavior. Default is false. */ public class ERXComponentRequestHandler extends WORequestHandler { private boolean _directComponentAccessAllowed; public ERXComponentRequestHandler() { super(); setDirectComponentAccessAllowed(ERXProperties.booleanForKeyWithDefault("ERXDirectComponentAccessAllowed", false)); } public static NSDictionary requestHandlerValuesForRequest(WORequest aRequest) { NSMutableDictionary aDictionary = new NSMutableDictionary(); NSArray pathArray = aRequest.requestHandlerPathArray(); String lastObject = null; String penultElement = null; String aSessionID = null; String aContextID = null; String aSenderID = null; int p = 0; int count = 0; int length = 0; int pageNameLength = 0; boolean _lookForIDsInCookiesFirst = WORequest._lookForIDsInCookiesFirst(); if (_lookForIDsInCookiesFirst) { aSessionID = aRequest.cookieValueForKey(WOApplication.application().sessionIdKey()); } if (pathArray != null) { count = pathArray.count(); } if ((pathArray != null) && (count != 0)) { lastObject = (String)pathArray.lastObject(); if (count > 1) { penultElement = (String)pathArray.objectAtIndex(count - 2); } length = lastObject.length(); while ((p < length) && (Character.isDigit(lastObject.charAt(p)))) { p++; } if ((p < length) && (lastObject.charAt(p) == '.')) { aContextID = lastObject.substring(0, p); p++; aSenderID = lastObject.substring(p); if ((penultElement != null) && (penultElement.endsWith(".wo"))) { pageNameLength = count - 2; } else if (penultElement != null) { if ((!_lookForIDsInCookiesFirst) || (aSessionID == null)) { aSessionID = penultElement; } pageNameLength = count - 2; } else { pageNameLength = 0; } if (aContextID != null) { aDictionary.setObjectForKey(aContextID, "wocid"); aDictionary.setObjectForKey(aSenderID, "woeid"); } } else { if (lastObject.endsWith(".wo")) { pageNameLength = count; } else { aSessionID = lastObject; pageNameLength = count - 1; } } if ((aSessionID == null) && (!_lookForIDsInCookiesFirst)) { aSessionID = aRequest.stringFormValueForKey(WOApplication.application().sessionIdKey()); if (aSessionID == null) { aSessionID = aRequest.cookieValueForKey(WOApplication.application().sessionIdKey()); } } } else if (WOApplication.application().shouldRestoreSessionOnCleanEntry(aRequest)) { aSessionID = aRequest.cookieValueForKey(WOApplication.application().sessionIdKey()); } if ((aSessionID != null) && (aSessionID.length() != 0)) { aDictionary.setObjectForKey(aSessionID, WOApplication.application().sessionIdKey()); } return aDictionary; } private WOComponent _restorePageForContextID(String oldContextID, WOSession aSession) { return aSession.restorePageForContextID(oldContextID); } private WOResponse _dispatchWithPreparedPage(WOComponent aPage, WOSession aSession, WOContext aContext, NSDictionary someElements) { WORequest aRequest = aContext.request(); WOApplication anApplication = WOApplication.application(); WOResponse aResponse = anApplication.createResponseInContext(aContext); String aSenderID = aContext.senderID(); String oldContextID = aSession._contextIDMatchingIDs(aContext); aResponse.setHTTPVersion(aRequest.httpVersion()); aResponse.setHeader("text/html", "content-type"); aContext._setResponse(aResponse); if (oldContextID == null) { if (aSenderID != null) { if (aRequest._hasFormValues()) { anApplication.takeValuesFromRequest(aRequest, aContext); } } aContext._setPageChanged(false); if (aSenderID != null) { WOActionResults anActionResults = anApplication.invokeAction(aRequest, aContext); if ((anActionResults == null) || ((anActionResults instanceof WOComponent))) { WOComponent aResultComponent = (WOComponent)anActionResults; if ((aResultComponent != null) && (aResultComponent.context() != aContext)) { aResultComponent._awakeInContext(aContext); } boolean didPageChange = false; if ((aResultComponent != null) && (aResultComponent != aContext._pageElement())) { didPageChange = true; } aContext._setPageChanged(didPageChange); if (didPageChange) { aContext._setPageElement(aResultComponent); } } else { WOResponse theResponse = anActionResults.generateResponse(); return theResponse; } } } else { WOComponent responsePage = _restorePageForContextID(oldContextID, aSession); aContext._setPageElement(responsePage); } anApplication.appendToResponse(aResponse, aContext); return aResponse; } private WOResponse _dispatchWithPreparedSession(WOSession aSession, WOContext aContext, NSDictionary someElements) { WOComponent aPage = null; WOResponse aResponse = null; String aPageName = (String)someElements.objectForKey("wopage"); String oldContextID = aContext._requestContextID(); String oldSessionID = (String)someElements.objectForKey(WOApplication.application().sessionIdKey()); WOApplication anApplication = WOApplication.application(); boolean clearIDsInCookies = false; if ((oldSessionID == null) || (oldContextID == null)) { if ((aPageName == null) && (!aSession.storesIDsInCookies())) { WORequest request = aContext.request(); String cookieHeader = request.headerForKey("cookie"); if ((cookieHeader != null) && (cookieHeader.length() > 0)) { NSDictionary cookieDict = request.cookieValues(); if ((cookieDict.objectForKey(WOApplication.application().sessionIdKey()) != null) || (cookieDict.objectForKey(WOApplication.application().instanceIdKey()) != null)) { clearIDsInCookies = true; } } } aPage = anApplication.pageWithName(aPageName, aContext); } else { aPage = _restorePageForContextID(oldContextID, aSession); if (aPage == null) { if (anApplication._isPageRecreationEnabled()) aPage = anApplication.pageWithName(aPageName, aContext); else { return anApplication.handlePageRestorationErrorInContext(aContext); } } } aContext._setPageElement(aPage); aResponse = _dispatchWithPreparedPage(aPage, aSession, aContext, someElements); if (anApplication.isPageRefreshOnBacktrackEnabled()) { aResponse.disableClientCaching(); } aSession._saveCurrentPage(); if ((clearIDsInCookies) && (!aSession.storesIDsInCookies())) { aSession._clearCookieFromResponse(aResponse); } return aResponse; } private WOResponse _dispatchWithPreparedApplication(WOApplication anApplication, WOContext aContext, NSDictionary someElements) { WOSession aSession = null; WOResponse aResponse = null; WOResponse errorResponse = null; String aSessionID = (String)someElements.objectForKey(WOApplication.application().sessionIdKey()); if (aSessionID == null) { aSession = anApplication._initializeSessionInContext(aContext); if (aSession == null) errorResponse = anApplication.handleSessionCreationErrorInContext(aContext); } else { aSession = anApplication.restoreSessionWithID(aSessionID, aContext); if (aSession == null) { errorResponse = anApplication.handleSessionRestorationErrorInContext(aContext); } } if (errorResponse == null) { aResponse = _dispatchWithPreparedSession(aSession, aContext, someElements); } else aResponse = errorResponse; aContext._putAwakeComponentsToSleep(); anApplication.saveSessionForContext(aContext); return aResponse; } WOResponse _handleRequest(WORequest aRequest) { WOContext aContext = null; WOResponse aResponse; NSDictionary requestHandlerValues = requestHandlerValuesForRequest(aRequest); WOApplication anApplication = WOApplication.application(); String aSessionID = (String)requestHandlerValues.objectForKey(WOApplication.application().sessionIdKey()); if ((!anApplication.isRefusingNewSessions()) || (aSessionID != null)) { String aSenderID = (String)requestHandlerValues.objectForKey("woeid"); String oldContextID = (String)requestHandlerValues.objectForKey("wocid"); WOStatisticsStore aStatisticsStore = anApplication.statisticsStore(); if (aStatisticsStore != null) aStatisticsStore.applicationWillHandleComponentActionRequest(); try { aContext = anApplication.createContextForRequest(aRequest); aContext._setRequestContextID(oldContextID); aContext._setSenderID(aSenderID); anApplication.awake(); aResponse = _dispatchWithPreparedApplication(anApplication, aContext, requestHandlerValues); NSNotificationCenter.defaultCenter().postNotification(WORequestHandler.DidHandleRequestNotification, aContext); anApplication.sleep(); } catch (Exception exception) { try { NSLog.err.appendln("<" + getClass().getName() + ">: Exception occurred while handling request:\n" + exception.toString()); if (NSLog.debugLoggingAllowedForLevelAndGroups(1, 4L)) { NSLog.debug.appendln(exception); } if (aContext == null) aContext = anApplication.createContextForRequest(aRequest); else { aContext._putAwakeComponentsToSleep(); } WOSession aSession = aContext._session(); aResponse = anApplication.handleException(exception, aContext); if (aSession != null) { try { anApplication.saveSessionForContext(aContext); anApplication.sleep(); } catch (Exception eAgain) { NSLog.err.appendln("<WOApplication '" + anApplication.name() + "'>: Another Exception occurred while trying to clean the application:\n" + eAgain.toString()); if (NSLog.debugLoggingAllowedForLevelAndGroups(1, 4L)) NSLog.debug.appendln(eAgain); } } } finally { if ((aContext != null) && (aContext._session() != null)) anApplication.saveSessionForContext(aContext); } } if (aResponse != null) { aResponse._finalizeInContext(aContext); } if (aStatisticsStore != null) { WOComponent aPage = aContext.page(); String aName = null; if (aPage != null) { aName = aPage.name(); } aStatisticsStore.applicationDidHandleComponentActionRequestWithPageNamed(aName); } } else { String newLocationURL = anApplication._newLocationForRequest(aRequest); String contentString = "Sorry, your request could not immediately be processed. Please try this URL: <a href=\"" + newLocationURL + "\">" + newLocationURL + "</a>"; aResponse = anApplication.createResponseInContext(null); WOResponse._redirectResponse(aResponse, newLocationURL, contentString); aResponse._finalizeInContext(null); } return aResponse; } @Override public WOResponse handleRequest(WORequest aRequest) { WOApplication anApplication = WOApplication.application(); Object globalLock = anApplication.requestHandlingLock(); WOResponse aResponse; if (globalLock != null) { synchronized (globalLock) { aResponse = _handleRequest(aRequest); } } else { aResponse = _handleRequest(aRequest); } return aResponse; } public boolean isDirectComponentAccessAllowed() { return _directComponentAccessAllowed; } public void setDirectComponentAccessAllowed(boolean directComponentAccessAllowed) { _directComponentAccessAllowed = directComponentAccessAllowed; } }