package er.extensions.appserver;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import org.apache.commons.lang3.CharEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WODynamicURL;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WORequestHandler;
import com.webobjects.appserver.WOResourceManager;
import com.webobjects.appserver.WOResponse;
import com.webobjects.appserver._private.WODeployedBundle;
import com.webobjects.foundation.NSBundle;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSNotificationCenter;
import er.extensions.foundation.ERXDictionaryUtilities;
import er.extensions.foundation.ERXProperties;
/**
* Simple static resource request handler. Allows for better debugging
* and you can set the document root via the system property <code>WODocumentRoot</code>.
* @author ak
*/
public class ERXStaticResourceRequestHandler extends WORequestHandler {
private static Logger log = LoggerFactory.getLogger(ERXStaticResourceRequestHandler.class);
private static WOApplication application = WOApplication.application();
private String _documentRoot;
private boolean _useRequestHandlerPath;
public ERXStaticResourceRequestHandler() {
_documentRoot = null;
}
/**
* Creates a static resource handler for the given framework, which gives you
* nicer relative URLs to work with. For instance, you could register a request
* handler "aj" that maps to the "Ajax" framework, which would make URLs of the
* form "/aj/wonder.js" map onto Ajax's WebServerResources/wonder.js folder.
*
* @param frameworkName the name of the framework to map to (or null/"app" for the application)
*/
public ERXStaticResourceRequestHandler(String frameworkName) {
if ("app".equals(frameworkName)) {
frameworkName = null;
}
WODeployedBundle bundle = WOApplication.application().resourceManager()._cachedBundleForFrameworkNamed(frameworkName);
File bundleFile = new File(bundle.bundlePath());
if (bundle.isFramework()) {
bundleFile = new File(bundleFile, "WebServerResources");
}
else {
bundleFile = new File(new File(bundleFile, "Contents"), "WebServerResources");
}
_documentRoot = bundleFile.getAbsolutePath();
_useRequestHandlerPath = true;
}
protected WOResponse _generateResponseForInputStream(InputStream is, long length, String type) {
WOResponse response = application.createResponseInContext(null);
if (is != null) {
if (length != 0) {
response.setContentStream(is, 50*1024, length);
}
} else {
response.setStatus(404);
}
if (type != null) {
response.setHeader(type, "content-type");
}
if(length != 0) {
response.setHeader("" + length, "content-length");
}
return response;
}
private String documentRoot() {
if (_documentRoot == null) {
_documentRoot = ERXProperties.stringForKey("WODocumentRoot");
if(_documentRoot == null) {
NSBundle bundle = NSBundle.bundleForName("JavaWebObjects");
NSDictionary dict = ERXDictionaryUtilities.dictionaryFromPropertyList("WebServerConfig", bundle);
_documentRoot = (String) dict.objectForKey("DocumentRoot");
}
}
return _documentRoot;
}
@Override
public WOResponse handleRequest(WORequest request) {
WOResponse response = null;
FileInputStream 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, CharEncoding.UTF_8);
}
file = new File(path);
length = 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;
}
}