2016-11-25 15:42:29 +01:00
|
|
|
package org.gcube.smartgears.managers;
|
|
|
|
|
|
|
|
import static org.gcube.smartgears.Constants.*;
|
|
|
|
import static org.gcube.smartgears.handlers.application.request.RequestError.*;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import javax.servlet.Filter;
|
|
|
|
import javax.servlet.FilterChain;
|
|
|
|
import javax.servlet.FilterConfig;
|
|
|
|
import javax.servlet.ServletException;
|
|
|
|
import javax.servlet.ServletRequest;
|
|
|
|
import javax.servlet.ServletResponse;
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
|
|
import org.gcube.smartgears.configuration.application.Exclude;
|
|
|
|
import org.gcube.smartgears.context.application.ApplicationContext;
|
|
|
|
import org.gcube.smartgears.context.application.DefaultApplicationContext;
|
|
|
|
import org.gcube.smartgears.handlers.application.ApplicationPipeline;
|
|
|
|
import org.gcube.smartgears.handlers.application.RequestEvent;
|
|
|
|
import org.gcube.smartgears.handlers.application.RequestHandler;
|
|
|
|
import org.gcube.smartgears.handlers.application.ResponseEvent;
|
|
|
|
import org.gcube.smartgears.handlers.application.request.RequestError;
|
|
|
|
import org.gcube.smartgears.handlers.application.request.RequestException;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A {@link Filter} that executes a {@link ApplicationPipeline} of {@link RequestHandler}s before and a client request is delivered
|
|
|
|
* to a given servlet and before the response produced by the servlet is returned to the client.
|
|
|
|
*
|
|
|
|
* @author Fabio Simeoni
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public class RequestManager implements Filter {
|
|
|
|
|
|
|
|
private static Logger log = LoggerFactory.getLogger(RequestManager.class);
|
|
|
|
|
|
|
|
private final ApplicationContext context;
|
|
|
|
private final String servlet;
|
|
|
|
private final List<RequestHandler> handlers;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates an instance with the name of the target servlet and a pipeline.
|
|
|
|
*
|
|
|
|
* @param servlet the name of the servlet
|
|
|
|
* @param pipeline the pipeline
|
|
|
|
*/
|
|
|
|
public RequestManager(ApplicationContext context, String servletName, List<RequestHandler> handlers) {
|
|
|
|
this.context = context;
|
|
|
|
this.servlet = servletName;
|
|
|
|
this.handlers = handlers;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
|
|
|
|
ServletException {
|
|
|
|
|
|
|
|
HttpServletRequest httprequest = (HttpServletRequest) request;
|
|
|
|
HttpServletResponse httpresponse = (HttpServletResponse) response;
|
|
|
|
|
|
|
|
List<RequestHandler> filterHandlers = getPipelineWithExcluded(httprequest, handlers);
|
|
|
|
|
2016-11-30 17:27:21 +01:00
|
|
|
if (filterHandlers.isEmpty()){
|
|
|
|
|
|
|
|
log.trace("filtered handlers are empty");
|
|
|
|
|
2016-11-25 15:42:29 +01:00
|
|
|
chain.doFilter(request, response);
|
|
|
|
|
2016-11-30 17:27:21 +01:00
|
|
|
}else {
|
2016-11-25 15:42:29 +01:00
|
|
|
|
|
|
|
ApplicationPipeline<RequestHandler> pipeline = new ApplicationPipeline<RequestHandler>(filterHandlers);
|
|
|
|
|
2016-11-30 17:27:21 +01:00
|
|
|
log.trace("filtered handler for this call are {}", filterHandlers);
|
|
|
|
|
2016-11-25 15:42:29 +01:00
|
|
|
// create a per-request context with temporary properties
|
|
|
|
ApplicationContext ctx = new DefaultApplicationContext(context);
|
|
|
|
|
|
|
|
RequestEvent event = new RequestEvent(servlet, ctx, httprequest,httpresponse);
|
|
|
|
|
|
|
|
try {
|
|
|
|
pipeline.forward(event);
|
|
|
|
}
|
|
|
|
catch(Throwable t) {
|
|
|
|
handleError(httprequest,httpresponse,t);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try{
|
|
|
|
// dispatch to other filters for this servlet
|
|
|
|
chain.doFilter(request, response);
|
|
|
|
}catch(Throwable t){
|
|
|
|
t.printStackTrace();
|
|
|
|
handleError(httprequest,httpresponse,t);
|
|
|
|
}
|
|
|
|
|
|
|
|
ResponseEvent responseEvent = new ResponseEvent(servlet, ctx, httprequest, httpresponse);
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
pipeline.reverse().forward(responseEvent);
|
|
|
|
}
|
|
|
|
catch(Throwable t) {
|
|
|
|
t.printStackTrace();
|
|
|
|
handleError(httprequest,httpresponse,t);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private List<RequestHandler> getPipelineWithExcluded(
|
|
|
|
HttpServletRequest request, List<RequestHandler> handlersToFilter) {
|
|
|
|
|
|
|
|
String query = request.getQueryString();
|
|
|
|
|
|
|
|
log.debug("servletPath is {} and pathInfo is {}",request.getServletPath(), request.getPathInfo());
|
|
|
|
|
|
|
|
if ("wsdl".equals(query) || "wsdl=1".equals(query))
|
|
|
|
return Collections.emptyList();
|
|
|
|
|
|
|
|
String path = request.getServletPath()==null?"":request.getServletPath();
|
|
|
|
|
|
|
|
path += request.getPathInfo() ==null?"":request.getPathInfo();
|
|
|
|
|
|
|
|
|
|
|
|
log.debug("check wich handler should be excluded {}", path);
|
|
|
|
|
|
|
|
for (Exclude exclude : context.configuration().excludes()){
|
|
|
|
String excludePath= exclude.getPath();
|
|
|
|
log.trace("exclude is {}",exclude);
|
|
|
|
if (
|
|
|
|
(EXCLUDE_ALL).equals(exclude) ||
|
|
|
|
(excludePath.endsWith(EXCLUDE_ALL) && path!=null && path.startsWith(excludePath.substring(0,excludePath.length()-2))) ||
|
|
|
|
excludePath.equals(path) || (path.endsWith("/") && excludePath.equals(path.substring(0, path.length()-1)))
|
|
|
|
){
|
|
|
|
//ALL handler are filtered
|
|
|
|
if (exclude.getHandlers().isEmpty()) return Collections.emptyList();
|
2016-11-30 17:27:21 +01:00
|
|
|
|
2016-11-25 15:42:29 +01:00
|
|
|
List<RequestHandler> filteredHandlers = new ArrayList<>();
|
2016-11-30 17:27:21 +01:00
|
|
|
for (RequestHandler rh : handlersToFilter){
|
2016-11-25 15:42:29 +01:00
|
|
|
if (!exclude.getHandlers().contains(rh.getName()))
|
|
|
|
filteredHandlers.add(rh);
|
2016-11-30 17:27:21 +01:00
|
|
|
}
|
2016-11-25 15:42:29 +01:00
|
|
|
return filteredHandlers;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//in case no path is recognized in excludes it return all handlers
|
|
|
|
return handlersToFilter;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void init(FilterConfig filterConfig) throws ServletException {
|
|
|
|
|
|
|
|
// propagate filter initialisation to handler
|
|
|
|
try {
|
|
|
|
|
|
|
|
for (RequestHandler handler : this.handlers)
|
|
|
|
|
|
|
|
handler.start(context);
|
|
|
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
|
|
|
throw new ServletException(t);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void destroy() {
|
|
|
|
|
|
|
|
for (RequestHandler handler : this.handlers)
|
|
|
|
try {
|
|
|
|
|
|
|
|
handler.stop();
|
|
|
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
|
|
|
log.error("cannot terminate handler {} for application {} ", handler, context.name());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// helpers
|
|
|
|
/*
|
|
|
|
private boolean shouldExcludeRequest(HttpServletRequest request) {
|
|
|
|
|
|
|
|
String query = request.getQueryString();
|
|
|
|
|
|
|
|
log.debug("servletPath is {} and pathInfo is {}",request.getServletPath(), request.getPathInfo());
|
|
|
|
|
|
|
|
if ("wsdl".equals(query) || "wsdl=1".equals(query))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
String path = request.getServletPath()==null?"":request.getServletPath();
|
|
|
|
|
|
|
|
path += request.getPathInfo() ==null?"":request.getPathInfo();
|
|
|
|
|
|
|
|
|
|
|
|
log.debug("check if should exclude call with path {}", path);
|
|
|
|
|
|
|
|
for (Exclude exclude : context.configuration().excludes()){
|
|
|
|
if (!exclude.getHandlers().isEmpty()) continue;
|
|
|
|
String excludePath= exclude.getPath();
|
|
|
|
log.trace("exclude is {}",exclude);
|
|
|
|
if (
|
|
|
|
(EXCLUDE_ALL).equals(exclude) ||
|
|
|
|
(excludePath.endsWith(EXCLUDE_ALL) && path!=null && path.startsWith(excludePath.substring(0,excludePath.length()-2))) ||
|
|
|
|
excludePath.equals(path) || (path.endsWith("/") && excludePath.equals(path.substring(0, path.length()-1)))
|
|
|
|
)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}*/
|
|
|
|
|
|
|
|
private void handleError(HttpServletRequest request, HttpServletResponse response,Throwable t) throws IOException {
|
|
|
|
|
|
|
|
RequestError error = t instanceof RequestException?
|
|
|
|
RequestException.class.cast(t).error():
|
|
|
|
application_error;
|
|
|
|
|
|
|
|
if (error == application_error) {
|
|
|
|
response.sendError(error.code(),error.message());
|
|
|
|
}else {
|
|
|
|
if (error == request_not_authorized_error){
|
|
|
|
response.setHeader("WWW-Authenticate", "Basic realm=\"Smartgears\"");
|
|
|
|
log.info("setting WWW-Authenticate to response header");
|
|
|
|
}
|
|
|
|
response.getWriter().write("Error ("+error.code()+") : "+error.message()+"\nStacktrace:\n");
|
|
|
|
t.printStackTrace(response.getWriter());
|
|
|
|
response.setStatus(error.code());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|