View Javadoc

1   package org.eclipse.jetty.websocket;
2   
3   import java.io.IOException;
4   import java.util.Map;
5   import java.util.zip.DataFormatException;
6   import java.util.zip.Deflater;
7   import java.util.zip.Inflater;
8   
9   import org.eclipse.jetty.io.Buffer;
10  import org.eclipse.jetty.io.ByteArrayBuffer;
11  import org.eclipse.jetty.util.log.Log;
12  import org.eclipse.jetty.util.log.Logger;
13  
14  public class DeflateFrameExtension extends AbstractExtension
15  {
16      private static final Logger LOG = Log.getLogger(DeflateFrameExtension.class);
17  
18      private int _minLength=8;
19      private Deflater _deflater;
20      private Inflater _inflater;
21      
22      public DeflateFrameExtension()
23      {
24          super("x-deflate-frame");
25      }
26  
27      @Override
28      public boolean init(Map<String, String> parameters)
29      {
30          if (!parameters.containsKey("minLength"))
31              parameters.put("minLength",Integer.toString(_minLength));
32          if(super.init(parameters))
33          {
34              _minLength=getInitParameter("minLength",_minLength);
35              
36              _deflater=new Deflater();
37              _inflater=new Inflater();
38              
39              return true;
40          }
41          return false;
42      }
43  
44      /* (non-Javadoc)
45       * @see org.eclipse.jetty.websocket.AbstractExtension#onFrame(byte, byte, org.eclipse.jetty.io.Buffer)
46       */
47      @Override
48      public void onFrame(byte flags, byte opcode, Buffer buffer)
49      {        
50          if (getConnection().isControl(opcode) || !isFlag(flags,1))
51          {
52              super.onFrame(flags,opcode,buffer);
53              return;
54          }
55  
56          if (buffer.array()==null)
57              buffer=buffer.asMutableBuffer();
58          
59          int length=0xff&buffer.get();
60          if (length>=0x7e)
61          {
62              int b=(length==0x7f)?8:2;
63              length=0;
64              while(b-->0)
65                  length=0x100*length+(0xff&buffer.get());
66          }    
67          
68          // TODO check a max framesize
69          
70          _inflater.setInput(buffer.array(),buffer.getIndex(),buffer.length());
71          ByteArrayBuffer buf = new ByteArrayBuffer(length);
72          try
73          {
74              while(_inflater.getRemaining()>0)
75              {
76                  int inflated=_inflater.inflate(buf.array(),buf.putIndex(),buf.space());
77                  if (inflated==0)
78                      throw new DataFormatException("insufficient data");
79                  buf.setPutIndex(buf.putIndex()+inflated);
80              }
81  
82              super.onFrame(clearFlag(flags,1),opcode,buf);
83          }
84          catch(DataFormatException e)
85          {
86              LOG.warn(e);
87              getConnection().close(WebSocketConnectionD13.CLOSE_PROTOCOL,e.toString());
88          }
89      }
90  
91      /* (non-Javadoc)
92       * @see org.eclipse.jetty.websocket.AbstractExtension#addFrame(byte, byte, byte[], int, int)
93       */
94      @Override
95      public void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException
96      {
97          if (getConnection().isControl(opcode) || length<_minLength)
98          {
99              super.addFrame(clearFlag(flags,1),opcode,content,offset,length);
100             return;
101         }
102         
103         // prepare the uncompressed input
104         _deflater.reset();
105         _deflater.setInput(content,offset,length);
106         _deflater.finish();
107         
108         // prepare the output buffer
109         byte[] out= new byte[length];
110         int out_offset=0;
111 
112         // write the uncompressed length
113         if (length>0xffff)
114         {
115             out[out_offset++]=0x7f;
116             out[out_offset++]=(byte)((length>>56)&0x7f);
117             out[out_offset++]=(byte)((length>>48)&0xff);
118             out[out_offset++]=(byte)((length>>40)&0xff);
119             out[out_offset++]=(byte)((length>>32)&0xff);
120             out[out_offset++]=(byte)((length>>24)&0xff);
121             out[out_offset++]=(byte)((length>>16)&0xff);
122             out[out_offset++]=(byte)((length>>8)&0xff);
123             out[out_offset++]=(byte)(length&0xff);
124         }
125         else if (length >=0x7e)
126         {
127             out[out_offset++]=0x7e;
128             out[out_offset++]=(byte)(byte)(length>>8);
129             out[out_offset++]=(byte)(length&0xff);
130         }
131         else
132         {
133             out[out_offset++]=(byte)(length&0x7f);
134         }
135 
136         int l = _deflater.deflate(out,out_offset,length-out_offset);
137         
138         if (_deflater.finished())
139             super.addFrame(setFlag(flags,1),opcode,out,0,l+out_offset);
140         else
141             super.addFrame(clearFlag(flags,1),opcode,content,offset,length);
142     }
143 }