Yes, the very root-directory of the whole application is a symbolic
link. There are no symbolic links in the rest of the paths to the
static resources, everything is located inside the root directory.
Adding the ContextHandler.ApproveAliases does resolve the problem.
Without it the requests simply end up being handled by the servlet
at / instead of the ContextHandler/ResourceHandler pairs.
Unfortunately I do not think I can post a simple reproducer. The
Jetty embedding code is wrapped inside a generic Servlet container
abstraction so the application that sets up the server does not call
any Jetty specific methods directly. But below are the most
important methods of the wrapper.
I hope you can tell me how I can resolve the issue. Taking out the
symlink is a no-go for us.
def addServletContext[T <: Servlet](contextPath : String,servletPath : String,servletClass : Class[T],uploadLimit : Int) =
{
class ServletContext extends ServletContextHandler with ServletConfig {
def setParameter(name : String,value : Any) = setAttribute(name,value)
setContextPath(contextPath)
val fileSizeThreshold = 1024 * 1024
val sh = new SessionHandler
sh.setUsingCookies(false)
sh.setSessionIdPathParameterName(ServletContainer.sessionIdName)
sh.setMaxInactiveInterval(sessionTimeout)
setSessionHandler(sh)
val holder = new ServletHolder(servletClass)
val mc = new MultipartConfigElement(System.getProperty("java.io.tmpdir"),uploadLimit,uploadLimit,fileSizeThreshold)
holder.getRegistration.setMultipartConfig(mc)
addServlet(holder,servletPath)
} val ctx = new ServletContext
contexts ::= ctx
ctx
}
def addDirectoryContext(contextPath : String,directoryPath : String)
{
class DirectoryContext extends ContextHandler()
{
addAliasCheck(new ContextHandler.ApproveAliases)
setContextPath(contextPath)
val resourceHandler = new ResourceHandler
resourceHandler.setResourceBase(directoryPath)
resourceHandler.setDirectoriesListed(false)
resourceHandler.setCacheControl("max-age=" + 24 * 60 * 60)
setHandler(resourceHandler)
}
val ctx = new DirectoryContext
contexts ::= ctx
}
def start
{
val sam = sessionMapping match
{
case Some(mapping) =>
{
new DefaultSessionIdManager(server)
{
override def newSessionId(request : HttpServletRequest,seed : Long) = mapping(super.newSessionId(request,seed))
}
}
case _ =>
{
new DefaultSessionIdManager(server)
}
}
sam.setWorkerName(null)
val houseKeeper = new org.eclipse.jetty.server.session.HouseKeeper
houseKeeper.setIntervalSec(60)
sam.setSessionHouseKeeper(houseKeeper)
server.setSessionIdManager(sam)
val ctxHandler = new ContextHandlerCollection
ctxHandler.setHandlers(Array(contexts.reverse:_*))
server.setHandler(ctxHandler)
server.start
server.getErrorHandler.setShowStacks(false)
}