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 /** The default length for the prefix */ 38 public static final int DEFAULT_PREFIX_LENGTH = 4; 39 40 /** The default maximum data length */ 41 public static final int DEFAULT_MAX_DATA_LENGTH = 2048; 42 43 private final Charset charset; 44 45 private int prefixLength = DEFAULT_PREFIX_LENGTH; 46 47 private int maxDataLength = DEFAULT_MAX_DATA_LENGTH; 48 49 /** 50 * Creates a new PrefixedStringDecoder instance 51 * 52 * @param charset the {@link Charset} to use for decoding 53 * @param prefixLength the length of the prefix 54 * @param maxDataLength maximum number of bytes allowed for a single String 55 */ 56 public PrefixedStringDecoder(Charset charset, int prefixLength, int maxDataLength) { 57 this.charset = charset; 58 this.prefixLength = prefixLength; 59 this.maxDataLength = maxDataLength; 60 } 61 62 /** 63 * Creates a new PrefixedStringDecoder instance 64 * 65 * @param charset the {@link Charset} to use for decoding 66 * @param prefixLength the length of the prefix 67 */ 68 public PrefixedStringDecoder(Charset charset, int prefixLength) { 69 this(charset, prefixLength, DEFAULT_MAX_DATA_LENGTH); 70 } 71 72 /** 73 * Creates a new PrefixedStringDecoder instance 74 * 75 * @param charset the {@link Charset} to use for decoding 76 */ 77 public PrefixedStringDecoder(Charset charset) { 78 this(charset, DEFAULT_PREFIX_LENGTH); 79 } 80 81 /** 82 * Sets the number of bytes used by the length prefix 83 * 84 * @param prefixLength the length of the length prefix (1, 2, or 4) 85 */ 86 public void setPrefixLength(int prefixLength) { 87 this.prefixLength = prefixLength; 88 } 89 90 /** 91 * Gets the length of the length prefix (1, 2, or 4) 92 * 93 * @return length of the length prefix 94 */ 95 public int getPrefixLength() { 96 return prefixLength; 97 } 98 99 /** 100 * Sets the maximum allowed value specified as data length in the incoming data 101 * <p> 102 * Useful for preventing an OutOfMemory attack by the peer. 103 * The decoder will throw a {@link BufferDataException} when data length 104 * specified in the incoming data is greater than maxDataLength 105 * The default value is {@link PrefixedStringDecoder#DEFAULT_MAX_DATA_LENGTH}. 106 * </p> 107 * 108 * @param maxDataLength maximum allowed value specified as data length in the incoming data 109 */ 110 public void setMaxDataLength(int maxDataLength) { 111 this.maxDataLength = maxDataLength; 112 } 113 114 /** 115 * Gets the maximum number of bytes allowed for a single String 116 * 117 * @return maximum number of bytes allowed for a single String 118 */ 119 public int getMaxDataLength() { 120 return maxDataLength; 121 } 122 123 /** 124 * {@inheritDoc} 125 */ 126 @Override 127 protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { 128 if (in.prefixedDataAvailable(prefixLength, maxDataLength)) { 129 String msg = in.getPrefixedString(prefixLength, charset.newDecoder()); 130 out.write(msg); 131 return true; 132 } 133 134 return false; 135 } 136 }