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