Can a tomcat hosted servlet break out of it's base URL? - java

I've just started writing some java servlets and running them with Tomcat (v7). My understanding of how the directory structure works is that URLs are relative to the name of your application:
So if my app is MyWebApp then by visiting http://server/MyWebApp I'll see, for example, the "index.jsp" file I created in the root directory of my web app.
If said index.jsp has a form with POSTs to "submit" then the broswer will send to http://server/MyWebApp/submit
And in my web.xml file I can point a class which extends HttpServlet to handle this POST request. Something like:
<servlet>
<servlet-name>MyHandler</servlet-name>
<servlet-class>org.me.handler</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyHandler</servlet-name>
<url-pattern>/submit</url-pattern>
</servlet-mapping>
However, suppose my form POSTs to "/submit". Then the browser sends the request to http://server/submit
I don't see any way to intercept this from my web app.
One approach is just to deploy my web app as the ROOT. Is there another approach?

Each web application in servlet container has a context path. It can only receive requests below the context path. For good reasons there is no way to "break out" of its context path (except if the servlet container has a bug).
A servlet mapping is always to be seen as relative to the context path.
You can deploy web applications as root, i.e. with context path "/". See here how to do this for Tomcat.
When your pages contain URLs to the server (href-, src-, action-attributes, etc.) you basically have two options:
Use a relative URL. E.g. the form in your example could simply have action="submit" which is turned into an absolute URL by the browser.
Use absolute URLs. Since (if) you don't want that your application is dependent on a fixed content path, you therefore should (need) to dynamically generate your pages and prefix those URLs with the actual context path.

Related

Tomcat - Click on Web Service gets "The requested resource is not available"

I am newbie for Java web services and tomcat.
I didn't find a specific answer, so I am trying...
I have built a war to deploy on a tomcat 8.0.28 server on windows (and later on Solaris)
On the "Tomcat Web Application Manager" I can see my webapp listed among the applications list and I see that it's "running" status is "true". (see image)
Doesn't it mean that the service is up and running?
I have two problems, which probably relate:
When I click on the application link on the Tomcat Web Application Manager, it gives me 404 error. Is it logical? Why is that?
On the WAR project I have a main method, in which I create a file. I can't find it, so I assume, it was never called. I guess it relates to the previous matter...
My suspicion is that I didn't configure the address well somewhere. I will try to pass here all the data that I think is relevant:
The application path, as it is shown in the "Tomcat Web Application Manager" is /CcgwServerWsCxf.
The display name as it is shown in the "Tomcat Web Application Manager" is CcgwCallbackWsServerWAR.
The servlet part in web.xml is as follows:
<servlet>
<servlet-name>CcgwCallbackServlet</servlet-name>
<servlet-class>com.mycomp.ta.load.CcgwCallbackServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CcgwCallbackServlet</servlet-name>
<url-pattern>/CCGWCallback/*</url-pattern>
</servlet-mapping>
This is my code in the port server class constructor:
System.out.println("Starting Server");
Object implementor = new CCGWCallbackPortTypeImpl();
String address = "http://192.168.5.106:1234/CCGWCallback/CallbackServer";
Endpoint.publish(address, implementor);
(1234 is my tomcat port)
The service address that I send to the client so it can send my notification messages back is:
http://192.168.5.106:1234/CCGWCallback/CallbackServer
The Serivce QName is
new QName("http://teleconference.mycompany.com/CCGW", "CCGWService");
I hope that I gave all the data.
Can you please help?
Thank you.
The context path of your application is /CcgwServerWsCxf and your servlet is mapped to /CCGWCallback/* (relative to the context path).
Any request with path below /CcgwServerWsCx is routed to your application.
But only requests with a path below /CcgwServerWsCx/CCGWCallback hit your servlet.
Therefore Tomcat responds with a 404 when you call /CcgwServerWsCxf (e.g. the hyperlink in the manager app).
You should call /CcgwServerWsCx/CCGWCallback and verify that your servlet is invoked.
Also you need to make sure that any client also uses the correct paths. For instance the URL http://192.168.5.106:1234/CCGWCallback/CallbackServer should probably be http://192.168.5.106:1234/CcgwServerWsCx/CCGWCallback/CallbackServer given your current Tomcat config.

Java Servlet - Mapping a servlet to every URL but a string

I have a servlet configured to handle all URLs (*):
<servlet>
<servlet-name>MyServ</servlet-name>
<servlet-class>MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServ</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
I need that for URLS beginning with /static/, it should serve them from the static WEB-INF. That is, MyServ should serve everything but /static.
How can I do that?
UPDATE: To clarify, what I'd like is:
/*/ - Goes to MyServ
/static/dir/file.css - Jetty serves the static file.css from the /dir/.
I'm not sure what web.xml to do, or where to put the static files.
I tried adding this:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
But, when I go to a /static/ URL, I just get:
HTTP ERROR 404
Problem accessing /static/dir/file.css. Reason:
Not Found
Powered by Jetty://
I'm not sure if my web.xml is wrong, or if I'm simply putting the files in the wrong place (I've tried under src/main/webapp and src/main/webapp/lib/META-INF/resources/)
Jetty
I am using Jetty. I want to avoid any other layers, such as Nginx, Apache, etc.
To win the bounty, please make sure you answer works for Jetty.
Your best bet is probably to have a rule for static that occurs before the rule for *.
Rule for URL path mapping:
It is used in the following order. First successful match is used with no further attempts.
The container will try to find an exact match of the path of the request to the path of the servlet. A successful match selects the servlet.
The container will recursively try to match the longest path-prefix. This is done by stepping down the path tree a directory at a time, using the ’/’ character as a path separator. The longest match determines the servlet selected.
If the last segment in the URL path contains an extension (e.g. .jsp), the servlet container will try to match a servlet that handles requests for the extension. An extension is defined as the part of the last segment after the last ’.’ character.
If neither of the previous three rules result in a servlet match, the container will attempt to serve content appropriate for the resource requested. If a “default” servlet is defined for the application, it will be used.
So it will match the rule for /static/, and stop there.
Your problem can by solved using the Nginx. Nginx serves static content HTML files, images (.jpg, .png, .gif), stylesheets (.css) and JavaScript (.js). These files need not to be processed by the web server. Nginx will do this job.
server {
listen 80;
server_name YOUR_DOMAIN;
root /PATH/TO/YOUR/WEB/APPLICATION;
location / {
index index.jsp;
}
location ~ \.jsp$ {
proxy_pass http://localhost:8080;
}
location ^~/servlets/* {
proxy_pass http://localhost:8080;
}
}
To serve static content you dont even need to have a servlet. You can put your static content in a folder which is directly accessible through your server.
For example if your application name is TestApp than you can place your content in TestApp/static/dir directory. Based on that your directory structure would be :
TestApp
|
|_____ WEB-INF
|
|_____ static
|
|____ dir
By doing above directory structure all your static content e.g. Sample.css will be accessible through below URL:
/TestApp/static/dir/Sample.css
Please look at this question for more information How to serve static content from tomcat
Note that by doing this your static directory will be open to everyone without any restriction which means anyone will be able to access your static content without any authentication. But as its your static content I guess its fine unless you have any reason for it.
First, files that are located in "WEB-INF" directory aren't directly web accessible.
Also, I noticed that your entry "src/main/webapp/lib/META-INF/resources/" does not include a extracted WAR directory, aka web application folder.
Example:
src/main/webapp/[WAR folder]/lib/META-INF/resources/
I assumed that you are using Tomcat. So, after you create your WAR file drop it into "webapp" directory, then start Tomcat. The WAR file should extract into a web application folder of the same name as the WAR file. Now from a browser you should has access to any files outside of "WEB-INF".
example: localhost:8080/[web app folder name]/[some file]
Hope this helps,
Simply put your static content into webapp Directory.
That part can be directly access. using localhost:port/yourAppName/ResourceName
Based on my experience (as already suggested by Srinivasu Talluri), reverse proxy is the answer to your problem.
You could use Nginx See detail configuration or configure Apache to work as reverse proxy.
Detail configuration for serving static content thru Nginx could be find here
When static contents will be handled by the web server itself, then your servlet configuration could be used as is. Thus your servlet will serve only the dynamic resources.
Hope it helps.

How to access my web application with and without / at the end of the URL

In my opinion I have a very simple problem, but I am not able to figure out a working solution.
I have been following web.xml
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/article/*</url-pattern>
</servlet-mapping>
If I access my web application from following url http://localhost/article everthing works fine. If I add a slash at the end, the application run into an ifinitie loop.
I knew this is produced by the getRequestDispatcher("index.jsp").forward(req, resp) call and the web.xml configuration entry /article/*.
If I change index.jsp to /index.jsp, I get forwarded correctly, but all resources are sill mapped to the wrong path. For example, the css files are mapped to article/css instead of css. I think this happens because the getRequestDispatcher, keeps the contextPath.
The index.jsp is placed in the root directory.
How could I access http://localhost/article and http://localhost/article/?
I assume that:
the static resources are relative to the JSP on your file system
the URLs are relative
The browser is going to resolve relative URLs relative to the current URL. You can use the application's context path to provide the correct path:
<link rel="stylesheet"
href="${pageContext.servletContext.contextPath}/css/foo.css">
Now it doesn't matter what the request URL is or what the application context path is; the links will be resolved correctly.
The expression is a bit verbose but you could always shorten it with an application-scoped copy of the string.

Jetty not routing to servlet when web application in sub directory of webapps

I have a web application that is functioning properly (servlets called) when I place the application folder in the {JETTY_HOME}/webapps directory.
If I place a copy of the web application in a sub folder of webapps, then all the static files are called when I browse to the site, but the servlets that I call via ajax are returning 404.
http://localhost/shlaa
calls /shlaa/CommentController.do correctly with no error.
http://localhost/mapapp/shlaa
returns 404 for the ajax call /mapapp/shlaa/CommentController.do
web.xml in both paths /WEB_INF folders contains the following
<servlet>
<servlet-name>CommentController</servlet-name>
<servlet-class>web.CommentController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CommentController</servlet-name>
<url-pattern>/CommentController.do</url-pattern>
</servlet-mapping>
The jetty.xml folder in {JETTY_HOME}/etc contains the following:
<Call class="org.mortbay.jetty.webapp.WebAppContext" name="addWebApplications">
<Arg><Ref id="contexts"/></Arg>
<Arg><SystemProperty name="jetty.home" default="."/>/webapps</Arg>
<Arg><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Arg>
<Arg type="boolean">True</Arg> <!-- extract -->
<Arg type="boolean">True</Arg> <!-- parent priority class loading -->
</Call>
In order to correctly deploy Java Web application to some Application Server or just simple Web Container (like in your case), the web app (also called web module) MUST have a specific structure. The top-level directory of a web module is the document root of the application.
Here is a Web Module Structure:
Now, what you define in <url-pattern> in web.xml file it is just a logical / virtual path for some servlet. Again, it is NOT a real path to the physical location of the servlet class, but a logical path - you make it up as you wish.
OK, now you must put your webapp with the right structure right in the webapps directory. For example, in the above picture Assembly Root symbolizes your webapp folder. So you take that folder either directly or you can make a WAR (Web application ARchive) and put it right under webapps directory. It's not that in webapps you have some directory and in that direcory there are several webapps. All web apps must be right under webapps directory.
So in your case, if your webapp folder has a name shlaa, you must put that folder right under webapp. Period.
Now quote from the official Java EE docs:
Mapping URLs to Web Components
When it receives a request, the web container must determine which web
component should handle the request. The web container does so by
mapping the URL path contained in the request to a web application and
a web component. A URL path contains the context root and, optionally,
alias:
http://host:port/context-root/alias
Setting the Component Alias
The alias identifies the web component that should handle a request.
The alias path must start with a forward slash (/) and end with a
string or a wildcard expression with an extension (for example,
*.jsp). Since web containers automatically map an alias that ends with *.jsp, you do not have to specify an alias for a JSP page unless you wish to refer to the page by a name other than its file name.
In your case, the URL to your webapp will be
http://localhost:8080/shlaa
Now qoute from the Jetty wiki docs (Jetty/Howto/SetContextPathto):
Using the WebAppProvider
The WebAppProvider's role is to look in the ${jetty.home}/webapps/
directory for any deployable applications (such as *.war), and deploy
them onto a context of the same name as the filename. For example, the
WebAppProvider deploys ${jetty.home}/webapps/MyApp-2.4.war into the
context /MyApp-2.4. There is also the special root.war reserved word
that deploys into the context / . While this is the easiest deployment
mechanism, it sacrifices control over deployment specifics.
To make the long story short just place your web app right under webapps directory to make everything work.
As for the <url-pattern> - feel free to define whatever patter you like.
NOTE: actually the are several ways to configure Jetty, i.e. XML configuration is not the only one. See Configuring Jetty for the details.
Quote from The Java™ Servlet SpecificationVersion 3.0:
Chapter 12 Mapping Requests to Servlets 12.1 Use
of URL Paths Upon receipt of a client request, the Web container
determines the Web application to which to forward it. The Web
application selected must have the longest context path that matches
the start of the request URL. The matched part of the URL is the
context path when mapping to servlets. The Web container next must
locate the servlet to process the request using the path mapping
procedure described below. The path used for mapping to a servlet is
the request URL from the request object minus the context path and the
path parameters. The URL path mapping rules below are used in order.
The first successful match is used with no further matches attempted:
The container will try to find an exact match of the path of the request to the path of the servlet. A successful match selects the
servlet.
The container will recursively try to match the longest path-prefix. This is done by stepping down the path tree a directory
at a time, using the ’/’ character as a path separator. The longest
match determines the servlet selected.
If the last segment in the URL path contains an extension (e.g. .jsp), the servlet container will try to match a servlet that handles
requests for the extension. An extension is defined as the part of the
last segment after the last ’.’ character.
If neither of the previous three rules result in a servlet match, the container will attempt to serve content appropriate for the
resource requested. If a "default" servlet is defined for the
application, it will be used. Many containers provide an implicit
default servlet for serving content. The container must use
case-sensitive string comparisons for matching.
12.2 Specification of Mappings
In the Web application deployment descriptor, the following syntax is used to define mappings:
A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for
path mapping.
A string beginning with a ‘*.’ prefix is used as an extension mapping.
The empty string ("") is a special URL pattern that exactly maps to the
application's context root, i.e., requests of the form http://host:port/<contextroot>/.
In this case the path info is ’/’ and the servlet path and context path is
empty string (““).
A string containing only the ’/’ character indicates the "default" servlet of the
application. In this case the servlet path is the request URI minus the context path
and the path info is null.
All other strings are used for exact matches only.
Example with your names.
Your webapp name is mapapp (it's the application root). You want your CommentController.do to be accessed via
http://localhost:8080/mapapp/shlaa/CommentController.do
Then (if all other requiremants like directory structure etc are met) in your web.xml you put the following:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>Comment Controller</servlet-name>
<servlet-class>com.example.CommentController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Comment Controller</servlet-name>
<url-pattern>/shlaa/CommentController.do</url-pattern>
</servlet-mapping>
</web-app>
The first forward slash (/) in the above url-pattern symbolizes context root / context path (mapapp in this case).
This way it will work.
Here are some usefull links.
The Java EE 5 Tutorial:
Web
Modules
Configuring Web
Applications
The Java EE 6 Tutorial:
Web Modules
Configuring Web
Applications
Jetty
Deploying Web
Applications
Jetty Documentaion Wiki
Hope this will help you.
UPDATE
For the Jetty specific configuration see this link:
How to have a web app respond only on a specific port
Here's what I think is happening.
Just cloning your application shlaa in both the webapps root and the webapps/mapapp will not clone your servlets to a new location.
The static content works because those files are actually present at that location and Jetty will serve them given the right location
For servlets, the server will recognize only one location, the one inside shlaa/web/WEB-INF/classes
(since you cloned your app, I assume your clone will be something like shla/mapapp/web/WEB-INF/classes)
What you have to do is just modify your web.xml so that shlaa/mapapp is also recognized
e.g : (try some combination of below)
<servlet-mapping>
<servlet-name>CommentController</servlet-name>
<url-pattern>/mapapp/CommentController.do</url-pattern>
</servlet-mapping>

Jnlp-Prevent downloading of the jars that i referenced

I have been developed a jnlp file, and it is working properly when client downloads it from his/her browser. No problem up to here, but client can also access to the jar files that my jnlp is referencing, and eventually download them.
I don't want my jars to be downloaded by others by writing the path from browser. I just want to make the jnlp is directly accessible from browser.
How can I fix this situation ?
There is no 'fix' for it. If the Jars are accessible to the JWS client that launches the app., they are also available by direct fetch.
You can use the provided JnlpDownloadServlet as a way to block access. The JnlpDownloadServlet (look for it in the samples provided with the JDK) will handle requests for Jar files and do a diff on them. If you setup your web.xml file like
<servlet>
<servlet-name>JnlpDownloadServlet</servlet-name>
<servlet-class>com.sun.javaws.servlet.JnlpDownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>JnlpDownloadServlet</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
then all requests for the files in /app will go through this servlet. This will prevent users from doing a simple browse to see the available files, but if they know the file name they can still create a get request to fetch it through the servlet.
If that is a problem, then you can also put security on access to this servlet (as you would any other servlet) using the security-constraint settings in the web.xml. If you add that, then the javaws launcher will require the user to provide valid credentials before it will download the files. I used BASIC as the auth-method because I wasn't sure if the javaws client would honor any others.
What if you generate the jnlp dynamically via a JSP or servlet (see here an example)?
In this case you can write a filter that can implement a policy(based on a cookie?) for retrieving files. If the cookie is not set you can disable the download of jars.
See the following article: http://lopica.sourceforge.net/faq.html#cookies

Categories