JavaRanch Home    
 
This page:         last edited 20 July 2011         What's Changed?         Edit

Invoker Servlet   

The Long and Sordid Tale of the Invoker Servlet



New

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 mapping for the invoker servlet -->
<!--
    <servlet-mapping>
        <servlet-name>invoker</servlet-name>
        <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
-->
You need to uncomment the servlet-mapping and then restart Tomcat. Your application should work now. This is not recommended, and you should at least read the next section

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:


<form action="/servlet/full.class.name">
</form>

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:


...
<servlet>
    <servlet-name>HelloWorld</servlet-name>
    <servlet-class>your.package.name.HelloWorld</servlet-class>
</servlet>
...
<servlet-mapping>
    <servlet-name>HelloWorld</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>
...

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

just /hello

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:


    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>logVerbosityLevel</param-name>
            <param-value>WARNING</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

And then, around line 285:


    <!-- The mapping for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
    </servlet-mapping>

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'

Huh??

Here, read this, at the top of conf/web.xml:
  <!-- ======================== Introduction ============================== -->
  <!-- This document defines default values for *all* web applications      -->
  <!-- loaded into this instance of Tomcat.  As each application is         -->
  <!-- deployed, this file is processed, followed by the                    -->
  <!-- "/WEB-INF/web.xml" deployment descriptor from your own applications. -->

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:
    <servlet>
        <servlet-name>invoker</servlet-name>
        <servlet-class>
          org.apache.catalina.servlets.InvokerServlet
        </servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
And then around line 275:
    <!-- The mapping for the invoker servlet -->
    <!--
    <servlet-mapping>
        <servlet-name>invoker</servlet-name>
        <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
    -->

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...

  • No security!

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/* !!

  • No Filters!

Just like no security... you can't filter selected servlets, you'd have to filter everything.

  • No init parameters!

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>

  • No hiding!
Not often thought of, and perhaps not a huge concern. But what about the following scenario? A hax0r views the source of your web page. They see "/servlet/com.yourcompany.servlets.showproduct" They see another page that has something like: "/servlet/com.yourcompany.servlets.admin.login"

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?

  • Maintenance nightmare!
Imagine you re-package all your servlets. Imagine you rename a servlet. If you've been using the invoker, you'd need to find every servlet and every JSP that included, forwarded, submitted to, redirected to or otherwise referred to that servlet. By providing mappings, you've introduce a layer of indirection; change one setting in web.xml, and nothing else need change!

ServletsFaq

JavaRanchContact us — Copyright © 1998-2014 Paul Wheaton