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 public class LineBasedFrameDecoder extends FrameDecoder {
30
31
32 private final int maxLength;
33
34 private final boolean failFast;
35 private final boolean stripDelimiter;
36
37
38 private boolean discarding;
39 private int discardedBytes;
40
41
42
43
44
45
46
47 public LineBasedFrameDecoder(final int maxLength) {
48 this(maxLength, true, false);
49 }
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public LineBasedFrameDecoder(final int maxLength, final boolean stripDelimiter, final boolean failFast) {
67 this.maxLength = maxLength;
68 this.failFast = failFast;
69 this.stripDelimiter = stripDelimiter;
70 }
71
72 @Override
73 protected Object decode(final ChannelHandlerContext ctx,
74 final Channel channel,
75 final ChannelBuffer buffer) throws Exception {
76 final int eol = findEndOfLine(buffer);
77 if (!discarding) {
78 if (eol >= 0) {
79 final ChannelBuffer frame;
80 final int length = eol - buffer.readerIndex();
81 final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
82
83 if (length > maxLength) {
84 buffer.readerIndex(eol + delimLength);
85 fail(ctx, length);
86 return null;
87 }
88
89 try {
90 if (stripDelimiter) {
91 frame = extractFrame(buffer, buffer.readerIndex(), length);
92 } else {
93 frame = extractFrame(buffer, buffer.readerIndex(), length + delimLength);
94 }
95 } finally {
96 buffer.skipBytes(length + delimLength);
97 }
98 return frame;
99 } else {
100 final int length = buffer.readableBytes();
101 if (length > maxLength) {
102 discardedBytes = length;
103 buffer.readerIndex(buffer.writerIndex());
104 discarding = true;
105 if (failFast) {
106 fail(ctx, "over " + discardedBytes);
107 }
108 }
109 return null;
110 }
111 } else {
112 if (eol >= 0) {
113 final int length = discardedBytes + eol - buffer.readerIndex();
114 final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
115 buffer.readerIndex(eol + delimLength);
116 discardedBytes = 0;
117 discarding = false;
118 if (!failFast) {
119 fail(ctx, length);
120 }
121 } else {
122 discardedBytes = buffer.readableBytes();
123 buffer.readerIndex(buffer.writerIndex());
124 }
125 return null;
126 }
127 }
128
129 private void fail(final ChannelHandlerContext ctx, int length) {
130 fail(ctx, String.valueOf(length));
131 }
132
133 private void fail(final ChannelHandlerContext ctx, String length) {
134 Channels.fireExceptionCaught(
135 ctx.getChannel(),
136 new TooLongFrameException(
137 "frame length (" + length + ") exceeds the allowed maximum (" + maxLength + ')'));
138 }
139
140
141
142
143
144 private static int findEndOfLine(final ChannelBuffer buffer) {
145 final int n = buffer.writerIndex();
146 for (int i = buffer.readerIndex(); i < n; i ++) {
147 final byte b = buffer.getByte(i);
148 if (b == '\n') {
149 return i;
150 } else if (b == '\r' && i < n - 1 && buffer.getByte(i + 1) == '\n') {
151 return i;
152 }
153 }
154 return -1;
155 }
156 }