/*==========================================================================*\ | $Id: RequestUtils.java,v 1.2 2012/03/28 13:48:08 stedwar2 Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2011-2012 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT 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 Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.core.http; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.util.HttpSupport; import com.webobjects.appserver.WORequest; import com.webobjects.appserver.WOResponse; import com.webobjects.foundation.NSData; //------------------------------------------------------------------------- /** * Helper methods for working with HTTP requests and responses. * * @author Tony Allevato * @author Last changed by $Author: stedwar2 $ * @version $Revision: 1.2 $, $Date: 2012/03/28 13:48:08 $ */ public class RequestUtils { //~ Constructors .......................................................... // ---------------------------------------------------------- /** * Prevent instantiation. */ private RequestUtils() { // Do nothing. } //~ Methods ............................................................... // ---------------------------------------------------------- /** * Gets a value indicating whether the specified request can accept a * response that is GZIP encoded. * * @param request the request * @return true if the request accepts a GZIP-encoded response; otherwise, * false */ public static boolean acceptsGZIPEncoding(WORequest request) { String accepts = request.headerForKey(HttpSupport.HDR_ACCEPT_ENCODING); return accepts != null && accepts.contains(HttpSupport.ENCODING_GZIP); } // ---------------------------------------------------------- /** * Gets an input stream to read the content from the specified request, * expanded it from GZIP format if necessary. * * @param request the request * @return an input stream to read the content from the request * @throws IOException if an I/O error occurs */ public static InputStream inputStreamForRequest(WORequest request) throws IOException { InputStream input = request.content().stream(); String encoding = request.headerForKey( HttpSupport.HDR_CONTENT_ENCODING); if (HttpSupport.ENCODING_GZIP.equals(encoding) || "x-gzip".equals(encoding)) { input = new GZIPInputStream(input); } else if (encoding != null) { throw new IOException("Content encoding \"" + encoding + "\" is " + "not supported."); } return input; } // ---------------------------------------------------------- /** * Appends a plain text string to a response, compressing it with GZIP if * the request supports that. * * @param content the content string * @param request the request * @param response the response * @throws IOException if an I/O error occurs */ public static void sendPlainText(String content, WORequest request, WOResponse response) throws IOException { byte[] raw = content.getBytes(Constants.CHARACTER_ENCODING); response.setHeader("text/plain;charset=" + Constants.CHARACTER_ENCODING, HttpSupport.HDR_CONTENT_TYPE); sendBytes(raw, request, response); } // ---------------------------------------------------------- /** * Appends a byte array to a response, compressing it with GZIP if the * request supports that. * * @param content the content array * @param request the request * @param response the response * @throws IOException if an I/O error occurs */ public static void sendBytes(byte[] content, WORequest request, WOResponse response) throws IOException { content = preSend(content, request, response); response.appendContentData(new NSData(content)); } // ---------------------------------------------------------- /** * Prepares a byte array to be appended to a response, by compressing it * (if the request supports that) as well as setting its etag header. * * @param content the raw content to send * @param request the request * @param response the response * @return the byte array that should be sent (which may be a compressed * version of the one sent in) * @throws IOException if an I/O error occurs */ private static byte[] preSend(byte[] content, WORequest request, WOResponse response) throws IOException { response.setHeader(etag(content), HttpSupport.HDR_ETAG); if (content.length > 256 && acceptsGZIPEncoding(request)) { content = compressBytes(content); response.setHeader(HttpSupport.ENCODING_GZIP, HttpSupport.HDR_CONTENT_ENCODING); } return content; } // ---------------------------------------------------------- /** * Compresses a byte array using GZIP. * * @param raw the raw data to compress * @return the compressed data * @throws IOException if an I/O error occurs */ private static byte[] compressBytes(byte[] raw) throws IOException { int maxLen = raw.length + 32; ByteArrayOutputStream out = new ByteArrayOutputStream(maxLen); GZIPOutputStream gzip = new GZIPOutputStream(out); gzip.write(raw); gzip.finish(); gzip.flush(); return out.toByteArray(); } // ---------------------------------------------------------- /** * Computes the etag (SHA-1 hash) for the specified content. * * @param content the content * @return SHA-1 hash for the specified content */ private static String etag(byte[] content) { MessageDigest md = Constants.newMessageDigest(); md.update(content); return ObjectId.fromRaw(md.digest()).getName(); } }