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
45
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
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
92
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
104 _deflater.reset();
105 _deflater.setInput(content,offset,length);
106 _deflater.finish();
107
108
109 byte[] out= new byte[length];
110 int out_offset=0;
111
112
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 }