Java tutorial
/* * This file is part of Mockey, a tool for testing application * interactions over HTTP, with a focus on testing web services, * specifically web applications that consume XML, JSON, and HTML. * * Copyright (C) 2009-2010 Authors: * * chad.lafontaine (chad.lafontaine AT gmail DOT com) * neil.cronin (neil AT rackle DOT com) * lorin.kobashigawa (lkb AT kgawa DOT com) * rob.meyer (rob AT bigdis DOT com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package com.mockey.model; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpRequest; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIUtils; import org.apache.http.cookie.Cookie; import org.apache.http.entity.StringEntity; import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HTTP; /** * Wraps httpServletRequest and parses out the information we're looking for. */ public class RequestFromClient { /** * We will ignore the accept-encoding for now to avoid dealing with GZIP * responses if we decide to accept GZIP'ed data later, here is an example * of how to un-gzip it: * * <pre> * http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient/src/examples/org/apache/http/examples/client/ClientGZipContentCompression.java * </pre> * */ public static final String[] HEADERS_TO_IGNORE = { "content-length", "host", "accept-encoding" }; private Log log = LogFactory.getLog(RequestFromClient.class); private List<Cookie> httpClientCookies = new ArrayList<Cookie>(); private Map<String, String[]> parameters = new HashMap<String, String[]>(); private Map<String, List<String>> headers = new HashMap<String, List<String>>(); private String requestBody; private String method; /** * Initialization will extract Headers, Body, Parameters, and Cookies from * the raw HTTP request. Note: This class will <i>_ignore_</i> some header * information. See <code>HEADERS_TO_IGNORE</code> * * @param rawRequest */ public RequestFromClient(HttpServletRequest rawRequest) { try { rawRequest.setCharacterEncoding(HTTP.ISO_8859_1); // "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } this.method = rawRequest.getMethod(); parseRequestHeaders(rawRequest); parseRequestBody(rawRequest); parseParameters(rawRequest); parseCookies(rawRequest); } public List<Cookie> getHttpClientCookies() { return this.httpClientCookies; } /** * Copy all necessary data from the request into a POST to the new server * * @param serviceBean * the path on the server to POST to * @return A fully populated HttpRequest object * @throws URISyntaxException * @throws UnsupportedEncodingException */ public HttpRequest postToRealServer(Url url) throws URISyntaxException, UnsupportedEncodingException { // TODO: Cleanup the logic to handle creating a GET vs POST HttpRequest request; URI uri = URIUtils.createURI(url.getScheme(), url.getHost(), -1, url.getPath(), this.buildParameterRequest(), null); if (("GET").equalsIgnoreCase(this.method)) { request = new HttpGet(uri); } else { HttpPost post = new HttpPost(uri); // copy the request body we received into the POST post.setEntity(constructHttpPostBody()); request = post; } // copy the headers into the request to the real server for (Map.Entry<String, List<String>> stringListEntry : headers.entrySet()) { String name = stringListEntry.getKey(); // ignore certain headers that httpclient will generate for us if (shouldIncludeHeader(name)) { for (String value : stringListEntry.getValue()) { request.addHeader(name, value); } } } return request; } private boolean shouldIncludeHeader(String name) { for (String header : HEADERS_TO_IGNORE) { if (header.equalsIgnoreCase(name)) { return false; } } return true; } /** * Parameter key and value(s). * * @return */ public Map<String, String[]> getParameters() { return this.parameters; } /** * * @return All the parameters as a URL encoded string * @throws UnsupportedEncodingException */ public String buildParameterRequest() throws UnsupportedEncodingException { StringBuffer requestMsg = new StringBuffer(); // Checking for this case: /someurl?wsdl boolean first = true; for (String key : parameters.keySet()) { String[] values = parameters.get(key); if (!first) { requestMsg.append("&"); } if (values != null && values.length > 0) { for (String value : values) { if (value.trim().length() > 0) { requestMsg.append(URLEncoder.encode(key, HTTP.UTF_8)).append("=") .append(URLEncoder.encode(value, HTTP.UTF_8)); } else { requestMsg.append(URLEncoder.encode(key, HTTP.UTF_8)); } } } if (first) { first = false; } } return requestMsg.toString(); } @SuppressWarnings("unchecked") private void parseRequestHeaders(HttpServletRequest rawRequest) { // Put header information coming from client. Enumeration<String> e = rawRequest.getHeaderNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); // Let's ignore some headers if (this.shouldIncludeHeader(name)) { List<String> values = new ArrayList<String>(); Enumeration eValues = rawRequest.getHeaders(name); while (eValues.hasMoreElements()) { String value = (String) eValues.nextElement(); values.add(value); } headers.put(name, values); } } // Override header information to prevent CACHING // As of 4/29/2011, updated Apache HttpClient. Result was the // following: // Testing with MAMP (Apache 2.0.63), I was seeing // this parameter being sent by Browsers Firefox 4 and // and Chrome 9, but NOT Safari 5. // To prevent caching, removing this attribute. e = rawRequest.getHeaderNames(); List<String> p = new ArrayList<String>(); p.add("Fri, 13 May 2006 23:54:18 GMT"); while (e.hasMoreElements()) { String name = (String) e.nextElement(); if ("if-none-match".equalsIgnoreCase(name)) { headers.remove(name); } else if ("If-modified-Since".equalsIgnoreCase(name)) { headers.put(name, p); } } } /** * an org.apache.commons.httpclient.Cookie is NOT a * javax.servlet.http.Cookie - and it looks like the two don't map onto each * other without data loss... * */ private void parseCookies(HttpServletRequest rawRequest) { javax.servlet.http.Cookie[] cookies = rawRequest.getCookies(); if (cookies != null) { // ****************** // This doesn't seem right. // We have to map javax Cookies to httpclient Cookies?!?! // // ****************** for (int i = 0; i < cookies.length; i++) { javax.servlet.http.Cookie c = cookies[i]; String domain = c.getDomain(); if (domain == null) { domain = rawRequest.getServerName(); } String cpath = c.getPath(); if (cpath == null) { cpath = rawRequest.getContextPath(); } BasicClientCookie basicClientCookie = new BasicClientCookie(c.getName(), c.getValue()); basicClientCookie.setDomain(domain); if (c.getMaxAge() > -1) { int seconds = c.getMaxAge(); long currentTime = System.currentTimeMillis(); Date expiryDate = new Date(currentTime + (seconds * 1000)); basicClientCookie.setExpiryDate(expiryDate); } this.httpClientCookies.add(basicClientCookie); } } } private void parseRequestBody(HttpServletRequest rawRequest) { try { InputStream is = rawRequest.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } requestBody = sb.toString(); } catch (IOException e) { log.error("Unable to parse body from incoming request", e); } } @SuppressWarnings("unchecked") private void parseParameters(HttpServletRequest rawRequest) { parameters = rawRequest.getParameterMap(); } /** * * @return readeable string output of header */ public String getHeaderInfo() { StringBuffer buf = new StringBuffer(); for (String headerName : headers.keySet()) { buf.append(headerName + "\n"); for (String headerValue : headers.get(headerName)) { buf.append(" " + headerValue + "\n"); } } return buf.toString(); } public String getMethod() { return this.method; } public String getCookieInfoAsString() { StringBuffer buf = new StringBuffer(); for (Cookie cookie : this.httpClientCookies) { buf.append(cookie.toString() + "\n\n"); } return buf.toString(); } private HttpEntity constructHttpPostBody() { HttpEntity body; try { if (requestBody != null) { body = new StringEntity(requestBody); } else { List<NameValuePair> parameters = new ArrayList<NameValuePair>(); for (Map.Entry<String, String[]> entry : this.parameters.entrySet()) { for (String value : entry.getValue()) { parameters.add(new BasicNameValuePair(entry.getKey(), value)); } } body = new UrlEncodedFormEntity(parameters, HTTP.ISO_8859_1); // .UTF_8); } } catch (UnsupportedEncodingException e) { throw new IllegalStateException("Unable to generate a POST from the incoming request", e); } return body; } /** * * @return - true if incoming request is posting a body */ public boolean hasPostBody() { return requestBody != null && requestBody.trim().length() > 0; } /** * * @return the body content of this request. */ public String getBodyInfo() { return requestBody; } /** * * @return the parameters of this request */ public String getParameterInfo() { StringBuilder builder = new StringBuilder(); for (Map.Entry<String, String[]> entry : parameters.entrySet()) { builder.append(entry.getKey()).append("="); for (String value : entry.getValue()) { builder.append(value); } builder.append("|"); } return builder.toString(); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("---------- Headers ---------\n"); builder.append(getHeaderInfo()); builder.append("---------- Cookies ---------\n"); builder.append(getCookieInfoAsString()); builder.append("--------- Parameters ------------ \n"); builder.append(getParameterInfo()); builder.append("-------- Post BODY --------------\n"); builder.append(getBodyInfo()); return builder.toString(); } }