How to prevent static resources from being handled by front controller servlet which is mapped on /* - servlets

I have a servlet which acts as a front controller.
#WebServlet("/*")
However, this also handles CSS and image files. How can I prevent this?

You have 2 options:
Use a more specific URL pattern such as /app/* or *.do and then let all your page requests match this URL pattern. See also Design Patterns web based applications
The same as 1, but you want to hide the servlet mapping from the request URL; you should then put all static resources in a common folder such as /static or /resources and create a filter which checks if the request URL doesn't match it and then forward to the servlet. Here's an example which assumes that your controller servlet is a #WebServlet("/app/*") and that the filter is a #WebFilter("/*") and that all your static resources are in /resources folder.
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
if (path.startsWith("/resources/")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/app" + path).forward(request, response); // Goes to your controller.
}
See also How to access static resources when mapping a global front controller servlet on /*.

I know this is an old question and I guess #BalusC 's answer probably works fine. But I couldn't modify the URL for the JSF app am working on, so I simply just check for the path and return if it is to static resources:
String path = request.getRequestURI().substring(request.getContextPath().length());
if (path.contains("/resources/")) {
return;
}
This works fine for me.

Related

.Net core Routing URLEncoded URL not working

I have a .Net core 2.2 WebAPI that works perfectly fine with "normal" style URLs e.g. /api/controller/action/param etc. I have a 3rd party service that does a POST to this API with a URL encoded path and the Asp.Net routing fails to route this request correctly.
The controller is at: .../api/file/uploadFile/{filename}
The POST from the 3rd party is:
".../api%2Ffile%2FuploadFile%2FMaintenanceReport_2019_08_05_17_11_10.html.gz".
Replacing the %2F in the path appears to work as expected:
".../api/file/uploadFile/MaintenanceReport_2019_08_05_17_11_10.html.gz"
The filename is: "MaintenanceReport_2019_08_05_17_11_10.html.gz"
Placing a Route Attribute with %2F instead of "/" sort of works, but looks very messy.
The filename passed into the path is also not resolving correctly as a parameters. I suspect this is due to the file extension being included.
I've searched the net and did not find anything related jumping out at me. Any suggestions/ideas?
[Route("api/[controller]/[action]")]
[Route("api%2F[controller]%2F[action]")]
public class FileController : Controller
{
...
}
I would have thought that the .Net core routing engine would detect the path
The default path separator in the url generated by the route is / .The issue seems that the separator before the parameter which is as part of the path value is not recognized or missing .
If you request the url like .../api%2Ffile%2FuploadFile%2FMaintenanceReport_2019_08_05_17_11_10.html.gz , you could try to use URL Rewriting Middleware like below :
In Configure
app.UseRewriter(new RewriteOptions()
.Add(RewriteRouteRules.ReWriteRequests)
);
2.Custom a class containing ReWriteRequests
public class RewriteRouteRules
{
public static void ReWriteRequests(RewriteContext context)
{
var request = context.HttpContext.Request;
if (request.Path.Value.Contains("%2F", StringComparison.OrdinalIgnoreCase))
{
context.HttpContext.Request.Path = context.HttpContext.Request.Path.Value.Replace("%2F", "/");
}
}
}
Reference: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-2.1&tabs=aspnetcore2x

AEM Servlet not getting executed

I have a servlet with OSGI annotation like below
#Component( immediate = true, service = Servlet.class, property = { "sling.servlet.extensions=json",
"sling.servlet.paths=/example/search", "sling.servlet.methods=get" } )
public class SearchSevrlet
extends SlingSafeMethodsServlet {
#Override
protected void doGet( final SlingHttpServletRequest req, final SlingHttpServletResponse resp )
throws ServletException, IOException {
log.info("This is not getting called ");
}
}
But When i try to hit the servlet with JQuery
$.get( "/example/search.json", function( data ) {
$( ".result" ).html( data );
alert( "Load was performed." );
});
I am getting below information rather than servlet getting executed.
{"sling:resourceSuperType":"sling/bundle/resource","servletClass":"com.group.aem.example.servlet.SearchSevrlet","sling:resourceType":"/example/search.servlet","servletName":"com.group.aem.example.servlet.SearchSevrlet"}
Please let me know if i need to make any other configuration.
The info that you are getting is the answer of the Default JSON Servlet
Please read this: Servlets and Scripts
You are registering the "SearchServlet" with the property "sling.servlet.paths". This property is defined as:
sling.servlet.paths: A list of absolute paths under which the servlet is accessible as a Resource. The property value must either be a single String, an array of Strings...
That means that your servlet will be only triggered if you request the same exact path, in this case "/example/search", like this:
GET /example/search
I would recommend you to use the properties "resourceTypes" and "selectors" in your Servlet rather than "paths". For example, a better configuration could be:
property = {
"sling.servlet.resourceTypes=/example/search.servlet",
"sling.servlet.selectors=searchselector",
"sling.servlet.extensions=json",
"sling.servlet.methods=GET"
}
With this config, your SearchServlet should be triggered with a GET request to a resource with resourceType="/example/search.servlet", with the selector "searchselector" and the extension "json". For example:
GET /corcoran/search.searchselector.json
I had a similar problem with yours.
To find out what is wrong, I checked "Recent Requests" page.
(at http://localhost:4502/system/console/requests.)
In my case, there was a log saying, "Will not look for a servlet at (my request path) as it is not in the list of allowed paths".
So I moved to "Config Manager" page(at http://localhost:4502/system/console/configMgr), and searched for "Apache Sling Servlet/Script Resolver and Error Handler".
It has a list named "Execution Paths", and I added my request path to the list.
After adding my path to the list, the problem is solved.

WebServlet url-pattern ending by /jsfinspector

I'd like to map a servlet for every url ending with "/jsfinspector". For example:
http://localhost/myapp/pages/somewhere/jsfinspector
http://localhost/myapp/jsfinspector
Is it possible to do that? In a very simple way, without declaring all possible url patterns in web.xml?
The Servlet API doesn't support that.
Your best bet is creating a #WebFilter("/*") which forwards to #WebServlet("/jsfinspector") when the URL matches, as shown below:
if (request.getRequestURI().endsWith("/jsfinspector")) {
request.getRequestDispatcher("/jsfinspector").forward(request, response);
} else {
chain.doFilter(request, response);
}
You can if necessary extract the original request URI in servlet as below:
String originalRequestURI = (String) request.getAttribute(RequestDispachter.FORWARD_REQUEST_URI);
You could think about creating a filter to intercept every request and eventually redirect the flow. https://docs.oracle.com/javaee/6/tutorial/doc/bnagb.html

subdomain CORS in webApi 2

I am using WebApi like I've learnt from http://t.co/mt9wIL8gLA
It all works well if I know exactly the perfect origin URI of my client's requests.
Too bad I am writing an enterprise-wide API, so my request to, say
http://apps.contoso.com/myApp/api/foobar
may come from apps all over my domain, say:
http://apps.contoso.com/CRMApp
http://apps.contoso.com/XYZ
http://www.contoso.com/LegacyApp
http://test.contoso.com/newApps/WowApp
...
and all the new apps my enterprise builds.
What is the best way to approach this? using Origins="*" is cheesy, adding origins to my WS source and redeploy is cheesier.
My current solution is writing a custom CorsPolicyAttribute like in http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#cors-policy-providers
and read the allowed origins from appsettings in web.config.
A LITTLE better could be, inside the custom attribute, checking if the request Origin: header is from contoso.com, maybe with a regexp, and add it to allowed origins.
I am wondering if there is a better, more standard, way.
Use a DynamicPolicyProviderFactory. That's what I use...I even posted a question about it the other day that kind of shows how to add the allowed domains to the web.config file.
I ended up just writing an AuthorizationFilterAttribute, although I might have just done a regular FilterAttribute.
public class FilterReferals : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
var request = actionContext.Request;
if (!AllowedReferers.GetAllowedReferersList().Contains(request.Headers.Referrer?.Host.ToLower()))
{
Challenge(actionContext);
return;
}
base.OnAuthorization(actionContext);
}
void Challenge(HttpActionContext actionContext)
{
var host = actionContext.Request.RequestUri.DnsSafeHost;
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
actionContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", host));
}
}

RequestDispatcher ending in infinite loop

I have two WAR applications and the mode of communication between them is via servlets.
My application (WAR A) opens a child window with the URL of a servlet in another WAR (lets say WAR B).
The servlet (in WAR B) processes the data and should send the processed data back to original application's servlet (i.e WAR A's servlet).
But this process ends in an infinite loop and also the URL parameters sent from WAR-A are null.
Here is the code snippet :
The below script opens a child window with the URL of servlet in WAR-B also passing some URL parameters.
function invokePlugin(invokeURL, custValJSON, meaCompPartJSON) {
window.open(invokeURL + '?custValJSON=' + custValJSON,'');
}
Below is servlet code in WAR-B which extracts the URL parameters and process the data and again send the request back to WAR-A's servlet...
private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String custValJSON = request.getParameter("custValJSON");
System.out.println("custValJSON : " + custValJSON);
CustomValues custVal = gson.fromJson(custValJSON, CustomValues.class);
if(custVal != null) {
System.out.println("Cust val details : " + custVal.getName());
custVal.setValue("Satya");
}
String destination = "/testPlannerPluginResult";
RequestDispatcher reqDispatch = request.getRequestDispatcher(destination);
request.setAttribute("custValJSON", gson.toJson(custVal));
if(reqDispatch != null) {
reqDispatch.forward(request, response);
}
}
Does anybody have idea on this?
Regards,
Satya
That then just means that the servlet is basically calling itself everytime. I don't immediately see the cause in the information given so far, but apparently the URL which you passed into the getRequestDispatcher() matches the URL of the servlet itself.
I however see a major mistake here:
RequestDispatcher reqDispatch = request.getRequestDispatcher(destination);
request.setAttribute("custValJSON", gson.toJson(custVal));
That can impossibly invoke the servlet which runs in another servlet context (read: another WAR). You need ServletContext#getContext() first to get the other servlet context and then use ServletContext#getRequestDispatcher() to dispatch the request to there.
ServletContext otherServletContext = getServletContext().getContext("/otherContextPath");
RequestDispatcher dispatcher = otherServletContext.getRequestDispatcher(destination);
This only requires that the both WARs are configured to expose the context for sharing. On Tomcat for example, this is to be done by adding crossContext="true" to the <Context>.

Resources