103928aee4356845252ac6b662d5c72c29903813eJake Slack// 203928aee4356845252ac6b662d5c72c29903813eJake Slack// ======================================================================== 303928aee4356845252ac6b662d5c72c29903813eJake Slack// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 403928aee4356845252ac6b662d5c72c29903813eJake Slack// ------------------------------------------------------------------------ 503928aee4356845252ac6b662d5c72c29903813eJake Slack// All rights reserved. This program and the accompanying materials 603928aee4356845252ac6b662d5c72c29903813eJake Slack// are made available under the terms of the Eclipse Public License v1.0 703928aee4356845252ac6b662d5c72c29903813eJake Slack// and Apache License v2.0 which accompanies this distribution. 803928aee4356845252ac6b662d5c72c29903813eJake Slack// 903928aee4356845252ac6b662d5c72c29903813eJake Slack// The Eclipse Public License is available at 1003928aee4356845252ac6b662d5c72c29903813eJake Slack// http://www.eclipse.org/legal/epl-v10.html 1103928aee4356845252ac6b662d5c72c29903813eJake Slack// 1203928aee4356845252ac6b662d5c72c29903813eJake Slack// The Apache License v2.0 is available at 1303928aee4356845252ac6b662d5c72c29903813eJake Slack// http://www.opensource.org/licenses/apache2.0.php 1403928aee4356845252ac6b662d5c72c29903813eJake Slack// 1503928aee4356845252ac6b662d5c72c29903813eJake Slack// You may elect to redistribute this code under either of these licenses. 1603928aee4356845252ac6b662d5c72c29903813eJake Slack// ======================================================================== 1703928aee4356845252ac6b662d5c72c29903813eJake Slack// 1803928aee4356845252ac6b662d5c72c29903813eJake Slack 1903928aee4356845252ac6b662d5c72c29903813eJake Slackpackage org.eclipse.jetty.websocket; 2003928aee4356845252ac6b662d5c72c29903813eJake Slack 2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.IOException; 2203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Map; 2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.zip.DataFormatException; 2403928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.zip.Deflater; 2503928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.zip.Inflater; 2603928aee4356845252ac6b662d5c72c29903813eJake Slack 2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.Buffer; 2803928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.io.ByteArrayBuffer; 2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Log; 3003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Logger; 3103928aee4356845252ac6b662d5c72c29903813eJake Slack 3203928aee4356845252ac6b662d5c72c29903813eJake Slack/** 3303928aee4356845252ac6b662d5c72c29903813eJake Slack * TODO Implement proposed deflate frame draft 3403928aee4356845252ac6b662d5c72c29903813eJake Slack */ 3503928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class DeflateFrameExtension extends AbstractExtension 3603928aee4356845252ac6b662d5c72c29903813eJake Slack{ 3703928aee4356845252ac6b662d5c72c29903813eJake Slack private static final Logger LOG = Log.getLogger(DeflateFrameExtension.class); 3803928aee4356845252ac6b662d5c72c29903813eJake Slack 3903928aee4356845252ac6b662d5c72c29903813eJake Slack private int _minLength=8; 4003928aee4356845252ac6b662d5c72c29903813eJake Slack private Deflater _deflater; 4103928aee4356845252ac6b662d5c72c29903813eJake Slack private Inflater _inflater; 4203928aee4356845252ac6b662d5c72c29903813eJake Slack 4303928aee4356845252ac6b662d5c72c29903813eJake Slack public DeflateFrameExtension() 4403928aee4356845252ac6b662d5c72c29903813eJake Slack { 4503928aee4356845252ac6b662d5c72c29903813eJake Slack super("x-deflate-frame"); 4603928aee4356845252ac6b662d5c72c29903813eJake Slack } 4703928aee4356845252ac6b662d5c72c29903813eJake Slack 4803928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 4903928aee4356845252ac6b662d5c72c29903813eJake Slack public boolean init(Map<String, String> parameters) 5003928aee4356845252ac6b662d5c72c29903813eJake Slack { 5103928aee4356845252ac6b662d5c72c29903813eJake Slack if (!parameters.containsKey("minLength")) 5203928aee4356845252ac6b662d5c72c29903813eJake Slack parameters.put("minLength",Integer.toString(_minLength)); 5303928aee4356845252ac6b662d5c72c29903813eJake Slack if(super.init(parameters)) 5403928aee4356845252ac6b662d5c72c29903813eJake Slack { 5503928aee4356845252ac6b662d5c72c29903813eJake Slack _minLength=getInitParameter("minLength",_minLength); 5603928aee4356845252ac6b662d5c72c29903813eJake Slack 5703928aee4356845252ac6b662d5c72c29903813eJake Slack _deflater=new Deflater(); 5803928aee4356845252ac6b662d5c72c29903813eJake Slack _inflater=new Inflater(); 5903928aee4356845252ac6b662d5c72c29903813eJake Slack 6003928aee4356845252ac6b662d5c72c29903813eJake Slack return true; 6103928aee4356845252ac6b662d5c72c29903813eJake Slack } 6203928aee4356845252ac6b662d5c72c29903813eJake Slack return false; 6303928aee4356845252ac6b662d5c72c29903813eJake Slack } 6403928aee4356845252ac6b662d5c72c29903813eJake Slack 6503928aee4356845252ac6b662d5c72c29903813eJake Slack /* (non-Javadoc) 6603928aee4356845252ac6b662d5c72c29903813eJake Slack * @see org.eclipse.jetty.websocket.AbstractExtension#onFrame(byte, byte, org.eclipse.jetty.io.Buffer) 6703928aee4356845252ac6b662d5c72c29903813eJake Slack */ 6803928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 6903928aee4356845252ac6b662d5c72c29903813eJake Slack public void onFrame(byte flags, byte opcode, Buffer buffer) 7003928aee4356845252ac6b662d5c72c29903813eJake Slack { 7103928aee4356845252ac6b662d5c72c29903813eJake Slack if (getConnection().isControl(opcode) || !isFlag(flags,1)) 7203928aee4356845252ac6b662d5c72c29903813eJake Slack { 7303928aee4356845252ac6b662d5c72c29903813eJake Slack super.onFrame(flags,opcode,buffer); 7403928aee4356845252ac6b662d5c72c29903813eJake Slack return; 7503928aee4356845252ac6b662d5c72c29903813eJake Slack } 7603928aee4356845252ac6b662d5c72c29903813eJake Slack 7703928aee4356845252ac6b662d5c72c29903813eJake Slack if (buffer.array()==null) 7803928aee4356845252ac6b662d5c72c29903813eJake Slack buffer=buffer.asMutableBuffer(); 7903928aee4356845252ac6b662d5c72c29903813eJake Slack 8003928aee4356845252ac6b662d5c72c29903813eJake Slack int length=0xff&buffer.get(); 8103928aee4356845252ac6b662d5c72c29903813eJake Slack if (length>=0x7e) 8203928aee4356845252ac6b662d5c72c29903813eJake Slack { 8303928aee4356845252ac6b662d5c72c29903813eJake Slack int b=(length==0x7f)?8:2; 8403928aee4356845252ac6b662d5c72c29903813eJake Slack length=0; 8503928aee4356845252ac6b662d5c72c29903813eJake Slack while(b-->0) 8603928aee4356845252ac6b662d5c72c29903813eJake Slack length=0x100*length+(0xff&buffer.get()); 8703928aee4356845252ac6b662d5c72c29903813eJake Slack } 8803928aee4356845252ac6b662d5c72c29903813eJake Slack 8903928aee4356845252ac6b662d5c72c29903813eJake Slack // TODO check a max framesize 9003928aee4356845252ac6b662d5c72c29903813eJake Slack 9103928aee4356845252ac6b662d5c72c29903813eJake Slack _inflater.setInput(buffer.array(),buffer.getIndex(),buffer.length()); 9203928aee4356845252ac6b662d5c72c29903813eJake Slack ByteArrayBuffer buf = new ByteArrayBuffer(length); 9303928aee4356845252ac6b662d5c72c29903813eJake Slack try 9403928aee4356845252ac6b662d5c72c29903813eJake Slack { 9503928aee4356845252ac6b662d5c72c29903813eJake Slack while(_inflater.getRemaining()>0) 9603928aee4356845252ac6b662d5c72c29903813eJake Slack { 9703928aee4356845252ac6b662d5c72c29903813eJake Slack int inflated=_inflater.inflate(buf.array(),buf.putIndex(),buf.space()); 9803928aee4356845252ac6b662d5c72c29903813eJake Slack if (inflated==0) 9903928aee4356845252ac6b662d5c72c29903813eJake Slack throw new DataFormatException("insufficient data"); 10003928aee4356845252ac6b662d5c72c29903813eJake Slack buf.setPutIndex(buf.putIndex()+inflated); 10103928aee4356845252ac6b662d5c72c29903813eJake Slack } 10203928aee4356845252ac6b662d5c72c29903813eJake Slack 10303928aee4356845252ac6b662d5c72c29903813eJake Slack super.onFrame(clearFlag(flags,1),opcode,buf); 10403928aee4356845252ac6b662d5c72c29903813eJake Slack } 10503928aee4356845252ac6b662d5c72c29903813eJake Slack catch(DataFormatException e) 10603928aee4356845252ac6b662d5c72c29903813eJake Slack { 10703928aee4356845252ac6b662d5c72c29903813eJake Slack LOG.warn(e); 10803928aee4356845252ac6b662d5c72c29903813eJake Slack getConnection().close(WebSocketConnectionRFC6455.CLOSE_BAD_PAYLOAD,e.toString()); 10903928aee4356845252ac6b662d5c72c29903813eJake Slack } 11003928aee4356845252ac6b662d5c72c29903813eJake Slack } 11103928aee4356845252ac6b662d5c72c29903813eJake Slack 11203928aee4356845252ac6b662d5c72c29903813eJake Slack /* (non-Javadoc) 11303928aee4356845252ac6b662d5c72c29903813eJake Slack * @see org.eclipse.jetty.websocket.AbstractExtension#addFrame(byte, byte, byte[], int, int) 11403928aee4356845252ac6b662d5c72c29903813eJake Slack */ 11503928aee4356845252ac6b662d5c72c29903813eJake Slack @Override 11603928aee4356845252ac6b662d5c72c29903813eJake Slack public void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException 11703928aee4356845252ac6b662d5c72c29903813eJake Slack { 11803928aee4356845252ac6b662d5c72c29903813eJake Slack if (getConnection().isControl(opcode) || length<_minLength) 11903928aee4356845252ac6b662d5c72c29903813eJake Slack { 12003928aee4356845252ac6b662d5c72c29903813eJake Slack super.addFrame(clearFlag(flags,1),opcode,content,offset,length); 12103928aee4356845252ac6b662d5c72c29903813eJake Slack return; 12203928aee4356845252ac6b662d5c72c29903813eJake Slack } 12303928aee4356845252ac6b662d5c72c29903813eJake Slack 12403928aee4356845252ac6b662d5c72c29903813eJake Slack // prepare the uncompressed input 12503928aee4356845252ac6b662d5c72c29903813eJake Slack _deflater.reset(); 12603928aee4356845252ac6b662d5c72c29903813eJake Slack _deflater.setInput(content,offset,length); 12703928aee4356845252ac6b662d5c72c29903813eJake Slack _deflater.finish(); 12803928aee4356845252ac6b662d5c72c29903813eJake Slack 12903928aee4356845252ac6b662d5c72c29903813eJake Slack // prepare the output buffer 13003928aee4356845252ac6b662d5c72c29903813eJake Slack byte[] out= new byte[length]; 13103928aee4356845252ac6b662d5c72c29903813eJake Slack int out_offset=0; 13203928aee4356845252ac6b662d5c72c29903813eJake Slack 13303928aee4356845252ac6b662d5c72c29903813eJake Slack // write the uncompressed length 13403928aee4356845252ac6b662d5c72c29903813eJake Slack if (length>0xffff) 13503928aee4356845252ac6b662d5c72c29903813eJake Slack { 13603928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=0x7f; 13703928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)0; 13803928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)0; 13903928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)0; 14003928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)0; 14103928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)((length>>24)&0xff); 14203928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)((length>>16)&0xff); 14303928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)((length>>8)&0xff); 14403928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)(length&0xff); 14503928aee4356845252ac6b662d5c72c29903813eJake Slack } 14603928aee4356845252ac6b662d5c72c29903813eJake Slack else if (length >=0x7e) 14703928aee4356845252ac6b662d5c72c29903813eJake Slack { 14803928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=0x7e; 14903928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)(length>>8); 15003928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)(length&0xff); 15103928aee4356845252ac6b662d5c72c29903813eJake Slack } 15203928aee4356845252ac6b662d5c72c29903813eJake Slack else 15303928aee4356845252ac6b662d5c72c29903813eJake Slack { 15403928aee4356845252ac6b662d5c72c29903813eJake Slack out[out_offset++]=(byte)(length&0x7f); 15503928aee4356845252ac6b662d5c72c29903813eJake Slack } 15603928aee4356845252ac6b662d5c72c29903813eJake Slack 15703928aee4356845252ac6b662d5c72c29903813eJake Slack int l = _deflater.deflate(out,out_offset,length-out_offset); 15803928aee4356845252ac6b662d5c72c29903813eJake Slack 15903928aee4356845252ac6b662d5c72c29903813eJake Slack if (_deflater.finished()) 16003928aee4356845252ac6b662d5c72c29903813eJake Slack super.addFrame(setFlag(flags,1),opcode,out,0,l+out_offset); 16103928aee4356845252ac6b662d5c72c29903813eJake Slack else 16203928aee4356845252ac6b662d5c72c29903813eJake Slack super.addFrame(clearFlag(flags,1),opcode,content,offset,length); 16303928aee4356845252ac6b662d5c72c29903813eJake Slack } 16403928aee4356845252ac6b662d5c72c29903813eJake Slack} 165