Servlet Response wrapper to add getHeaderNames and getHeaders methods to Servet 2.4 spec container not working - servlets

Since Servlet 3.0, HttpServletResponse#getHeaderNames() and HttpServletResponse#getHeaders() has been available. However, I'm using an older spec, specifically Servlet 2.4.
Having looked at the resource, How can I get the HTTP status code out of a ServletResponse in a ServletFilter?, I got an idea of how to write a wrapper. If I understand it right, I have to use setHeader() to facilitate the creation of getHeaderNames() and getHeaders(). I think I have a solid footing on how to store the headers to simulate the usage of these missing methods.
The problem is the filter which leverages this wrapper does not seem to be calling setHeader() automatically. I don't get it. I presume sincegetStatus() is working properly, I'm expecting setHeader() to behave in the same fashion. Specifically, I'm looking to print out all the response headers, after calling chain.doFilter(). I'm not sure what I'm doing wrong here. Maybe there is something wrong with how I'm storing header name-value pairs.
I would appreciate any help. Thank you.
public class ServletResponseWrapper extends HttpServletResponseWrapper {
private int httpStatus = SC_OK;
private HashMap<String, String> hashMapHeaders = new HashMap<String, String>();
public ServletResponseWrapper(HttpServletResponse response) {
super(response);
}
#Override
public void sendError(int sc) throws IOException {
httpStatus = sc;
super.sendError(sc);
}
#Override
public void sendError(int sc, String msg) throws IOException {
httpStatus = sc;
super.sendError(sc, msg);
}
#Override
public void setStatus(int sc) {
httpStatus = sc;
super.setStatus(sc);
}
public int getStatus() {
return httpStatus;
}
#Override
public void sendRedirect(String location) throws IOException {
httpStatus = SC_MOVED_TEMPORARILY;
super.sendRedirect(location);
}
#Override
public void setHeader(String name, String value) {
hashMapHeaders.put(name, value);
super.setHeader(name, value);
}
public String getHeader(String name) {
return hashMapHeaders.get(name);
}
public Enumeration<String> getHeaderNames() {
Enumeration<String> enumerationHeaderNames = Collections.enumeration(hashMapHeaders.keySet());
return enumerationHeaderNames;
}
}
public class ServletResponseWrapperFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletResponseWrapper servletResponseWrapper = new ServletResponseWrapper( (HttpServletResponse) response );
chain.doFilter( request, servletResponseWrapper );
// Process response
// This works, even though I never explicitly call the setStatus() method
int status = response.getStatus();
// This returns NULL because no header values get set; I presume setHeader() gets called implicitly
Enumeration<String> headerNames = servletResponseWrapper.getHeaderNames();
}
public void init(FilterConfig config) throws ServletException {
//empty
}
public void destroy() {
// empty
}
}
web.xml file
<display-name>Tomcat App</display-name>
<filter>
<filter-name>ResponseHeadersFilter</filter-name>
<filter-class>com.company.filters.ResponseHeadersFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ResponseHeadersFilter</filter-name>
<url-pattern>/testfilter.jsp</url-pattern>
</filter-mapping>
I took the vendor's servlet out of the equation. The filter now fires on an empty JSP file. Tomcat is also hooked to a front-end web server, IIS. I disabled IIS. Now, I'm accessing the website directly over Tomcat, via port 8080. Despite all this, I dot see any response headers.
Using Fiddler, the response headers I see are few but existing, namely:
(Cache) Date
(Entity) Content- Length, Content-Type
(Miscellaneous) Server
And status response, i.e. HTTP/1.1 200 OK
I can get by without getting response headers in the filter. But the big question I have is this is a bug with Servlet version 2.4 or is there some kind of OS Server and/or Tomcat configuration change I need to enable? Unless there's some Tomcat configuration, I'm led to believe this is likely a bug. Perhaps a clean install using the default configuration of the Tomcat version I'm using, 5.5.28, would resolve the problem, but I cannot attempt that at this time.

Related

How can I enable lenient parsing with json in retrofit?

I am getting MalformedJSONException, unterminated object error. The content of the url passed is unquoted or relaxed json data. Parsing this content works fine when using just Gson alone but when using Retrofit, it throws the above exception after reading the contents of the URL. Is there a way to enable lenient parsing of the content?
Main Activity Class is given below
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ENDPOINT)
.build();
Log.d("myinfo","endpoint built");
QuizAPI api = adapter.create(QuizAPI.class);
api.getFeed(new Callback<QuizObject>() {
#Override
public void success(QuizObject arg0, Response arg1) {
Log.d("myinfo", "success in callback");
Log.d("myinfo",arg0.getVersion());
}
#Override
public void failure(RetrofitError arg0) {
Log.d("myinfo", arg0.getLocalizedMessage());
}
});
}
protected void updateDisplay(){
output.append("updating..");
}

Lifecycle/Scope of #WebServlet [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do servlets work? Instantiation, session variables and multithreading
I have a weird (but probably expected) behaviour in my WebServlet. Environment is:
- Apache 2.2.x
- Glassfish 3.1.1 + mod_jk
- JSF Mojarra 2.1.3
I have an abstract servlet that implements some code to check in the FacesContext/Session if there is a specific #SessionScoped managed bean and if so, whether the user is signed-in. If user is signed-in, then proceeds to the file delivery. The implementing #WebServlet only provides the actual file download.
Abstract Servlet:
public abstract class SecureDownloadServlet extends HttpServlet {
#EJB
private UserProductBean userProductBean;
private UserInfoView userInfoView = null;
private UserInfoView getUserInfoView(HttpServletRequest req) {
FacesContext context = FacesContext.getCurrentInstance();
if (context != null) {
userInfoView = (UserInfoView) context.getApplication()
.getELResolver().getValue(FacesContext.
getCurrentInstance().getELContext(), null, "userInfoView");
}
if (userInfoView == null) {
userInfoView = (UserInfoView) getServletContext().
getAttribute("userInfoView");
}
if (userInfoView == null) {
userInfoView = (UserInfoView) req.getSession().
getAttribute("userInfoView");
}
return userInfoView;
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse response)
throws IOException, ServletException {
if (getUserInfoView(req) == null || !getUserInfoView(req).getLoggedIn()) {
response.sendRedirect("message.xhtml?msg=noLogin");
return;
}
doDownload(req, response);
}
public abstract void doDownload(HttpServletRequest req,
HttpServletResponse response)
throws IOException, ServletException;
}
Then I have a #WebServlet that extends the above abstract HttpServlet and implements the abstract method:
#WebServlet(name = "SecureImageServlet", urlPatterns = {"/print","/m/print"})
public class SecureImageServlet extends SecureDownloadServlet {
#Override
public void doDownload(HttpServletRequest req, HttpServletResponse response)
throws IOException, ServletException {
// some code
}
}
Now here is the issue:
- From computer A, sign in, then call the SecureImageServlet servlet to get a file (i.e. http://www.example.com/print?id=12345). The userInfoView session bean is initialized as expected, and the file is delivered.
- From computer B, without being signed-in, call http://www.example.com/print?id=12345. The userInfoView is already initialized with the session of user on computer A!!! And the file is delivered too.
It looks like the WebServlet becomes ApplicationScope or something like that. Is it the #EJB injection that does that?
Note the the instance of userInfoView is the same (the object id in the debugger shows the same number) which means somehow the computer B is seen as the same user as computer A
Edited format
Ok, a friend of mine (without an account on SO :) ) pointed out my mistake:
I am using userInfoView as a class member instead of keeping it within the request scope. I fixed it by removing the class member and voila!

MockHttpServletRequest isn't passing the URL to next filter in chain

I am trying to implement a filter that uses MockHttpServletRequest to add a header to the request object. I want to use that header for preauthentication. This is the filter class..
public class MockAuthFilter implements Filter{
private FilterConfig filterConfig = null;
private static String loggedInUserName = "myId";
private static String httpRequestHeaderName = "SM_ID";
private Logger logger = Logger.getLogger(MockAuthFilter.class);
#Override
public void destroy() {
this.filterConfig = null;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if(this.filterConfig.getServletContext() == null){}
HttpServletRequest httpRequest = (HttpServletRequest) request;
MockHttpServletRequest mRequest = new MockHttpServletRequest(this.filterConfig.getServletContext());
if(mRequest.getHeader(httpRequestHeaderName)==null ||
!mRequest.getHeader(httpRequestHeaderName).equalsIgnoreCase(loggedInUserName))
mRequest.addHeader(httpRequestHeaderName, loggedInUserName);
mRequest.setMethod("GET");
mRequest.setRequestURI(httpRequest.getRequestURL().toString());
logger.debug("**********************exiting doFilter() method*****************");
chain.doFilter(mRequest, response);
}
#Override
public void init(FilterConfig config) throws ServletException {
this.filterConfig = config;
}
}
but there is not url populated when the request reaches the next filter in the filter chain of Spring Security. I see following lines in the log file..
[2011-10-13 16:52:35,114] [DEBUG] [http-8080-1] [com.app.filter.MockAuthFilter:doFilter:55] - **********************exiting doFilter() method*****************
[2011-10-13 16:52:35,114] [DEBUG] [http-8080-1] [com.app.filter.MockAuthFilter:doFilter:55] - **********************exiting doFilter() method*****************
[2011-10-13 16:52:35,114] [DEBUG] [http-8080-1] [org.springframework.security.web.util.AntPathRequestMatcher:matches:103] - Checking match of request : ''; against '/static/**'
[2011-10-13 16:52:35,114] [DEBUG] [http-8080-1][org.springframework.security.web.util.AntPathRequestMatcher:matches:103] - Checking match of request : ''; against '/static/**'
As you can see there was no url in the request object passed onto AntPathrequestMatcher's matches method..
I have checked mockrequest object right before chain.doFilter() method and it contains the url value in its requestURI field. if URI and URL aren't the same thing here, what changes should I make here so that url is maintained in the request object..
Don't use MockHttpServletRequest like that. It's for testing, not for production code. The appropriate way to wrap a request and/or response in a filter to modify its behavior later on is with HttpServletRequestWrapper and HttpServletResponseWrapper.
Why are you even trying to wrap or remove the original request if all you want is to add a header? Just use addHeader() on the incoming request.
Trying to change the request method and request URI in the filter as you're doing may have unexpected consequences and will almost certainly not do what you probably expect it to do. By the time the request hits your filter, the filter chain has already been built based on the original state of the request. Changing it now won't affect where it ends up going.

How do delete a HTTP response header?

I have a situation where one of the response headers Content-Disposition has to be removed. So I thought of writing a servlet filter to do this. But I realized that the HttpServletResponse has only a setHeader() method but no method to remove it.
How can I do this?
You can't delete headers afterwards by the standard Servlet API. Your best bet is to just prevent the header from being set. You can do this by creating a Filter which replaces the ServletResponse with a custom HttpServletResponseWrapper implementation which skips the setHeader()'s job whenever the header name is Content-Disposition.
Basically:
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
public void setHeader(String name, String value) {
if (!name.equalsIgnoreCase("Content-Disposition")) {
super.setHeader(name, value);
}
}
});
}
Just map that filter on the URL-pattern of interest to get it to run.
This may not be Servlet API compliant, but setting the value to null works on GlassFish 4 and probably on Tomcat too as that is what is underneath GlassFish.
We really need to update the Servlet API specification to either add a method to allow removing headers or to officially support using setHeader with a null value.
An example where this is important is if you use a security constraint (SSL/TLS) on your web application then static resource caching is complicated by the fact that the container will automatically add headers to prevent caching (you can try to disable with disableProxyCaching and securePagesWithPragma on Tomcat/GlassFish). I've already got a servlet filter for cache control that works great for non-secure content so I would like to keep cache control all in one place and simply set Prama and Cache-Control to null to clear any container added headers.
As the other responses. There is no way to remove a header after being set, at least not standard (glassfish lets clear a header setting it's value to null). So at the end of the day you would have two choices:
Reset the response with response.reset() - This effectively removes ALL headers AND ALSO ANY BUFFERED DATA, depending on you case can be a good alternative (in my case was after authentication validation errors). If the response is already committed you'll get an IllegalStateException.
Set header to empty string, clearly this doesn't remove the header. But the http specification only has some definitions for and empty value in the Accept-Encoding, TE (transfer encoding) and HOST headers, so depending in your needs you can control that in your application layer.
This does not work for me using Spring 4. I'm trying to strip out the Expires response header. For every page. Like so:
public class CachingFilter implements Filter {
private final Log logger = LogFactory.getLog(getClass());
public CachingFilter() {}
public void destroy() {}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
logger.debug("doFilter()");
chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
public void setHeader(String name, String value) {
logger.debug("setHeader(" + name + ","+value+")");
if (!name.equalsIgnoreCase("Expires")) {
super.setHeader(name, value);
}
}
});
}
public void init(FilterConfig fConfig) throws ServletException {}
}
And here is how I add the filter:
public class AppConfig implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
private static final String DISPATCHER_SERVLET_MAPPING = "/";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(AppContext.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(rootContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING);
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
FilterRegistration.Dynamic noCache = servletContext.addFilter("noCacheFilter", new CachingFilter());
noCache.addMappingForUrlPatterns(dispatcherTypes, true, "/*");
servletContext.addListener(new ContextLoaderListener(rootContext));
}
}
setHeader() being called for Expires and Cache-Control, but I can't override the Expires filter value, or the Cache-Control value. I can add to the Cache-Control value. It turns into an array of values if I call setHeader on Cache-Control. But I need to delete the header.

Using Spring 3 #ExceptionHandler with commons FileUpload and SizeLimitExceededException/MaxUploadSizeExceededException

I am having trouble with catching and gracefully handling commons fileupload's FileUploadBase.SizeLimitExceededException or spring's MaxUploadSizeExceededException when uploading large files.
From what I can tell these exceptions are thrown during data binding, before the controller is actually reached, therefore resulting in a 500 and no calling of the exception handler method. Has anyone come across this before, and what is the best way for handling these exceptions properly?
thanks to thetoolman for this simple solution. I extended it a bit. I wanted to leave the file handling untouched and transport the Exception to the Controller.
package myCompany;
public class DropOversizeFilesMultipartResolver extends CommonsMultipartResolver {
/**
* Parse the given servlet request, resolving its multipart elements.
*
* Thanks Alexander Semenov # http://forum.springsource.org/showthread.php?62586
*
* #param request
* the request to parse
* #return the parsing result
*/
#Override
protected MultipartParsingResult parseRequest(final HttpServletRequest request) {
String encoding = determineEncoding(request);
FileUpload fileUpload = prepareFileUpload(encoding);
List fileItems;
try {
fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
} catch (FileUploadBase.SizeLimitExceededException ex) {
request.setAttribute(EXCEPTION_KEY, ex);
fileItems = Collections.EMPTY_LIST;
} catch (FileUploadException ex) {
throw new MultipartException("Could not parse multipart servlet request", ex);
}
return parseFileItems(fileItems, encoding);
}
}
and in the controller
#InitBinder("fileForm")
protected void initBinderDesignForm(WebDataBinder binder) {
binder.setValidator(new FileFormValidator());
}
#RequestMapping(value = "/my/mapping", method = RequestMethod.POST)
public ModelAndView acceptFile(HttpServletRequest request, Model model, FormData formData,
BindingResult result) {
Object exception = request.getAttribute(DropOversizeFilesMultipartResolver.EXCEPTION_KEY);
if (exception != null && FileUploadBase.SizeLimitExceededException.class.equals(exception.getClass())) {
result.rejectValue("file", "<your.message.key>");
LOGGER.error(exception);
}
the spring config remains the same. It would be really nice to have the exception transported to the validator, but I haven't figured out how to do this yet.
I know this is old, but I was looking for a solution to this as well and could not find anything. We are providing RESTful services using Spring and we are doing file upload and were not sure how to handle this. I came up with the following and hopefully it will be useful to someone:
All our exceptions are handled with annotations, so we have our error handler resolver set-up like this:
#Configuration
public class MyConfig{
#Bean
public AnnotationMethodHandlerExceptionResolver exceptionResolver(){
final AnnotationMethodHandlerExceptionResolver resolver = new AnnotationMethodHandlerExceptionResolver();
resolver.setMessageConverters(messageConverters());
resolver;
}
}
Then a common class that can handle the exception
public class MultipartExceptionHandler
{
#ExceptionHandler(MaxUploadSizeExceededException.class)
#ResponseStatus(value = HttpStatus.PRECONDITION_FAILED)
#ResponseBody
protected CustomError handleMaxUploadSizeExceededException(final HttpServletRequest request,
final HttpServletResponse response, final Throwable e)
throws IOException
{
logger.error(e);
CustomError c = new CustomErrorMaxFileSize("Max file size exceeded", MAX_FILE_SIZE);
return c;
}
#ExceptionHandler(MultipartException.class)
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ResponseBody
protected CustomError handleGenericMultipartException(final HttpServletRequest request,
final HttpServletResponse response, final Throwable e)
throws IOException
{
logger.error(e);
CustomError c = new CustomErrorGeneric("There was a problem with the upload");
return c;
}
}
Then we subclass the commons multipart resolver and implement the HandlerExceptionResolver interface
#Component(value="multipartResolver") // Spring expects this name
public class MyMultipartResolver extends CommonsMultipartResolver implements HandlerExceptionResolver
{
// This is the Spring bean that handles exceptions
// We defined this in the Java configuration file
#Resource(name = "exceptionResolver")
private AnnotationMethodHandlerExceptionResolver exceptionResolver;
// The multipart exception handler with the #ExceptionHandler annotation
private final MultipartExceptionHandler multipartExceptionHandler = new MultipartExceptionHandler();
// Spring will call this when there is an exception thrown from this
// multipart resolver
#Override
public ModelAndView resolveException(
final HttpServletRequest request,
final HttpServletResponse response,
final Object handlerParam,
final Exception ex)
{
// Notice that we pass this.multipartExceptionHandler
// and not the method parameter 'handlerParam' into the
// exceptionResolver. We do this because the DispatcherServlet
// doDispatch() method calls checkMultipart() before determining
// the handler for the request. If doing the multipart check fails
// with a MultipartException, Spring will never have a reference
// to the handler and so 'handlerParam' will be null at this point.
return exceptionResolver.resolveException(request, response, this.multipartExceptionHandler, ex);
}
}
This seems to be a quite common problem. I've had similar problems and similar questions have been asked, see for example this question. I have yet to see a nice solution to the problem. You could use a vanilla servlet filter to handle these exceptions, but that will duplicate your error handling since you already have an ExceptionHandler.

Resources