How to modify request headers in a J2EE web application.

Request headers may be modified in a J2EE web application (webapp). By “modify” I mean to add, remove, or edit the request headers. The “hooks” are to 1) subclass javax.servlet.http.HttpServletRequestWrapper and 2) implement the javax.servlet.Filter interface. Notice that the code will be written against the standard Servlet API; this means that your code is portable (usable in other containers). Let’s step through to see how we may “modify” the request headers by adding an additional one.

First, sublcass javax.servlet.http.HttpServletRequestWrapper. The HttpServletRequestWrapper class works by using a Decorator design pattern. You will have to override two methods 1) getHeader(String name) and 2) getHeaderNames(). You will also have to provide a constructor that takes in a javax.servlet.http.HttpServletRequest object. The new class extending HttpServletRequestWrapper is called FakeHeadersRequest. This new class simply generates a request header titled “username.” The value of this request header is taken from the cookies. If a cookie with a name “username” is found, then its value is used also for the “username” request header.

/**
 * Copyright 2009 Jee Vang 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required 
 * by applicable law or agreed to in writing, software distributed 
 * under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
 * or implied. See the License for the specific language governing 
 * permissions and limitations under the License. 
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * Fake headers request object. Adds a request header
 * with the name "username". The value of this request header
 * will be taken from a cookie (also with the name, "username").
 * 
 * @author Jee Vang
 *
 */
public class FakeHeadersRequest extends HttpServletRequestWrapper {

	/**
	 * Constructor. 
	 * 
	 * @param request HttpServletRequest.
	 */
	public FakeHeadersRequest(HttpServletRequest request) {
		super(request);
	}
	
	public String getHeader(String name) {
		//get the request object and cast it
		HttpServletRequest request = (HttpServletRequest)getRequest();
		
		//if we are looking for the "username" request header
		if("username".equals(name)) {
			//loop through the cookies
			Cookie[] cookies = request.getCookies();
			
			//if cookies are null, then return null
			if(null == cookies) {
				return null;
			}
			
			for(int i=0; i < cookies.length; i++) {
				//if the cookie's name is "username"
				if("username".equals(cookies&#91;i&#93;.getName())) {
					//get its value and return it
					String val = cookies&#91;i&#93;.getValue();
					return val;
				}
			}
		}
		
		//otherwise fall through to wrapped request object
		return request.getHeader(name);
	}
	
	public Enumeration getHeaderNames() {
		//create an enumeration of the request headers
		//additionally, add the "username" request header
		
		//create a list
		List list = new ArrayList();
		
		//loop over request headers from wrapped request object
		HttpServletRequest request = (HttpServletRequest)getRequest();
		Enumeration e = request.getHeaderNames();
		while(e.hasMoreElements()) {
			//add the names of the request headers into the list
			String n = (String)e.nextElement();
			list.add(n);
		}
		
		//additionally, add the "username" to the list of request header names
		list.add("username");
		
		//create an enumeration from the list and return
		Enumeration en = Collections.enumeration(list);
		return en;
	}

}
&#91;/sourcecode&#93;

Now, we implement the javax.servlet.Filter interface in a class called SimpleFilter. SimpleFilter does nothing in the destroy() and init() methods. However, in the doFilter() method, the ServletRequest object is cast to a HttpServletRequest object, and then wrapped in the FakeHeadersRequest object. The filter chain then proceeds but with the instance of FakeHeadersRequest (instead of the instance of HttpServletRequest).  

&#91;sourcecode language="java"&#93;
/**
 * Copyright 2009 Jee Vang 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required 
 * by applicable law or agreed to in writing, software distributed 
 * under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
 * or implied. See the License for the specific language governing 
 * permissions and limitations under the License. 
 */

import java.io.IOException;

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;

/**
 * A simple filter used to create an additional header.
 * 
 * @author Jee Vang
 *
 */
public class SimpleFilter implements Filter {

	public void destroy() {
				
	}

	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
			FilterChain filterChain) throws IOException, ServletException {
		//if the ServletRequest is an instance of HttpServletRequest
		if(servletRequest instanceof HttpServletRequest) {
			//cast the object
			HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
			//create the FakeHeadersRequest object to wrap the HttpServletRequest
			FakeHeadersRequest request = new FakeHeadersRequest(httpServletRequest);
			//continue on in the filter chain with the FakeHeaderRequest and ServletResponse objects
			filterChain.doFilter(request, servletResponse);
		} else {
			//otherwise, continue on in the chain with the ServletRequest and ServletResponse objects
			filterChain.doFilter(servletRequest, servletResponse);
		}		
		
		return;
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		
	}

}
&#91;/sourcecode&#93;

Now define the filter in your webapp's web.xml file. 

&#91;sourcecode language="xml"&#93;
<!-- define the filter -->
<filter>
 <filter-name>simpleFilter</filter-name>
 <filter-class>vang.jee.servlet.filter.SimpleFilter</filter-class>
</filter>
<!-- map the filter to a URL pattern -->
<filter-mapping>
 <filter-name>simpleFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

Now it is time to test your filter to see if the an additional request header was added. To test the code, the following JSP is used to create a cookie named “username.” After you create the “username” cookie, simply refresh the page (press F5), and you should see all the request headers plus the “username” request headers.

<%--
Copyright 2008 Jee Vang
Licensed under the Apache License, Version 2.0 (the "License"); 
you may not use this file except in compliance with the License. 
You may obtain a copy of the License at 
 http://www.apache.org/licenses/LICENSE-2.0 
Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
See the License for the specific language governing permissions and 
limitations under the License. 
--%>
<%@page language="java" contentType="text/html; charset=utf-8"%>
<%@page import="java.util.Enumeration"%>
<html>
<head>
<script type="text/javascript">
function saveIt(name) {
	var x = document.forms['cookieform'].username.value;
	if (!x)
		alert('Please fill in a value in the input box.');
	else {
		createCookie(name,x,7);
	}
}

function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readIt(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca&#91;i&#93;;
		while (c.charAt(0)==' ') 
			c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) 
			alert(c.substring(nameEQ.length,c.length));
	}
}

function eraseIt(name) {
	createCookie(name,"",-1);
	alert('Cookie erased');
}

</script>
</head>
<body>
<%
Enumeration e = request.getHeaderNames();
while(e.hasMoreElements()) {
	String n = (String)e.nextElement();
	String v = request.getHeader(n);
	out.println(n + " : " + v + "<br>\n");
}
%>
<form action="#" name="cookieform">
	<input type="text" name="username"> <br/>
	<a href="javascript:saveIt('username')" class="page">Create</a><br/>
	<a href="javascript:readIt('username')" class="page">Read</a><br/>
	<a href="javascript:eraseIt('username')" class="page">Erase</a>
</form>
</body>
</html>

Upon first loading the JSP page, your headers should look like the following. This output was produced using FireFox 3.0.6 as the browser, and Tomcat 4.1.29 as the web server.

host : localhost:8080
user-agent : Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 Ubiquity/0.1.5
accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-language : en-us,en;q=0.5
accept-encoding : gzip,deflate
accept-charset : ISO-8859-1,utf-8;q=0.7,*;q=0.7
keep-alive : 300
connection : keep-alive
cache-control : max-age=0
username : null

After you enter something into the textfield and hit create, reloading the page will produce an output as follows.

host : localhost:8080
user-agent : Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 Ubiquity/0.1.5
accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-language : en-us,en;q=0.5
accept-encoding : gzip,deflate
accept-charset : ISO-8859-1,utf-8;q=0.7,*;q=0.7
keep-alive : 300
connection : keep-alive
cookie : JSESSIONID=D187F63111362BEE78277F5292DEC48A; username=Jason Mraz
cache-control : max-age=0
username : Jason Mraz

We are now at the end of this blog on how to modify request headers in a J2EE web application—specifically, how to add an additional header.

1 thought on “How to modify request headers in a J2EE web application.

  1. Pingback: Delicious Bookmarks for August 26th through August 27th « Lâmôlabs

Leave a comment