- 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