1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelHandlerContext;
20 import io.netty.util.ByteProcessor;
21
22 import java.util.List;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public class LineBasedFrameDecoder extends ByteToMessageDecoder {
43
44
45 private final int maxLength;
46
47 private final boolean failFast;
48 private final boolean stripDelimiter;
49
50
51 private boolean discarding;
52 private int discardedBytes;
53
54
55 private int offset;
56
57
58
59
60
61
62
63 public LineBasedFrameDecoder(final int maxLength) {
64 this(maxLength, true, false);
65 }
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 public LineBasedFrameDecoder(final int maxLength, final boolean stripDelimiter, final boolean failFast) {
83 this.maxLength = maxLength;
84 this.failFast = failFast;
85 this.stripDelimiter = stripDelimiter;
86 }
87
88 @Override
89 protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
90 Object decoded = decode(ctx, in);
91 if (decoded != null) {
92 out.add(decoded);
93 }
94 }
95
96
97
98
99
100
101
102
103
104 protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
105 final int eol = findEndOfLine(buffer);
106 if (!discarding) {
107 if (eol >= 0) {
108 final ByteBuf frame;
109 final int length = eol - buffer.readerIndex();
110 final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
111
112 if (length > maxLength) {
113 buffer.readerIndex(eol + delimLength);
114 fail(ctx, length);
115 return null;
116 }
117
118 if (stripDelimiter) {
119 frame = buffer.readRetainedSlice(length);
120 buffer.skipBytes(delimLength);
121 } else {
122 frame = buffer.readRetainedSlice(length + delimLength);
123 }
124
125 return frame;
126 } else {
127 final int length = buffer.readableBytes();
128 if (length > maxLength) {
129 discardedBytes = length;
130 buffer.readerIndex(buffer.writerIndex());
131 discarding = true;
132 offset = 0;
133 if (failFast) {
134 fail(ctx, "over " + discardedBytes);
135 }
136 }
137 return null;
138 }
139 } else {
140 if (eol >= 0) {
141 final int length = discardedBytes + eol - buffer.readerIndex();
142 final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
143 buffer.readerIndex(eol + delimLength);
144 discardedBytes = 0;
145 discarding = false;
146 if (!failFast) {
147 fail(ctx, length);
148 }
149 } else {
150 discardedBytes += buffer.readableBytes();
151 buffer.readerIndex(buffer.writerIndex());
152
153 offset = 0;
154 }
155 return null;
156 }
157 }
158
159 private void fail(final ChannelHandlerContext ctx, int length) {
160 fail(ctx, String.valueOf(length));
161 }
162
163 private void fail(final ChannelHandlerContext ctx, String length) {
164 ctx.fireExceptionCaught(
165 new TooLongFrameException(
166 "frame length (" + length + ") exceeds the allowed maximum (" + maxLength + ')'));
167 }
168
169
170
171
172
173 private int findEndOfLine(final ByteBuf buffer) {
174 int totalLength = buffer.readableBytes();
175 int i = buffer.indexOf(buffer.readerIndex() + offset,
176 buffer.readerIndex() + totalLength, (byte) '\n');
177 if (i >= 0) {
178 offset = 0;
179 if (i > 0 && buffer.getByte(i - 1) == '\r') {
180 i--;
181 }
182 } else {
183 offset = totalLength;
184 }
185 return i;
186 }
187 }