1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.filter.codec.prefixedstring;
21
22 import org.apache.mina.core.buffer.BufferDataException;
23 import org.apache.mina.core.buffer.IoBuffer;
24 import org.apache.mina.core.session.IoSession;
25 import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
26 import org.apache.mina.filter.codec.ProtocolDecoder;
27 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
28
29 import java.nio.charset.Charset;
30
31 /**
32 * A {@link ProtocolDecoder} which decodes a String using a fixed-length length prefix.
33 *
34 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
35 */
36 public class PrefixedStringDecoder extends CumulativeProtocolDecoder {
37
38 public final static int DEFAULT_PREFIX_LENGTH = 4;
39
40 public final static int DEFAULT_MAX_DATA_LENGTH = 2048;
41
42 private final Charset charset;
43
44 private int prefixLength = DEFAULT_PREFIX_LENGTH;
45
46 private int maxDataLength = DEFAULT_MAX_DATA_LENGTH;
47
48 /**
49 * @param charset the charset to use for encoding
50 * @param prefixLength the length of the prefix
51 * @param maxDataLength maximum number of bytes allowed for a single String
52 */
53 public PrefixedStringDecoder(Charset charset, int prefixLength, int maxDataLength) {
54 this.charset = charset;
55 this.prefixLength = prefixLength;
56 this.maxDataLength = maxDataLength;
57 }
58
59 public PrefixedStringDecoder(Charset charset, int prefixLength) {
60 this(charset, prefixLength, DEFAULT_MAX_DATA_LENGTH);
61 }
62
63 public PrefixedStringDecoder(Charset charset) {
64 this(charset, DEFAULT_PREFIX_LENGTH);
65 }
66
67 /**
68 * Sets the number of bytes used by the length prefix
69 *
70 * @param prefixLength the length of the length prefix (1, 2, or 4)
71 */
72 public void setPrefixLength(int prefixLength) {
73 this.prefixLength = prefixLength;
74 }
75
76 /**
77 * Gets the length of the length prefix (1, 2, or 4)
78 *
79 * @return length of the length prefix
80 */
81 public int getPrefixLength() {
82 return prefixLength;
83 }
84
85 /**
86 * Sets the maximum allowed value specified as data length in the incoming data
87 * <p>
88 * Useful for preventing an OutOfMemory attack by the peer.
89 * The decoder will throw a {@link BufferDataException} when data length
90 * specified in the incoming data is greater than maxDataLength
91 * The default value is {@link PrefixedStringDecoder#DEFAULT_MAX_DATA_LENGTH}.
92 * </p>
93 *
94 * @param maxDataLength maximum allowed value specified as data length in the incoming data
95 */
96 public void setMaxDataLength(int maxDataLength) {
97 this.maxDataLength = maxDataLength;
98 }
99
100 /**
101 * Gets the maximum number of bytes allowed for a single String
102 *
103 * @return maximum number of bytes allowed for a single String
104 */
105 public int getMaxDataLength() {
106 return maxDataLength;
107 }
108
109 protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
110 if (in.prefixedDataAvailable(prefixLength, maxDataLength)) {
111 String msg = in.getPrefixedString(prefixLength, charset.newDecoder());
112 out.write(msg);
113 return true;
114 }
115
116 return false;
117 }
118 }