Examining payloads of all requests to the server - java

I have a Java based server application using maven for dependency management and a tomcat server to host it. I have a bunch of IoT devices sending different kinds of payloads all the time. Please note the payloads vary in sizes from 1 MB to 80 MB. So, I want to track the usage of data by each device.
Instead of writing payload size checks at every single API, can I write a filter or interceptor to examine payloads for all API requests? Also, if the payload is higher than 80 MB I want to reject the payload.
Please let me know if there's anyway to accomplish this.

You can do this with a Filter, something like this:
public class PayLoadCheckFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
if (request.getContentLength() > 80e+07) {
((HttpServletResponse) response).setStatus(503);
}
else {
filterChain.doFilter(request, response);
}
}
#Override
public void destroy() {
}
See here for how to add the filter to the web.xml.

Related

SlingServletFilter: Get status code before doFilter

I'm trying to make unexisting pages under my domain go to a 404 page. I need to distinguish 404 pages from the other pages. However, I do not know how to do this. And the thing below is not working.
#Component(service = Filter.class,
property = {
"service.ranking=" + Integer.MIN_VALUE})
#SlingServletFilter(scope = {SlingServletFilterScope.REQUEST},
pattern = "/content/foo/.*",
resourceTypes = "cq:Page",
extensions = {"html"},
methods = {"GET"})
public class NotFoundFilter implements Filter {
private static final String DEFAULT_METHOD = "GET";
#Reference
private UrlOperationsManager urlOperationsManager;
#Reference
private RequestResponseFactory requestResponseFactory;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!(request instanceof SlingHttpServletRequest) ||
!(response instanceof SlingHttpServletResponse)) {
chain.doFilter(request, response);
return;
}
SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;
//this condition here is not working since slingResponse has no getStatusCode method.
if(slingResponse.getStatusCode() == 404) {
//do something
}
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
}
You could work around this by implementing your own HttpServletResponseWrapper to save the value and access it later. The Sling implementation is marginally different (at least as far as this particular mechanic is concerned) from the generic Servlet API, which is covered in depth in How can I get the HTTP status code out of a ServletResponse in a ServletFilter?
However, if your intention is to serve a particular error document for a given status code, I'd approach it differently. Assuming you use a Dispatcher, you could have the web server take care of it.
The official AEM project archetype comes with a few simple examples that you could enable if you use Apache. The details will depend on your site structure but the gist is that it's possible to provide a similar configuration using the ErrorDocument directive to point to a cached error page relative to the document root, usually making it use content-editable error pages.
Some errors, especially HTTP 5** family could be a bit more tricky that way in that they usually happen when there's something wrong with AEM itself so it's prudent to make sure a fully static version is always available.

How to determine if the request is NOT the initial request in a Filter?

What I am trying to do is the following:
Modify the logback to write out the users id and request id on the log lines.
e.g.
2017-11-24 [userid:abcd123 - requestId:12345679] [ClassA:MethodA1] message...
2017-11-24 [userid:abcd123 - requestId:12345679] [ClassA:MethodA2] message...
2017-11-24 [userid:abcd123 - requestId:12345679] [ClassB:MethodB1] message...
Notice that the requestId remains the same as it is all part of one request made to the system by the end user.
I have created a Filter based off of several examples where it shows how to set values into the MDC. e.g.(https://logback.qos.ch/manual/mdc.html1)
...
#Component
public class RequestFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
String mdcData = String.format("[userId:%s | requestId:%s] ", user(), requestId());
MDC.put("mdcData", mdcData); //Referenced from logging configuration.
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
private String requestId() {
return UUID.randomUUID().toString();
}
private String user() {
return "tux";
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
...
If I make a request to a rest service it executes one time without the system making any additional requests to itself for information. This is what I had expected and a I can see the log entries where they all contain the same requestId.
If I make a browser page request to one of our Swagger pages then the web page makes multiple internal requests for additional information that will appear on the page. The logging captures about 20 requests made by the loading of the web page request due to all of the additional requests for information that the page needs to render. When this occurs then I end up with X number of log entries where each of the internal requests are generating a unique request and requestId gets logged for each of them. This was not my intention.
HOW do I determine with a request to the system the initiating portion over the internal request calls that are created?
I need to not set the MDC values for the requestId over and over. I only need it set once per call based on the first request that gets made from the external user.
Not even sure what you would call this other than lifecycle of a request but I'm not finding the answer.
Appreciate any guidance. Thanks.
EDIT: Link to another question I have out there that is only dealing with identifying the original user request.
One way to address this is to map you RequestFilter to the URL pattern of your services that you want to log and not to "/*".
EDIT: Another idea would be to map the filter to "/*" but in your doFilter method, do not MDC any requests that contain "swagger" in the URL. You might have to experiment and possibly include all the URL's that get generated from the Swagger page, as some may not contain the word "swagger" in them.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (isRequestSwaggerUrl(request)) {
chain.doFilter(request, response);
return;
}
try {
String mdcData = String.format("[userId:%s | requestId:%s] ", user(), requestId());
MDC.put("mdcData", mdcData); //Referenced from logging configuration.
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}

Can a servlet filter distinguish between and filter out unauthorized POST, GET, DELETE, etc. requests?

We have some REST endpoints (e.g., /getalleuropeancars or /getalljapanesecars or /getallamericancars). These endpoints are all GET only.
Right now, each annotated endpoint class has its own code for checking for unauthorized methods (which is everything except GET). We would like one class to handle all unauthorized methods; you know, code re-use and all that.
Will a filter be able to distinguish between "GET /getalleuropeancars" and "POST /getalleuropeancars" and "DELETE /getalleuropeancars" and redirect to the proper place? Looking at servlet filters, it seems that they can only detect different URL paths, not different HTTP methods.
<url-pattern>/getalleuropeancars</url-pattern>
<url-pattern>/getalljapanesecars</url-pattern>
<url-pattern>/getallamericancars</url-pattern>
So, is a servlet-filter what we need?
Yes a Servlet Filter can do it. There are two things here, one is mapping the Filter to all the paths (url-patterns) you want it to filter. Second is to have it filter out the non-GET methods. Below is the code of a Filter that filters out non-GET requests. Jus fill in the //return error with your own code for returning an error.
public class OnlyGetsFilter implements Filter {
#Override
public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) throws IOException, ServletException {
HttpServletRequest hsr = (HttpServletRequest) sr;
if (!"GET".equals(hsr.getMethod())) {
//return error
} else {
fc.doFilter(sr, sr1);
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig fc) throws ServletException {
}
}

What is the equivalent of an apache module in java server technology

I have a task to examine incoming HTTP requests and do some processing on the header and request body then store that locally.
If I understand correctly, I can do that with an apache module for Apache servers and an IIS extension for IIS. I'm not clear on what I would use for Java based application servers.
Any help/guidance would be appreciated.
If you will use a Java application server, then you should handle this in a Servlet Filter. Here's an example:
#WebFilter("/app/*")
public class LoginFilter implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
//Set init params and load any resources to be used in this class.
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
//Here you will pre and post process the request-response cycle.
//Pre process is before executing "chain.doFilter(req, res);"
//Post process is after executing "chain.doFilter(req, res);"
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
String someRequestHeader = request.getHeader("<header-you-want-or-need>");
//do what you need to do
chain.doFilter(req, res);
}
#Override
public void destroy() {
//Close/free any resources used in this class.
}
}
More info:
The Java EE 7 Tutorial. 17 Java Servlet Technology. 17.6 Filtering Requests and Responses
Maybe you could use a HttpServlet.
Also have a look at the tutorial.

Is there a way to check if I'm inside a servlet request with Guice?

I'm writing a JUL logging Handler and I'd like to augment the logged messages with information about the current request, if we're currently handling a request. To accomplish this, I've injected a Provider<Thing> into the Handler, where Thing is #RequestScoped.
However, calling provider.get() throws an OutOfScopeException if the logging happens while we're not handling a request. I feel like catching the OutOfScopeException would be bad form. Is there a better way to determine whether or not a request is currently executing?
With wicket I used a little trick. This should be framework independent. I made a request filter and put a public static ThreadLocal in it. So if current thread is born from request, threadlocal will be set.
public class SessionContext implements Filter {
private static final ThreadLocal<HttpSession> session = new ThreadLocal<HttpSession>();
#Override
public void init(FilterConfig filterConfig) throws ServletException {
return;
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
session.set(((HttpServletRequest)servletRequest).getSession());
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
return;
}
public static HttpSession getSession(){
return session.get();
}
public static User getUser(){
return (User) session.get().getAttribute(UserService.USER);
}
}
and in web.xml:
<filter>
<filter-name>session</filter-name>
<filter-class>SessionContext</filter-class>
</filter>
As far as I know, there is no elegant way to do this. The Guice API is tight and will not grant access to the thread-local needed to make such a test. As of version 3, the thread-local in question sits on com.google.inject.servlet.GuiceFilter#localContext. You could access it by reflection but it is arguably even worse style than catching the exception.
I would stick on caching the exception... or hack into that class and add an static boolean test method.

Categories

Resources