Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between session.getServletContext() and session.getServletContext().getContext("/SampleProject")

I have a Tomcat 6 instance running on my local machine.

I have made the following changes in its configuration:

  • In /conf/context.xml – changed the tag as follows

    <Context crossContext="true">
    
  • In /conf/server.xml – changed the tag as follows

    <Connector port="8080" protocol="HTTP/1.1" emptySessionPath="true"
           connectionTimeout="20000" 
           redirectPort="8443" />
    

Suppose I have a WAR file named SampleProject.war deployed here which extract to folder SampleProject.

In some servlet in this WAR, say SampleServlet, I write two blocks of code as follows :

ServletContext context1 = session.getServletContext();

and

ServletContext context2 = session.getServletContext().getContext("/SampleProject");

What is the difference between context1 and context2? I thought that both refer to the application context. But if I set some attribute in context1 and access in context2, I don't get the value in context2.

Any help would be appreciated.

like image 434
TechSpellBound Avatar asked Mar 26 '13 14:03

TechSpellBound


2 Answers

I feel your question was slightly misunderstood and that you already had the basic understanding of the API i.e. once a web-app sets its crossContext="true" it could use getContext() to get access to a context that corresponds to some other web-app deployed on the server.

getServletContext().getContext() equals NULL unless <Context crossContext="true">

From what I've understood, your question actually is that in /SameWebApp why

ServletContext context1 = session.getServletContext();
context1.setAttribute("contextAttribute", new Object());
ServletContext context2 = session.getServletContext().getContext("/SameWebApp");

System.out.println(context1.equals(context2)); // prints false, or 
System.out.println(context2.getAttribute("contextAttribute")); // prints null (at least they could have been clones)

In just one word, the answer is "Security". Imagine if you couldn't guarantee that an "adminEmail" context attribute has not been tampered with by an evil web-app having its crossContext=true. Your app could potentially help compromise itself as soon as that "Forgot Password" request comes! :)

A Dive into Tomcat internals

Tomcat 7 provides a class ApplicationContext implements ServletContext that returns from getContext("/context-root") as

    if (context.getCrossContext()) {
        // If crossContext is enabled, can always return the context
        return child.getServletContext();
    } else if (child == context) {
        // Can still return the current context
        return context.getServletContext();
    } else {
        // Nothing to return
        return (null);
    }

Here context belongs to current web-app and child represents the other web-app. But, hold on, what makes Tomcat call it a child?

These two actually aren't ApplicationContext but instances of StandardContext a class that implements Context but instead of servlet specific things holds Tomcat specific config settings for a web-app like crossContext, hostname, mimeMappings etc. StandardContext.getParent() gives you the Container and hence it has been referred to as a child above.

Anyways, we're interested in the case when child == context is true i.e. getContext() was called on the "/SameWebApp". The call is being delegated to StandardContext.getServletContext() which has been implemented to return a different instance of ApplicationContext.

This is why the attributes you set in context1 are not found in context2.

But wait, there's some more to it. Why does StandardContext.getServletContext() return like

return (context.getFacade());

A Tomcat instance is basically executing two types of Java code:

  • container provided, and
  • user deployed

The container code is "Trusted" and may need to run with elevated privileges sometimes. The user code, on the other hand, is not trusted and needs to be restricted from compromising Tomcat internals.

One of the things that Tomcat does to achieve this is always wrap an ApplicationContextFacade around the ApplicationContext (and hence the StandardContext as well). So just to recap, what appears to be a simple ServletContext implementation is actually a StandardContext mapped to an ApplicationContext which is then wrapped within an ApplicationContextFacade.

For further information on how the ApplicationContextFacade works using Reflection in tandem with Globals.IS_SECURITY_ENABLED and SecurityUtil.isPackageProtectionEnabled() settings please take a look at Why do Servlets access Tomcat ApplicationContext through a Facade on SO.

References:
Tomcat 7 Source Code (Download Link)

like image 167
Ravi K Thapliyal Avatar answered Nov 01 '22 19:11

Ravi K Thapliyal


Absolutely those two context objects are different from another.. Context1 object gives current web application servlet context obj. ( ServletContext context1 = session.getServletContext();)

and

context2 object gives the servletcontext obj of specified web application (ServletContext context2 = session.getServletContext().getContext("/SampleProject");)

you are setting object in one context and trying to retrieve using another context, so it is not possible to get attribute from another web application context by putting it in current application context. But you can get attribute resides in another web application context by using second method.

like image 3
Eswar Avatar answered Nov 01 '22 17:11

Eswar