1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.frame;
17
18 import org.jboss.netty.buffer.ChannelBuffer;
19 import org.jboss.netty.channel.Channel;
20 import org.jboss.netty.channel.ChannelHandlerContext;
21 import org.jboss.netty.channel.Channels;
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
55
56
57
58
59
60
61
62
63
64
65 public class DelimiterBasedFrameDecoder extends FrameDecoder {
66
67 private final ChannelBuffer[] delimiters;
68 private final int maxFrameLength;
69 private final boolean stripDelimiter;
70 private boolean discardingTooLongFrame;
71 private int tooLongFrameLength;
72
73
74
75
76
77
78
79
80
81 public DelimiterBasedFrameDecoder(int maxFrameLength, ChannelBuffer delimiter) {
82 this(maxFrameLength, true, delimiter);
83 }
84
85
86
87
88
89
90
91
92
93
94
95 public DelimiterBasedFrameDecoder(
96 int maxFrameLength, boolean stripDelimiter, ChannelBuffer delimiter) {
97 validateMaxFrameLength(maxFrameLength);
98 validateDelimiter(delimiter);
99 delimiters = new ChannelBuffer[] {
100 delimiter.slice(
101 delimiter.readerIndex(), delimiter.readableBytes())
102 };
103 this.maxFrameLength = maxFrameLength;
104 this.stripDelimiter = stripDelimiter;
105 }
106
107
108
109
110
111
112
113
114
115 public DelimiterBasedFrameDecoder(int maxFrameLength, ChannelBuffer... delimiters) {
116 this(maxFrameLength, true, delimiters);
117 }
118
119
120
121
122
123
124
125
126
127
128
129 public DelimiterBasedFrameDecoder(
130 int maxFrameLength, boolean stripDelimiter, ChannelBuffer... delimiters) {
131 validateMaxFrameLength(maxFrameLength);
132 if (delimiters == null) {
133 throw new NullPointerException("delimiters");
134 }
135 if (delimiters.length == 0) {
136 throw new IllegalArgumentException("empty delimiters");
137 }
138 this.delimiters = new ChannelBuffer[delimiters.length];
139 for (int i = 0; i < delimiters.length; i ++) {
140 ChannelBuffer d = delimiters[i];
141 validateDelimiter(d);
142 this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes());
143 }
144 this.maxFrameLength = maxFrameLength;
145 this.stripDelimiter = stripDelimiter;
146 }
147
148 @Override
149 protected Object decode(
150 ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
151
152 int minFrameLength = Integer.MAX_VALUE;
153 ChannelBuffer minDelim = null;
154 for (ChannelBuffer delim: delimiters) {
155 int frameLength = indexOf(buffer, delim);
156 if (frameLength >= 0 && frameLength < minFrameLength) {
157 minFrameLength = frameLength;
158 minDelim = delim;
159 }
160 }
161
162 if (minDelim != null) {
163 int minDelimLength = minDelim.capacity();
164 ChannelBuffer frame;
165
166 if (discardingTooLongFrame) {
167
168
169 discardingTooLongFrame = false;
170 buffer.skipBytes(minFrameLength + minDelimLength);
171
172
173
174 int tooLongFrameLength = this.tooLongFrameLength;
175 this.tooLongFrameLength = 0;
176 fail(ctx, tooLongFrameLength);
177 return null;
178 }
179
180 if (minFrameLength > maxFrameLength) {
181
182 buffer.skipBytes(minFrameLength + minDelimLength);
183 fail(ctx, minFrameLength);
184 return null;
185 }
186
187 if (stripDelimiter) {
188 frame = buffer.readBytes(minFrameLength);
189 buffer.skipBytes(minDelimLength);
190 } else {
191 frame = buffer.readBytes(minFrameLength + minDelimLength);
192 }
193
194 return frame;
195 } else {
196 if (!discardingTooLongFrame) {
197 if (buffer.readableBytes() > maxFrameLength) {
198
199 tooLongFrameLength = buffer.readableBytes();
200 buffer.skipBytes(buffer.readableBytes());
201 discardingTooLongFrame = true;
202 }
203 } else {
204
205 tooLongFrameLength += buffer.readableBytes();
206 buffer.skipBytes(buffer.readableBytes());
207 }
208 return null;
209 }
210 }
211
212 private void fail(ChannelHandlerContext ctx, long frameLength) {
213 if (frameLength > 0) {
214 Channels.fireExceptionCaught(
215 ctx.getChannel(),
216 new TooLongFrameException(
217 "frame length exceeds " + maxFrameLength +
218 ": " + frameLength + " - discarded"));
219 } else {
220 Channels.fireExceptionCaught(
221 ctx.getChannel(),
222 new TooLongFrameException(
223 "frame length exceeds " + maxFrameLength +
224 " - discarding"));
225 }
226 }
227
228
229
230
231
232
233 private static int indexOf(ChannelBuffer haystack, ChannelBuffer needle) {
234 for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) {
235 int haystackIndex = i;
236 int needleIndex;
237 for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) {
238 if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {
239 break;
240 } else {
241 haystackIndex ++;
242 if (haystackIndex == haystack.writerIndex() &&
243 needleIndex != needle.capacity() - 1) {
244 return -1;
245 }
246 }
247 }
248
249 if (needleIndex == needle.capacity()) {
250
251 return i - haystack.readerIndex();
252 }
253 }
254 return -1;
255 }
256
257 private static void validateDelimiter(ChannelBuffer delimiter) {
258 if (delimiter == null) {
259 throw new NullPointerException("delimiter");
260 }
261 if (!delimiter.readable()) {
262 throw new IllegalArgumentException("empty delimiter");
263 }
264 }
265
266 private static void validateMaxFrameLength(int maxFrameLength) {
267 if (maxFrameLength <= 0) {
268 throw new IllegalArgumentException(
269 "maxFrameLength must be a positive integer: " +
270 maxFrameLength);
271 }
272 }
273 }