/** * The contents of this file are subject to the OpenMRS Public License * Version 1.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://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.web.filter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.zip.GZIPOutputStream; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; /** * Wraps Response Stream for GZipFilter * * @author Matt Raible * @version $Revision: 1.3 $ $Date: 2004/05/16 02:17:00 $ */ public class GZIPResponseStream extends ServletOutputStream { // abstraction of the output stream used for compression protected OutputStream bufferedOutput = null; // state keeping variable for if close() has been called protected boolean closed = false; // reference to original response protected HttpServletResponse response = null; // reference to the output stream to the client's browser protected ServletOutputStream output = null; // default size of the in-memory buffer private int bufferSize = 50000; public GZIPResponseStream(HttpServletResponse response) throws IOException { super(); closed = false; this.response = response; this.output = response.getOutputStream(); bufferedOutput = new ByteArrayOutputStream(); } public void close() throws IOException { // verify the stream is yet to be closed if (closed) { throw new IOException("This output stream has already been closed"); } // if we buffered everything in memory, gzip it if (bufferedOutput instanceof ByteArrayOutputStream) { // get the content ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput; // prepare a gzip stream ByteArrayOutputStream compressedContent = new ByteArrayOutputStream(); GZIPOutputStream gzipstream = new GZIPOutputStream(compressedContent); byte[] bytes = baos.toByteArray(); gzipstream.write(bytes); gzipstream.finish(); // get the compressed content byte[] compressedBytes = compressedContent.toByteArray(); // set appropriate HTTP headers response.setContentLength(compressedBytes.length); response.addHeader("Content-Encoding", "gzip"); output.write(compressedBytes); output.flush(); output.close(); closed = true; } // if things were not buffered in memory, finish the GZIP stream and response else if (bufferedOutput instanceof GZIPOutputStream) { // cast to appropriate type GZIPOutputStream gzipstream = (GZIPOutputStream) bufferedOutput; // finish the compression gzipstream.finish(); // finish the response output.flush(); output.close(); closed = true; } } public void flush() throws IOException { if (closed) { throw new IOException("Cannot flush a closed output stream"); } bufferedOutput.flush(); } public void write(int b) throws IOException { if (closed) { throw new IOException("Cannot write to a closed output stream"); } // make sure we aren't over the buffer's limit checkBufferSize(1); // write the byte to the temporary output bufferedOutput.write((byte) b); } private void checkBufferSize(int length) throws IOException { // check if we are buffering too large of a file if (bufferedOutput instanceof ByteArrayOutputStream) { ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput; if ((baos.size() + length) > bufferSize) { // files too large to keep in memory are sent to the client without Content-Length specified response.addHeader("Content-Encoding", "gzip"); // get existing bytes byte[] bytes = baos.toByteArray(); // make new gzip stream using the response output stream GZIPOutputStream gzipstream = new GZIPOutputStream(output); gzipstream.write(bytes); // we are no longer buffering, send content via gzipstream bufferedOutput = gzipstream; } } } public void write(byte[] b) throws IOException { write(b, 0, b.length); } public void write(byte[] b, int off, int len) throws IOException { if (closed) { throw new IOException("Cannot write to a closed output stream"); } // make sure we aren't over the buffer's limit checkBufferSize(len); // write the content to the buffer bufferedOutput.write(b, off, len); } public boolean closed() { return (this.closed); } public void reset() { //noop } }