use of com.webobjects.appserver.WOResponse in project wonder-slim by undur.
the class ERXStaticResourceRequestHandler method handleRequest.
@Override
public WOResponse handleRequest(WORequest request) {
WOResponse response = null;
InputStream is = null;
long length = 0;
String contentType = null;
String uri = request.uri();
if (uri.charAt(0) == '/') {
WOResourceManager rm = application.resourceManager();
String documentRoot = documentRoot();
File file = null;
StringBuilder sb = new StringBuilder(documentRoot.length() + uri.length());
String wodataKey = request.stringFormValueForKey("wodata");
if (uri.startsWith("/cgi-bin") && wodataKey != null) {
uri = wodataKey;
if (uri.startsWith("file:")) {
// remove file:/
uri = uri.substring(5);
} else {
}
} else {
int index = uri.indexOf("/wodata=");
if (index >= 0) {
uri = uri.substring(index + "/wodata=".length());
} else {
sb.append(documentRoot);
}
}
if (_useRequestHandlerPath) {
try {
WODynamicURL dynamicURL = new WODynamicURL(uri);
String requestHandlerPath = dynamicURL.requestHandlerPath();
if (requestHandlerPath == null || requestHandlerPath.length() == 0) {
sb.append(uri);
} else {
sb.append('/');
sb.append(requestHandlerPath);
}
} catch (Exception e) {
throw new RuntimeException("Failed to parse URL '" + uri + "'.", e);
}
} else {
sb.append(uri);
}
String path = sb.toString();
try {
path = path.replaceAll("\\?.*", "");
if (request.userInfo() != null && !request.userInfo().containsKey("HttpServletRequest")) {
/* PATH_INFO is already decoded by the servlet container */
path = path.replace('+', ' ');
path = URLDecoder.decode(path, StandardCharsets.UTF_8);
}
file = new File(path);
if (path.startsWith("jar:")) {
URLConnection uc = new URL(path).openConnection();
if (uc instanceof JarURLConnection) {
length = (int) uc.getContentLengthLong();
} else {
length = -1;
}
is = uc.getInputStream();
} else {
length = (int) file.length();
is = new FileInputStream(file);
}
contentType = rm.contentTypeForResourceNamed(path);
log.debug("Reading file '{}' for uri: {}", file, uri);
} catch (IOException ex) {
if (!uri.toLowerCase().endsWith("/favicon.ico")) {
log.info("Unable to get contents of file '{}' for uri: {}", file, uri);
}
}
} else {
log.error("Can't fetch relative path: {}", uri);
}
response = _generateResponseForInputStream(is, length, contentType);
NSNotificationCenter.defaultCenter().postNotification(WORequestHandler.DidHandleRequestNotification, response);
response._finalizeInContext(null);
return response;
}
use of com.webobjects.appserver.WOResponse in project wonder-slim by undur.
the class ERXAdminDirectAction method forbiddenResponse.
/**
* @return A response object with HTTP status code 403.
*/
protected static WOResponse forbiddenResponse() {
WOResponse response = new WOResponse();
response.setStatus(WOMessage.HTTP_STATUS_FORBIDDEN);
return response;
}
use of com.webobjects.appserver.WOResponse in project wonder-slim by undur.
the class ERXAdminDirectAction method systemPropertyAction.
/**
* Sets a System property. Also active in deployment mode.
*
* <h3>Synopsis:</h3>
* pw=<i>aPassword</i>&key=<i>someSystemPropertyKey</i>&value=<i>someSystemPropertyValue</i>
*
* @return either null when the password is wrong or a new page showing the System properties
*/
public WOActionResults systemPropertyAction() {
if (canPerformAction()) {
String key = request().stringFormValueForKey("key");
WOResponse r = new WOResponse();
if (ERXUtilities.stringIsNullOrEmpty(key)) {
String user = request().stringFormValueForKey("user");
Properties props = ERXConfigurationManager.defaultManager().defaultProperties();
if (user != null) {
System.setProperty("user.name", user);
props = ERXConfigurationManager.defaultManager().applyConfiguration(props);
}
r.appendContentString(ERXProperties.logString(props));
} else {
String value = request().stringFormValueForKey("value");
value = ERXUtilities.stringIsNullOrEmpty(value) ? "" : value;
java.util.Properties p = System.getProperties();
p.put(key, value);
System.setProperties(p);
ERXApplication.configureLoggingWithSystemProperties();
for (java.util.Enumeration e = p.keys(); e.hasMoreElements(); ) {
Object k = e.nextElement();
if (k.equals(key)) {
r.appendContentString("<b>'" + k + "=" + p.get(k) + "' <= you changed this</b><br>");
} else {
r.appendContentString("'" + k + "=" + p.get(k) + "'<br>");
}
}
r.appendContentString("</body></html>");
}
return r;
}
return forbiddenResponse();
}
use of com.webobjects.appserver.WOResponse in project wonder-slim by undur.
the class ERXApplication method dispatchRequest.
public WOResponse dispatchRequest(WORequest request) {
WOResponse response;
if (requestHandlingLog.isDebugEnabled()) {
requestHandlingLog.debug("{}", request);
}
try {
ERXStats.initStatisticsIfNecessary();
_lowMemoryHandler.checkMemory();
response = super.dispatchRequest(request);
} finally {
ERXStats.logStatisticsForOperation(statsLog, "key");
ERXThreadStorage.reset();
}
if (requestHandlingLog.isDebugEnabled()) {
requestHandlingLog.debug("Returning, encoding: " + response.contentEncoding() + " response: " + response);
}
if (ERXResponseCompression.responseCompressionEnabled()) {
if (ERXResponseCompression.shouldCompress(request, response)) {
response = ERXResponseCompression.compressResponse(response);
}
}
return response;
}
use of com.webobjects.appserver.WOResponse in project wonder-slim by undur.
the class ERXAjaxSession method savePage.
/**
* Overridden so that Ajax requests are not saved in the page cache. Checks both the
* response userInfo and the response headers if the DONT_STORE_PAGE key is present. The value doesn't matter.
* <p>
* Page Replacement cache is specifically designed to support component actions in Ajax updates. The problem with
* component actions in Ajax is that if you let them use the normal page cache, then after only 30 (or whatever your backtrack
* cache is set to) updates from Ajax, you will fill your backtrack cache. Unfortunately for the user, though, the backtrack cache
* filled up with background ajax requests, so when the user clicks on a component action on the FOREGROUND page, the
* foreground page has fallen out of the cache, and the request cannot be fulfilled (because its context is gone). If you simply
* turn off backtrack cache entirely for a request, then you can't have component actions inside of an Ajax updated area, because
* the context of the Ajax update that generated the link will never get stored, and so you will ALWAYS get a backtrack error.
* <p>
* Enter page replacement cache. If you look at the behavior of Ajax, it turns out that what you REALLY want is a hybrid page cache. You
* want to keep the backtrack of just the LAST update for a particular ajax component -- you don't care about its previous 29 states
* because the user can't use the back button to get to them anyway, but if you have the MOST RECENT cached version of the page
* then you can click on links in Ajax updated areas. Page Replacement cache implements this logic. For each Ajax component on
* your page that is updating, it keeps a cache entry of its most recent backtrack state (note the difference between this and the
* normal page cache. The normal page cache contains one entry per user-backtrackable-request. The replacement cache contains
* one entry per Ajax component*, allowing up to replacement_page_cache_size many components per page). Each time the Ajax area
* refreshes, the most recent state is replaced*. When a restorePage request comes in, the replacement cache is checked first. If
* the replacement cache can service the page, then it does so. If the replacement cache doesn't contain the context, then it
* passes up to the standard page cache. If you are not using Ajax, no replacement cache will exist in your session, and all the code
* related to it will be skipped, so it should be minimally invasive under those conditions.
* <p>
* <b>*</b> It turns out that we have to keep the last TWO states, because of a race condition in the scenario where the replacement page
* cache replaces context 2 with the context 3 update, but the user's browser hasn't been updated yet with the HTML from
* context 3. When the user clicks, they are clicking the context 2 link, which has now been removed from the replacement cache.
* By keeping the last two states, you allow for the brief period where that transition occurs.
* <p>
* Random note (that I will find useful in 2 weeks when I forget this again): The first time through savePage, the request is saved
* in the main cache. It's only on a subsequent Ajax update that it uses page replacement cache. So even though the cache
* is keyed off of context ID, the explanation of the cache being components-per-page-sized works out because each component
* is requesting in its own thread and generating their own non-overlapping context ids.
*/
@Override
public void savePage(WOComponent page) {
WOContext context = context();
if (ERXAjaxApplication.shouldNotStorePage(context)) {
if (log.isDebugEnabled())
log.debug("Considering pageReplacementCache for {} with contextID {}", context.request().uri(), context.contextID());
WORequest request = context.request();
WOResponse response = context.response();
String pageCacheKey = null;
if (response != null) {
pageCacheKey = response.headerForKey(ERXAjaxSession.PAGE_REPLACEMENT_CACHE_LOOKUP_KEY);
}
if (pageCacheKey == null && request != null) {
pageCacheKey = request.headerForKey(ERXAjaxSession.PAGE_REPLACEMENT_CACHE_LOOKUP_KEY);
}
// A null pageCacheKey should mean an Ajax request that is not returning a content update or an expliclty not cached non-Ajax request
if (pageCacheKey != null) {
log.debug("Will use pageCacheKey {}", pageCacheKey);
String originalContextID = context.request().headerForKey(ERXAjaxSession.ORIGINAL_CONTEXT_ID_KEY);
pageCacheKey = originalContextID + "_" + pageCacheKey;
LinkedHashMap pageReplacementCache = (LinkedHashMap) objectForKey(ERXAjaxSession.PAGE_REPLACEMENT_CACHE_KEY);
if (pageReplacementCache == null) {
pageReplacementCache = new LinkedHashMap();
setObjectForKey(pageReplacementCache, ERXAjaxSession.PAGE_REPLACEMENT_CACHE_KEY);
}
// Remove the oldest entry if we're about to add a new one and that would put us over the cache size ...
// We do a CACHE_SIZE*2 here because for every page, we have to potentially store its previous contextid to prevent
// race conditions, so there technically can be 2x cache size many pages in the cache.
boolean removedCacheEntry = cleanPageReplacementCacheIfNecessary(pageCacheKey);
if (!removedCacheEntry && pageReplacementCache.size() >= ERXAjaxSession.MAX_PAGE_REPLACEMENT_CACHE_SIZE * 2) {
Iterator entryIterator = pageReplacementCache.entrySet().iterator();
Map.Entry oldestEntry = (Map.Entry) entryIterator.next();
entryIterator.remove();
if (log.isDebugEnabled())
log.debug("{} pageReplacementCache too large, removing oldest entry = {}", pageCacheKey, ((TransactionRecord) oldestEntry.getValue()).key());
}
TransactionRecord pageRecord = new TransactionRecord(page, context, pageCacheKey);
pageReplacementCache.put(context.contextID(), pageRecord);
log.debug("{} new context = {}", pageCacheKey, context.contextID());
log.debug("{} = {}", pageCacheKey, pageReplacementCache.keySet());
ERXAjaxApplication.cleanUpHeaders(response);
} else {
// A null pageCacheKey should mean an Ajax request that is not returning a content update or an explicitly not cached non-Ajax request
log.debug("Not caching as no pageCacheKey found");
}
} else {
log.debug("Calling super.savePage for contextID {}", context.contextID());
super.savePage(page);
}
}
Aggregations