Update: This post is a crock. There is, in fact, a way to hide JSPs, and any other resource from the user’s browser: the WEB-INF directory. The 2.4 servlet spec (section SRV9.5) says:
The WEB-INF node is not part of the public document tree of the application. ... However, the contents of the WEB-INF directory structure… may be exposed using the
RequestDispatchercalls.
And that’s where I’ll be putting JSPs in future.
—Thanks to Joachim and Jason.
A Java servlet container is a web server, but it’s rare to see a Java servlet container directly attached to the Internet. Most often we deploy servlet containers behind ‘real’ web servers like Apache. Why is this?
The reason is JSPs. JSPs need to be placed into the servlet container’s URL space. However, typical java web applications are based on model two and break if a user points their browser directly at a JSP. If we could configure a servlet container so that a user couldn’t send HTTP requests to JSPs, that would be fine, but the servlet container spec doesn’t provide a way to do that. So we end up proxying our Java applications through Apache to give us control over the visible URL space.
Of course, you can use model one and make all your JSPs user callable, but Java system designers reject model one for all the same reasons they reject ASP and PHP.
In large deployments, using Apache brings advantages in security, manageability and efficiency, but in small deployments, its only benefit is to hide part of the URL space. I find this unnecessary complication galling.
All that said, the standard servlets-behind-Apache model is workable and sustainable in the long term, and so I am not advocating a complete revision of the servlet container specification.
What I am advocating is that future web framework developers avoid Sun’s mistakes: ensure that page templates aren’t placed into the public URL space; better still, ensure that page templates don’t directly respond to HTTP requests at all.
Comments
Have you considered putting a filter on *.jsp to block access? In the 2.4 version of the Servlet spec, you can configure the filter so it is not used for includes or forwards.
Peace,
Cameron.
I've never really considered this a practical problem.
If you're doing Model 2, JSPs will only ever be reached through a RequestDispatcher, and won't be able to do anything useful without the controller servlet having placed the right information into the request. So the URLs won't be visible to the user, and even if the user guesses the correct URL of a JSP, they'll at best end up with an empty page, and at worst with a 500 error.
On the other hand, Velocity gives you pluggable resource-loaders, so your Velocity templates don't have to live in the web directory if they don't want to.
You can also place JSP's in WEB-INF, so that they are only accessible by the RequestDispatcher.
But I haven't actually done this because I don't see it as much of a problem. I think some of the Struts folks reccomend this as a standard practice to enforce MVC design.
A good reason to use Apache in front of your servlet container is that it can handle serving static content such as graphics. In most containers, there are a limited number of request threads, and you don't want them taken up with HTTP requests for graphics or .js/.css. On a big site this can help.
Plus there's the option of using the loadbalancing connectors, and the fact that Apache 2 is cool as hell. The Reverse Proxy feature, along with the ability to add headers to the request is very helpful.
The obvious answer is just to put your JSP pages under WEB-INF, then they aren't accessible from direct requests but can be dispatched to from a controller servlet.
You can also create a security constraint that disallows access to "*.jsp" from a client request (which is, by the way, documented in the servlet spec :-).
I take it all back. I hadn't realised WEB-INF was special like that.