001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.filter.codec.prefixedstring; 021 022import org.apache.mina.core.buffer.BufferDataException; 023import org.apache.mina.core.buffer.IoBuffer; 024import org.apache.mina.core.session.IoSession; 025import org.apache.mina.filter.codec.CumulativeProtocolDecoder; 026import org.apache.mina.filter.codec.ProtocolDecoder; 027import org.apache.mina.filter.codec.ProtocolDecoderOutput; 028 029import java.nio.charset.Charset; 030 031/** 032 * A {@link ProtocolDecoder} which decodes a String using a fixed-length length prefix. 033 * 034 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 035 */ 036public class PrefixedStringDecoder extends CumulativeProtocolDecoder { 037 038 public final static int DEFAULT_PREFIX_LENGTH = 4; 039 040 public final static int DEFAULT_MAX_DATA_LENGTH = 2048; 041 042 private final Charset charset; 043 044 private int prefixLength = DEFAULT_PREFIX_LENGTH; 045 046 private int maxDataLength = DEFAULT_MAX_DATA_LENGTH; 047 048 /** 049 * @param charset the charset to use for encoding 050 * @param prefixLength the length of the prefix 051 * @param maxDataLength maximum number of bytes allowed for a single String 052 */ 053 public PrefixedStringDecoder(Charset charset, int prefixLength, int maxDataLength) { 054 this.charset = charset; 055 this.prefixLength = prefixLength; 056 this.maxDataLength = maxDataLength; 057 } 058 059 public PrefixedStringDecoder(Charset charset, int prefixLength) { 060 this(charset, prefixLength, DEFAULT_MAX_DATA_LENGTH); 061 } 062 063 public PrefixedStringDecoder(Charset charset) { 064 this(charset, DEFAULT_PREFIX_LENGTH); 065 } 066 067 /** 068 * Sets the number of bytes used by the length prefix 069 * 070 * @param prefixLength the length of the length prefix (1, 2, or 4) 071 */ 072 public void setPrefixLength(int prefixLength) { 073 this.prefixLength = prefixLength; 074 } 075 076 /** 077 * Gets the length of the length prefix (1, 2, or 4) 078 * 079 * @return length of the length prefix 080 */ 081 public int getPrefixLength() { 082 return prefixLength; 083 } 084 085 /** 086 * Sets the maximum allowed value specified as data length in the incoming data 087 * <p> 088 * Useful for preventing an OutOfMemory attack by the peer. 089 * The decoder will throw a {@link BufferDataException} when data length 090 * specified in the incoming data is greater than maxDataLength 091 * The default value is {@link PrefixedStringDecoder#DEFAULT_MAX_DATA_LENGTH}. 092 * </p> 093 * 094 * @param maxDataLength maximum allowed value specified as data length in the incoming data 095 */ 096 public void setMaxDataLength(int maxDataLength) { 097 this.maxDataLength = maxDataLength; 098 } 099 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}