1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  package org.jboss.netty.handler.codec.http.websocketx;
55  
56  import org.jboss.netty.buffer.ChannelBuffer;
57  import org.jboss.netty.buffer.ChannelBuffers;
58  import org.jboss.netty.channel.Channel;
59  import org.jboss.netty.channel.ChannelHandlerContext;
60  import org.jboss.netty.handler.codec.frame.TooLongFrameException;
61  import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
62  import org.jboss.netty.logging.InternalLogger;
63  import org.jboss.netty.logging.InternalLoggerFactory;
64  
65  import java.nio.ByteBuffer;
66  
67  
68  
69  
70  
71  
72  
73  public class WebSocket08FrameEncoder extends OneToOneEncoder {
74  
75      private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocket08FrameEncoder.class);
76  
77      private static final byte OPCODE_CONT = 0x0;
78      private static final byte OPCODE_TEXT = 0x1;
79      private static final byte OPCODE_BINARY = 0x2;
80      private static final byte OPCODE_CLOSE = 0x8;
81      private static final byte OPCODE_PING = 0x9;
82      private static final byte OPCODE_PONG = 0xA;
83  
84      private final boolean maskPayload;
85  
86      
87  
88  
89  
90  
91  
92  
93      public WebSocket08FrameEncoder(boolean maskPayload) {
94          this.maskPayload = maskPayload;
95      }
96  
97      @Override
98      protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
99  
100         byte[] mask;
101 
102         if (msg instanceof WebSocketFrame) {
103             WebSocketFrame frame = (WebSocketFrame) msg;
104             ChannelBuffer data = frame.getBinaryData();
105             if (data == null) {
106                 data = ChannelBuffers.EMPTY_BUFFER;
107             }
108 
109             byte opcode;
110             if (frame instanceof TextWebSocketFrame) {
111                 opcode = OPCODE_TEXT;
112             } else if (frame instanceof PingWebSocketFrame) {
113                 opcode = OPCODE_PING;
114             } else if (frame instanceof PongWebSocketFrame) {
115                 opcode = OPCODE_PONG;
116             } else if (frame instanceof CloseWebSocketFrame) {
117                 opcode = OPCODE_CLOSE;
118             } else if (frame instanceof BinaryWebSocketFrame) {
119                 opcode = OPCODE_BINARY;
120             } else if (frame instanceof ContinuationWebSocketFrame) {
121                 opcode = OPCODE_CONT;
122             } else {
123                 throw new UnsupportedOperationException("Cannot encode frame of type: " + frame.getClass().getName());
124             }
125 
126             int length = data.readableBytes();
127 
128             if (logger.isDebugEnabled()) {
129                 logger.debug("Encoding WebSocket Frame opCode=" + opcode + " length=" + length);
130             }
131 
132             int b0 = 0;
133             if (frame.isFinalFragment()) {
134                 b0 |= 1 << 7;
135             }
136             b0 |= frame.getRsv() % 8 << 4;
137             b0 |= opcode % 128;
138 
139             ChannelBuffer header;
140             ChannelBuffer body;
141 
142             if (opcode == OPCODE_PING && length > 125) {
143                 throw new TooLongFrameException("invalid payload for PING (payload length must be <= 125, was "
144                         + length);
145             }
146 
147             int maskLength = maskPayload ? 4 : 0;
148             if (length <= 125) {
149                 header = ChannelBuffers.buffer(2 + maskLength);
150                 header.writeByte(b0);
151                 byte b = (byte) (maskPayload ? 0x80 | (byte) length : (byte) length);
152                 header.writeByte(b);
153             } else if (length <= 0xFFFF) {
154                 header = ChannelBuffers.buffer(4 + maskLength);
155                 header.writeByte(b0);
156                 header.writeByte(maskPayload ? 0xFE : 126);
157                 header.writeByte(length >>> 8 & 0xFF);
158                 header.writeByte(length & 0xFF);
159             } else {
160                 header = ChannelBuffers.buffer(10 + maskLength);
161                 header.writeByte(b0);
162                 header.writeByte(maskPayload ? 0xFF : 127);
163                 header.writeLong(length);
164             }
165 
166             
167             if (maskPayload) {
168                 Integer random = (int) (Math.random() * Integer.MAX_VALUE);
169                 mask = ByteBuffer.allocate(4).putInt(random).array();
170                 header.writeBytes(mask);
171 
172                 body = ChannelBuffers.buffer(length);
173                 int counter = 0;
174                 while (data.readableBytes() > 0) {
175                     byte byteData = data.readByte();
176                     body.writeByte(byteData ^ mask[counter++ % 4]);
177                 }
178             } else {
179                 body = data;
180             }
181             return ChannelBuffers.wrappedBuffer(header, body);
182         }
183 
184         
185         return msg;
186     }
187 
188 }