Filter Liferay HttpRequest - servlets

I would like to filter (modify) HttpRequest, which is coming to target Liferay Servlet, intercept it and add some attributes. (for example User) and then redirect (forward) the request to the target servlet. I create new servlet that should work like interceptor, add the attribute (request.setAttribute("user", User)) and then either dispatcher.forward or response.redirect... This is only for testing purposes to be able to call some liferay functionality from tests.
The problem is that Liferay is filtering the request and add there its 7 attributes. I tried also create SimpleFilter, but its not called when target servlet is called, only when I create my own Servlet which extends HttpServlet.
So the question is, is it possible to tell liferay not to filter the requests or more important not to remove the attributes from the request? I have debugged the Liferay source code, catch the Filter Chain and on the 1. filter I see there original request, and at the end the requests contains those Liferay attributes.
Many thanks.
The target servlet is defined like this:
<servlet>
<servlet-name>targetServlet</servlet-name>
<servlet-class>com.liferay.portal.kernel.servlet.PortalDelegateServlet</servlet-class>
<init-param>
<param-name>servlet-class</param-name>
<param-value>org.springframework.web.context.support.HttpRequestHandlerServlet</param-value>
</init-param>
<init-param>
<param-name>sub-context</param-name>
<param-value>targetServlet</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

Related

Invoke servlet Filters from another servlet

I'm working on a CMS.
My code is inside the doGet() function of a servlet invoked at url "/market". I want a HttpServletRequestWrapper that would pass through all filters set for url "/page".
I expect these filters would update the request, so that an annotation processor could later inject dependencies with correct values.
I'm in a Tomcat server, so I should be able to cast to the right special object, and I don't have to be compliant to other servers.
An associated question is that using req.getRequestDispatcher(path).forward(requestWrapper, responseWrapper);, I was expecting the filters to be invoked. Should they ?
The javadoc says:
This method allows one servlet to do preliminary processing of a
request
Filters are by default mapped on the REQUEST dispatcher only. The below example of a filter mapping
<filter-mapping>
<filter-name>yourFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
is implicitly equivalent to
<filter-mapping>
<filter-name>yourFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
This means, the filter is only triggered on the "raw" incoming request, not on a forwarded request.
There are three more dispatchers: FORWARD, INCLUDE and ERROR. The RequestDispatcher#forward() triggers the FORWARD dispatcher. If you'd like to let your filter hook on that as well, then just add it:
<filter-mapping>
<filter-name>yourFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Note that you need to explicitly specify the REQUEST dispatcher here, otherwise it would assume that you're overriding it altogether and are only interested in FORWARD dispatcher.
Inside the filter, if you'd like to distinguish between a REQUEST and FORWARD, then you can then check that by determining the presence of a request attribute keyed with RequestDispatcher#FORWARD_REQUEST_URI
String forwardRequestURI = (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
if (forwardRequestURI != null) {
// Forward was triggered on the given URI.
}

How to handler HTTP Request with # character in URL

My customer sent one HTTP request with URL http://example.com/callback#id_token=data
Now I need handle this request and get data of "id_token".
Please help me handle this request using Java web project.
I tried with servlet but not get data of "id_token"
My servlet is below
<servlet>
<servlet-name>callback</servlet-name>
<servlet-class>com.admin.controller.CallbackServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>callback</servlet-name>
<url-pattern>/callback</url-pattern>
</servlet-mapping>
Thanks a lot.
Unless url-encoded, the hash #id_token=data usually ends up in document.location.hash on the client side.
console.log(document.location.hash);//#id_token=data
var hash = document.location.hash;
var split = hash.split('=');
console.log(split[0]);//#id_token
console.log(split[1]);//data
You can usually access the console with F12, tab "console".

Handler method mappings with Spring 3.2.6

I'm trying to learn web app development with Spring MVC framework and I'm not completely clear about how controller mappings work. It will be better if I show my config and code first and then explain what I don't understand.
Here's mapping in my web.xml:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
mapping in my controller class:
#Controller
#RequestMapping("/main/courses")
public class CourseController {
...
and mapping of the method in question in this controller:
#RequestMapping(value="", method = RequestMethod.GET)
public String getCourses(Model model) {
...
As you can see, value attribute is set to empty quotes and this is the only way this mapping works. If I change value attribute to "/", I get 404 error. I have other mappings in this controller that work fine, for example value="/add". The only problem is when I try to map to the root of this controller.
Is value="" a valid value? Why value="/" doesn't work?
The #RequestMapping used at the class level sets the base path mapping that all the handlers methods will resolved against.
In your example, that's
#RequestMapping("/main/courses")
When you specify another #RequestMapping on a method like
#RequestMapping("/add")
that is added as a path element. So the request would need to be to
/main/courses/add
If you have another like so
#RequestMapping("/")
then you add a new path element but the element itself is empty. So the request needs to be to
/main/courses/
With a mapping like
#RequestMapping("")
there is no new path element, it's just the empty String. So the request would need to be to
/main/courses

How to map servlet to /*, it fails with infinite loop and eventually StackOverflowError

I would like to map my servlet to /*, but it failed with an infinite loop.
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>my.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
The java code is:
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response){
request.getRequestDispatcher("/WEB-INF/jsps/hello.jsp").forward(request, response);
}
}
If I map to /hello, everything works fine.
As the HelloServlet is mapped to /*, it will also be invoked on RequestDispatcher#forward() and cause the infinite loop.
How is this caused and how can I solve it?
This is not possible. The JSP should actually invoke container's builtin JspServlet. But the /* mapping definied by the webapp has a higher precedence.
You need to map the servlet on a more specific URL pattern like /pages/* and create a servlet filter which forwards non-static requests to that servlet. Yes, non-static requests (image/CSS/JS files) are also covered by /*, but they should not be processed by the servlet at all.
Assuming that you've all static resources in /resources folder, the following should do:
<filter>
<filter-name>filter</filter-name>
<filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>/pages/*</url-pattern>
</servlet-mapping>
With the following in filter's doFilter():
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
if (path.startsWith("/resources")) {
chain.doFilter(request, response); // Goes to container's own default servlet.
} else {
request.getRequestDispatcher("/pages" + uri).forward(request, response); // Goes to controller servlet.
}
This takes place fully transparently without any change to /pages in the URL. The forward to the JSP will not trigger the filter or the servlet. Filters do by default not kick in on forwards and the JSP forward path does not match the controller servlet's URL pattern any more.
Alternatively, if you have your own default servlet implementation, then you could map the servlet to / and let it delegate to the default servlet if the request isn't applicable as a front controller request. This is what Spring MVC is doing under the covers. Creating a default servlet is however not a trivial task as it should be capable of responding to conditional requests, caching requests, streaming requests, resume requests, directory listing requests, etecetera.
See also:
Difference between / and /* in servlet mapping url pattern
How to access static resources when mapping a global front controller servlet on /*
Design Patterns web based applications
This is possible duplicate to Servlet Filter going in infinite loop when FORWARD used in mapping in JSF
Otherwise should check what your JSP contains, it could be that it makes request for css or image files that can result in this behaviour. Also would recommend to try without a wildcard.

How to use Servlet in Struts2

How to use servlets together with Struts2?
I assume you want to know how to use a servlet in conjunction with Struts2 when you have mapped everything to the Struts2 filter.
You can use the following in your struts.xml:
<constant name="struts.action.excludePattern" value="/YourServlet"/>
You can exclude multiple patterns by separating them with a comma, such as:
<constant name="struts.action.excludePattern" value="/YourServlet,/YourOtherServlet"/>
More Information
Filter mapping for everthing to Struts2 besides one servlet?
Filters not working in Struts2
There are three ways to resolve this problem:
add constant tag in struts.xml
<constant name="struts.action.excludePattern" value="/YourServlet,/YourOtherServlet"/>
add suffix in servlet configuration in web.xml
<servlet-mapping>
<servlet-name>Authcode</servlet-name>
<url-pattern>/authcode.servlet</url-pattern>
</servlet-mapping>
Because in struts 2, it will only intercept all the request end with .action, if this request do not have any suffix, it will automatically add it. When we make our servlet url-pattern have a suffix, then struts 2 will not intercept it anymore.
implement a user-defined filter
Servlets technology is more low level architectural layer than Struts2. Even more Struts2 is embedded to your project as a filter (that is part of servlet technology).
So to add one more servlet just add to web.xml registration:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>class.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
If you need multi mapping servlet you can using:
<constant name="struts.action.excludePattern" value="/Servletname1, /Servletname2" />
But in struts, you should not using servlet url because it not unity. You can use ajax:
$.ajax({
url : "nameAction.action?param="+id,
type : "post",
data : {
'id' : id
},
success : function(data) {
// $('#result').html(data);
},
error : function(jqXHR, textStatus, errorThrown) {
$('#result').html("Error");
}
});

Resources