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