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