The Long and Sordid Tale of the Invoker Servlet
As of Tomcat version 6.0 web applications wishing to use the Invoker Servlet will have to be run as privileged. This is in addition to the requirements listed below.
Since running your web application as privileged grants access to other server components, you should seriously consider removing any invoker servlet requirements from your application before moving to Tomcat version 6.0.
Wait, wait, I don't want some long boring story, just tell me how to make it work right now!
Alright, if you insist.
Cutting To the Chase
The invoker is evil! Don't use it. Period.
Read on if you still don't believe it...
But First, The Short Tale
In the file conf/web.xml find a section of text that looks like this:
The Middling Tale
Alright, so you've read this far.
Older tutorials, books, downloads and web sites will probably provide you with application code that looks something like:
This method uses the invoker servlet, provided by many servlet containers. The much better way of invoking a servlet is by providing an explicit mapping for it. This is accomplished by using a pair of tags in your web application's web.xml file. This is not the same file as mentioned above. That file was located in Tomcat's conf/ directory. This web.xml file (which you will probably need to create) will reside in your web-application's WEB-INF/ directory. For each servlet you want to call, provide a pair of tags like the following:
There are a couple things to note when you do this. Order of elements in web.xml is very important. So when you go to create your second 'couplet', make sure all your <servlet> tags are declared before your <servlet-mapping> tags. You'll maybe want to keep the 'couplets' together, because it will be easier to see which one belongs to which, but don't do it!
Also note, the <servlet-class> tag contains the fully qualified name of your class. Package and everything, and don't include .class on the end.
Finally <url-pattern> is what you'd now use to invoke the HelloWorld servlet.
not /servlet/hello not /servlet/hello/your.package.name.HelloWorld
The Even Longer Sordid Tale of the Invoker Servlet
The Servlet Spec The 'bible' on Servlets is the Servlet Specification.
It can be downloaded from http://www.jcp.org/aboutJava/communityprocess/final/jsr053/ Oddly enough, there is a section in the spec that states "We emphasize that this specification is not a user's guide for servlet developers and is not intended to be used as such."
As much as the spec is not meant to be a tutorial, I think there is a wealth of information in the spec, and every servlet developer should read it.
For example... if you read the spec, you would find no mention anywhere of any 'invoker' servlet, or being able to invoke a servlet with a pattern that looks like "/servlet/the.class.name.of.the.servlet"
So why do so many tutorials and web pages have patterns like this? There's a part of the spec that gives a hint:
''SRV.11.2.1 Implicit Mappings'' ... If the container has an internal JSP container, the *.jsp extension is mapped to it, allowing JSP pages to be executed on demand. This mapping is termed an implicit mapping. If a *.jsp mapping is defined by the web application, its mapping takes precedence over the implicit mapping. ... A servlet container is allowed to make other implicit mappings as long as explicit mappings take precedence.
Oh, that's interesting. So there must be something in Tomcat that allows me to run JSPs. I know this, because all I need to do is drop a JSP file into my web-application directory, and without any more fuss, it will just work.
Hold the phone! A JSP is just a text file: how does Tomcat know enough to grab it, convert it to a java source file, then compile that file into a servlet class, and finally, invoke that servlet? How does it do all that?
The answer is: the implicit *.jsp mapping. And you'll find it in conf/web.xml
Somewhere around line 155 of an un-modified conf/web.xml file, you'll find this:
And then, around line 285:
Here then, is the explanation of how the JSPs magically work. It's not magic at all really, it's the 'implicit' mapping mentioned in the specification. The way Tomcat has been implemented, it's not really 'implicit', so much as it's 'explicity mapped in a web.xml file that is implicitly applied globally, to every application'
Here, read this, at the top of conf/web.xml:
So even when you don't supply your own web.xml file in WEB-INF, you are still getting some defaults. Lucky for you, or even your JSP files would not work!
So how does this relate to the invoker servlet?? Let's get back on topic! Someone once thought "hmm, there ought to be a way for developers to just drop a servlet class into a directory and have it just work, just like we can do for JSPs". They decided that any pattern that began with "/servlet" should invoke this magical process, and they decided that what appeared after the "/servlet" part should be the class name of the servlet to invoke. Lots of other people agreed with this idea, and so eventually it became convention for servlet containers to offer this "/servlet" mapping, just like the specification allows for an implicit "*.jsp" mapping. The part of the spec that made the "/servlet" mapping possible? The part that is quoted above... but we'll repeat it here:
A servlet container is allowed to make other implicit mappings as long as explicit mappings take precedence.
Somewhere around line 60 of an unmodified conf/web.xml file, you'll find:
But look... it's commented out! WHY? Because after a while, some of the bad things about using this 'lazy' way of invoking servlets began to outweight the benefits of using explicit mappings. And since it was never part of the spec, it was easy enough to remove. But of course, almost nothing actually gets deleted these days, so there it still is, around line 275, commented out. So if you really wanted to, just like in the 'Short' version of this story, you can uncomment the mapping, restart Tomcat, and be back in the 'bad old days'.
Why the Invoker is Evil
In case you wonder, it's not just the author of this wiki page that thinks so. There are Tomcat committers that feel the same way, and it's even in the Tomcat faq ! http://wiki.apache.org/tomcat/FAQ/Miscellaneous#Q3
Here then, are some of their reasons, plus a few others...
A very cool part of server-side java applications is that you can declaratively protect access to certain areas of your web application, in web.xml. It's beyond the topic of this FAQ, but basically, you can map URL patterns to security constraints, forcing people to login before they can access the functionality. But you can't do this if all of your servlets look the same. Which they all would, if they were all invoked through an invoker servlet. They'd all start with /servlet/* !!
Just like no security... you can't filter selected servlets, you'd have to filter everything.
Servlets might require a few different startup parameters, like file paths, or jdbc URLs. If you don't map your servlets, you can't take advantage of the <init-param> tags. Your only choice would be to hard-code, or use the more global <env-entry>
They now have a fairly good idea of your package layout. They'd be able to indiscriminately spoof a call to any servlet in any of your packages if you had the invoker enabled (and they stumbled on to an actual class name). Maybe this wouldn't be a disaster. On the other hand, do you want to stake your job or reputation on it?