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