@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException
{
CauchoRequest cauchoReq = null;
HttpServletRequest req;
HttpServletResponse res;
if (request instanceof CauchoRequest) {
cauchoReq = (CauchoRequest) request;
req = cauchoReq;
}
else
req = (HttpServletRequest) request;
res = (HttpServletResponse) response;
boolean isInclude = false;
String uri;
uri = (String) req.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
if (uri != null)
isInclude = true;
else
uri = req.getRequestURI();
Cache cache = _localCache.get(uri);
String filename = null;
String cacheUrl = null;
if (cache == null) {
cacheUrl = getCacheUrl(req, uri);
cache = _pathCache.get(cacheUrl);
if (cache != null)
_localCache.put(uri, cache);
}
if (cache == null) {
CharBuffer cb = new CharBuffer();
String servletPath;
if (cauchoReq != null)
servletPath = cauchoReq.getPageServletPath();
else if (isInclude)
servletPath = (String) req.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
else
servletPath = req.getServletPath();
if (servletPath != null)
cb.append(servletPath);
String pathInfo;
if (cauchoReq != null)
pathInfo = cauchoReq.getPagePathInfo();
else if (isInclude)
pathInfo
= (String) req.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);
else
pathInfo = req.getPathInfo();
if (pathInfo != null)
cb.append(pathInfo);
String relPath = cb.toString();
if (_isCaseInsensitive)
relPath = relPath.toLowerCase(Locale.ENGLISH);
filename = getServletContext().getRealPath(relPath);
Path path = _context.lookupNative(filename);
// only top-level requests are checked
if (cauchoReq == null || cauchoReq.getRequestDepth(0) != 0) {
}
else if (relPath.regionMatches(true, 0, "/web-inf", 0, 8)
&& (relPath.length() == 8
|| ! Character.isLetterOrDigit(relPath.charAt(8)))) {
res.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
else if (relPath.regionMatches(true, 0, "/meta-inf", 0, 9)
&& (relPath.length() == 9
|| ! Character.isLetterOrDigit(relPath.charAt(9)))) {
res.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (relPath.endsWith(".DS_store")) {
// MacOS-X security hole with trailing '.'
res.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
else if (! CauchoSystem.isWindows() || relPath.length() == 0) {
}
else if (path.isDirectory()) {
}
else if (path.isWindowsInsecure()) {
// Windows security issues with trailing '.'
res.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// A null will cause problems.
for (int i = relPath.length() - 1; i >= 0; i--) {
char ch = relPath.charAt(i);
if (ch == 0) {
res.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
}
ServletContext webApp = getServletContext();
String mimeType = webApp.getMimeType(relPath);
boolean isPathReadable = path.canRead();
Path jarPath = null;
if (! isPathReadable) {
String resource = "META-INF/resources" + relPath;
URL url = webApp.getClassLoader().getResource(resource);
if (url != null)
jarPath = Vfs.lookup(url);
}
cache = new Cache(path, jarPath, relPath, mimeType);
_localCache.put(uri, cache);
_pathCache.put(cacheUrl, cache);
}
else if (cache.isModified()) {
cache = new Cache(cache.getFilePath(),
cache.getJarPath(),
cache.getRelPath(),
cache.getMimeType());
cacheUrl = getCacheUrl(req, uri);
_pathCache.put(cacheUrl, cache);
_localCache.put(uri, cache);
}
if (_isGenerateSession)
req.getSession(true);
if (cache.isDirectory()) {
if (! uri.endsWith("/")) {
String queryString = req.getQueryString();
if (queryString != null)
sendRedirect(res, uri + "/?" + queryString);
else
sendRedirect(res, uri + "/");
}
else if (_dir != null)
_dir.forward(req, res);
else
res.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (! cache.canRead()) {
if (isInclude)
throw new FileNotFoundException(uri);
else
res.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// server/4500, #4218
String method = req.getMethod();
if (! method.equalsIgnoreCase("GET")
&& ! method.equalsIgnoreCase("HEAD")
&& ! method.equalsIgnoreCase("POST")) {
res.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED,
"Method not implemented");
return;
}
String ifMatch = req.getHeader("If-None-Match");
String etag = cache.getEtag();
if (ifMatch != null && ifMatch.equals(etag)) {
res.addHeader("ETag", etag);
res.sendError(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
String lastModified = cache.getLastModifiedString();
if (ifMatch == null) {
String ifModified = req.getHeader("If-Modified-Since");
boolean isModified = true;
if (ifModified == null) {
}
else if (ifModified.equals(lastModified)) {
isModified = false;
}
else {
long ifModifiedTime;
QDate date = QDate.allocateLocalDate();
try {
ifModifiedTime = date.parseDate(ifModified);
} catch (Exception e) {
log.log(Level.FINER, e.toString(), e);
ifModifiedTime = 0;
}
QDate.freeLocalDate(date);
isModified = (ifModifiedTime == 0
|| ifModifiedTime != cache.getLastModified());
}
if (! isModified) {
if (etag != null)
res.addHeader("ETag", etag);
res.sendError(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
}
res.addHeader("ETag", etag);
res.addHeader("Last-Modified", lastModified);
if (_isEnableRange && cauchoReq != null && cauchoReq.isTop())
res.addHeader("Accept-Ranges", "bytes");
if (_characterEncoding != null)
res.setCharacterEncoding(_characterEncoding);