1 /*
2 * Copyright 2012 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package org.jboss.netty.handler.codec.marshalling;
17
18 import java.io.ObjectStreamConstants;
19
20 import org.jboss.marshalling.ByteInput;
21 import org.jboss.marshalling.Unmarshaller;
22 import org.jboss.netty.buffer.ChannelBuffer;
23 import org.jboss.netty.channel.Channel;
24 import org.jboss.netty.channel.ChannelHandlerContext;
25 import org.jboss.netty.channel.ExceptionEvent;
26 import org.jboss.netty.handler.codec.frame.TooLongFrameException;
27 import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
28 import org.jboss.netty.handler.codec.replay.VoidEnum;
29
30 /**
31 * {@link ReplayingDecoder} which use an {@link Unmarshaller} to read the Object out of the {@link ChannelBuffer}.
32 *
33 * If you can you should use {@link MarshallingDecoder}.
34 *
35 *
36 *
37 */
38 public class CompatibleMarshallingDecoder extends ReplayingDecoder<VoidEnum> {
39 protected final UnmarshallerProvider provider;
40 protected final int maxObjectSize;
41
42 /**
43 * Create a new instance of {@link CompatibleMarshallingDecoder}.
44 *
45 * @param provider
46 * the {@link UnmarshallerProvider} which is used to obtain the {@link Unmarshaller}
47 * for the {@link Channel}
48 * @param maxObjectSize
49 * the maximal size (in bytes) of the {@link Object} to unmarshal. Once the size is
50 * exceeded the {@link Channel} will get closed. Use a a maxObjectSize of
51 * {@link Integer#MAX_VALUE} to disable this. You should only do this if you are sure
52 * that the received Objects will never be big and the sending side are trusted, as
53 * this opens the possibility for a DOS-Attack due an {@link OutOfMemoryError}.
54 */
55 public CompatibleMarshallingDecoder(UnmarshallerProvider provider, int maxObjectSize) {
56 this.provider = provider;
57 this.maxObjectSize = maxObjectSize;
58 }
59
60 @Override
61 protected Object decode(
62 ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception {
63 Unmarshaller unmarshaller = provider.getUnmarshaller(ctx);
64 ByteInput input = new ChannelBufferByteInput(buffer);
65 if (maxObjectSize != Integer.MAX_VALUE) {
66 input = new LimitingByteInput(input, maxObjectSize);
67 }
68 try {
69 unmarshaller.start(input);
70 Object obj = unmarshaller.readObject();
71 unmarshaller.finish();
72 return obj;
73 } catch (LimitingByteInput.TooBigObjectException e) {
74 throw new TooLongFrameException("Object to big to unmarshal");
75 } finally {
76 // Call close in a finally block as the ReplayingDecoder will throw an Error if not enough bytes are
77 // readable. This helps to be sure that we do not leak resource
78 unmarshaller.close();
79 }
80 }
81
82 @Override
83 protected Object decodeLast(ChannelHandlerContext ctx, Channel channel,
84 ChannelBuffer buffer, VoidEnum state)
85 throws Exception {
86 switch (buffer.readableBytes()) {
87 case 0:
88 return null;
89 case 1:
90 // Ignore the last TC_RESET
91 if (buffer.getByte(buffer.readerIndex()) == ObjectStreamConstants.TC_RESET) {
92 buffer.skipBytes(1);
93 return null;
94 }
95 }
96
97 Object decoded = decode(ctx, channel, buffer, state);
98 return decoded;
99 }
100
101 /**
102 * Calls {@link Channel#close()} if a TooLongFrameException was thrown
103 */
104 @Override
105 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
106 if (e.getCause() instanceof TooLongFrameException) {
107 e.getChannel().close();
108
109 } else {
110 super.exceptionCaught(ctx, e);
111 }
112 }
113 }