- From: Roland Mainz <Roland.Mainz@informatik.med.uni-giessen.de>
- Date: Tue, 04 May 1999 04:05:24 +0200
- To: W3 Jigsaw Mailinglist <www-jigsaw@w3.org>, "jigsaw@w3.org" <jigsaw@w3.org>
- Message-Id: <372E55E3.4C816EB3@informatik.med.uni-giessen.de>
Hi ! ---- I tried out GZIPFilter (attached to a HTTPFrame), but I saw only rubbish in the web-browsers (did I do something wrong here ?). Therefore, I wrote a replacement for GZIPFrame, adding some features like variable buffer size (to get a little bit control of the CPU usage of this frame), and I've added "compress" encoding. ---- If someone has information about the "deflate" compression supported by MS Internet Explorer, let me know this info that I can extend CompressFrame with this encoding. ---- Source is included as an attachment. ---- Bye, Roland -- __ . . __ (o.\ \/ /.o) Roland Mainz C programmer \__\/\/__/ Roland.Mainz@informatik.med.uni-giessen.de MPEG specialist /O /==\ O\ gisburn@w-specht.rhein-ruhr.de Sun&&Amiga programmer (;O/ \/ \O;) TEL +49 (0) 2426901568 FAX +49 (0) 2426901569
// // $Id: CompressFilter.java,v 1.1 1998/04/05 11:06:24 gisburn Exp $ // Written by Roland Mainz (Roland.Mainz@informatik.med.uni-giessen.de) // based on GZIPFilter.java 1.7 written by the Jigsaw team package org.w3c.jigsaw.filters; import java.io.*; import java.util.zip.*; import org.w3c.tools.resources.*; import org.w3c.www.mime.*; import org.w3c.www.http.*; import org.w3c.jigsaw.http.*; import org.w3c.jigsaw.resources.*; /** * This filter will compress the content of replies. * Compression is done <em>on the fly</em>. This assumes that you're really * on a slow link, where you have lots of CPU, but not much bandwidth. * <p>A nifty usage for that filter, is to plug it on top of a * <code>org.w3c.jigsaw.proxy.ProxyDirectory</code>, in which case it * will compress the data when it flies out of the proxy. */ public class CompressFilter extends ResourceFilter { /** * This class implements the thread which moves data * from given in to out because we cannot do this on the * calling filter thread. */ class DataMover extends Thread { InputStream in = null; OutputStream out = null; public void run() { try { byte buf[] = new byte[ 512 ]; int got = -1; while( (got = in.read( buf ) ) >= 0 ) out.write( buf, 0, got ); } catch( IOException ex ) { System.err.print( getName() + ": I/O failure" ); ex.printStackTrace(); } finally { try { in.close(); } catch( Exception ex ) { /* ignored */ }; try { out.close(); } catch( Exception ex ) { /* ignored */ }; } } DataMover( InputStream in, OutputStream out ) { this.in = in; this.out = out; // FIXME: the thread name should contain more info... setName( "CompressDataMover" ); start(); } } /** * Do debugging ? */ final static private boolean doDebug = false; /** * Attribute index - List of MIME type that we can compress */ protected static int ATTR_MIME_TYPES = -1; /** * Attribute index - Compress buffer size. * Larger values means better compression, but more CPU usage; * small values means less compression, but less CPU usage. * Not that some compressions like "compress" (zip compression) does * not respect this attribute (but "gzip" does) ! */ protected static int ATTR_BUFFER_SIZE = -1; /** * Buffer size special value "-1": Use default buffer size for this compression. */ final static public int useDefaultBufferSize = -1; static { Class c = null; Attribute a = null; try { c = Class.forName( "org.w3c.jigsaw.filters.CompressFilter" ); } catch( Exception ex ) { ex.printStackTrace(); System.exit( 1 ); } d( "compress filter loaded." ); // this should be a useable default: compress all text based // content (html, xml, plain text etc.) final String mime_type_defaults[] = { "text/*" }; // Register the MIME types attribute: a = new StringArrayAttribute( "mime-types", mime_type_defaults, Attribute.EDITABLE ); ATTR_MIME_TYPES = AttributeRegistry.registerAttribute( c, a ); // Register the buffer size attribute: a = new IntegerAttribute( "buffer-size", new Integer( useDefaultBufferSize ), Attribute.EDITABLE ); ATTR_BUFFER_SIZE = AttributeRegistry.registerAttribute( c, a ); } /** * The set of MIME types we are allowed to compress. */ protected MimeType types[] = null; /** * Catch the setting of mime types to compress. * @param idx The attribute being set. * @param val The new attribute value. */ public void setValue( int idx, Object value ) { super.setValue( idx, value ); // FIXME: What about ATTR_BUFFER_SIZE ? if( idx == ATTR_MIME_TYPES ) { synchronized( this ) { types = null; } } } /** * get the buffer size */ public synchronized int getBufferSize() { Integer val = (Integer)getValue( ATTR_BUFFER_SIZE, null ); if( val == null ) // use default buffer size return( useDefaultBufferSize ); return( val.intValue() ); } /** * Get the set of MIME types to match: * @return An array of MimeType instances. */ public synchronized MimeType[] getMimeTypes() { if( types == null ) { String strtypes[] = (String[])getValue( ATTR_MIME_TYPES, null ); if( strtypes == null ) return( null ); types = new MimeType[strtypes.length]; for( int i = 0 ; i < types.length ; i++) { try { types[i] = new MimeType( strtypes[i] ); } catch( Exception ex ) { types[i] = null; } } } return( types ); } // tested with Lynx protected void doCompress( Reply reply, int bufferSize ) throws Exception { d( "using compress compression, buffer = " + bufferSize + "." ); PipedOutputStream pout = new PipedOutputStream(); PipedInputStream pin = new PipedInputStream( pout ); ZipOutputStream zout = new ZipOutputStream( pout ); zout.putNextEntry( new ZipEntry( "x" ) ); // add a ZIP entry new DataMover( reply.openStream(), zout ); reply.addContentEncoding( "compress" ); reply.setContentLength( -1 ); reply.setStream( pin ); } // tested with Netscape 4.x, 5.x, IE 5 and Lynx protected void doGZIP( Reply reply, int bufferSize ) throws Exception { d( "using gzip compression, buffer = " + bufferSize + "." ); PipedOutputStream pout = new PipedOutputStream(); PipedInputStream pin = new PipedInputStream( pout ); OutputStream out = (bufferSize == useDefaultBufferSize)? (new GZIPOutputStream( pout )): (new GZIPOutputStream( pout, bufferSize )); new DataMover( reply.openStream(), out ); reply.addContentEncoding( "gzip" ); reply.setContentLength( -1 ); reply.setStream( pin ); } // don#t have any info about this compression method - seems that only // IE supports it // void doDeflate( Reply reply ) throws Exception /** * @param request The original request. * @param reply It's original reply. * @return A Reply instance, or <strong>null</strong> if processing * should continue normally. * @exception ProtocolException If processing should be interrupted, * because an abnormal situation occured. */ public ReplyInterface outgoingFilter( RequestInterface req, ReplyInterface rep ) throws ProtocolException { Request request = (Request)req; Reply reply = (Reply)rep; // Anything to compress ? if( !reply.hasStream() ) return( null ); // Match possible mime types: MimeType t[] = getMimeTypes(); int bufferSize = getBufferSize(); boolean matched = false; if( t != null ) { for( int i = 0 ; i < t.length ; i++) { if( t[i] == null ) continue; if( t[i].match( reply.getContentType() ) > 0 ) { matched = true; break; } } } // no mimetypes matched ? if( !matched ) return( null ); // FIXME: IMHO it will cause havoc if outgoing data are already compressed... // We should add here a check whether a content-encoding is present, and abort // our work here in this case. HttpAcceptEncoding encodings[] = request.getAcceptEncoding(); // no encodings set (e.g. no encodings supported) ? if( encodings == null ) return( null ); // TODO: The incoming array of Accept-Encodings should be sorted by quality, // if there is such a thing for this kind of headers try { for( int i = 0 ; i < encodings.length ; i++ ) { String e = encodings[i].toString(); if( e.indexOf( "compress" ) != -1 ) { doCompress( reply, bufferSize ); return( null ); } else if( e.indexOf( "gzip" ) != -1 ) { doGZIP( reply, bufferSize ); return( null ); } else { // unsupported encoding (deflate etc.) d( "unsupported encoding `" + e + "`." ); } } } catch( Exception exc ) { exc.printStackTrace(); } return( null ); } private static void d( String s ) { if( doDebug ) System.err.println( "CompressFilter: " + s ); } }
Received on Monday, 3 May 1999 22:04:30 UTC