1 /*
2 * Copyright 2009 Red Hat, Inc.
3 *
4 * Red Hat licenses this file to you under the Apache License, version 2.0
5 * (the "License"); you may not use this file except in compliance with the
6 * 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.serialization;
17
18 import java.io.InputStream;
19 import java.io.ObjectInputStream;
20 import java.io.ObjectOutputStream;
21 import java.io.ObjectStreamConstants;
22
23 import org.jboss.netty.buffer.ChannelBuffer;
24 import org.jboss.netty.buffer.ChannelBufferInputStream;
25 import org.jboss.netty.channel.Channel;
26 import org.jboss.netty.channel.ChannelHandlerContext;
27 import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
28
29 /**
30 * A decoder which deserializes the received {@link ChannelBuffer}s into Java
31 * objects (interoperability version).
32 * <p>
33 * This decoder is interoperable with the standard Java object
34 * streams such as {@link ObjectInputStream} and {@link ObjectOutputStream}.
35 * <p>
36 * However, this decoder might perform worse than {@link ObjectDecoder} if
37 * the serialized object is big and complex. Also, it does not limit the
38 * maximum size of the object, and consequently your application might face
39 * the risk of <a href="http://en.wikipedia.org/wiki/DoS">DoS attack</a>.
40 * Please use {@link ObjectEncoder} and {@link ObjectDecoder} if you are not
41 * required to keep the interoperability with the standard object streams.
42 *
43 * @deprecated This decoder has a known critical bug which fails to decode and
44 * raises a random exception in some circumstances. Avoid to use
45 * it whenever you can. The only workaround is to replace
46 * {@link CompatibleObjectEncoder}, {@link CompatibleObjectDecoder},
47 * {@link ObjectInputStream}, and {@link ObjectOutputStream} with
48 * {@link ObjectEncoder}, {@link ObjectDecoder},
49 * {@link ObjectEncoderOutputStream}, and
50 * {@link ObjectDecoderInputStream} respectively. This workaround
51 * requires both a client and a server to be modified.
52 *
53 * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
54 * @author <a href="http://gleamynode.net/">Trustin Lee</a>
55 *
56 * @version $Rev: 2188 $, $Date: 2010-02-19 18:00:00 +0900 (Fri, 19 Feb 2010) $
57 */
58 @Deprecated
59 public class CompatibleObjectDecoder extends ReplayingDecoder<CompatibleObjectDecoderState> {
60
61 private final SwitchableInputStream bin = new SwitchableInputStream();
62 private ObjectInputStream oin;
63
64 /**
65 * Creates a new decoder.
66 */
67 public CompatibleObjectDecoder() {
68 super(CompatibleObjectDecoderState.READ_HEADER);
69 }
70
71 /**
72 * Creates a new {@link ObjectInputStream} which wraps the specified
73 * {@link InputStream}. Override this method to use a subclass of the
74 * {@link ObjectInputStream}.
75 */
76 protected ObjectInputStream newObjectInputStream(InputStream in) throws Exception {
77 return new ObjectInputStream(in);
78 }
79
80 @Override
81 protected Object decode(
82 ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, CompatibleObjectDecoderState state) throws Exception {
83 bin.switchStream(new ChannelBufferInputStream(buffer));
84 switch (state) {
85 case READ_HEADER:
86 oin = newObjectInputStream(bin);
87 checkpoint(CompatibleObjectDecoderState.READ_OBJECT);
88 case READ_OBJECT:
89 return oin.readObject();
90 default:
91 throw new IllegalStateException("Unknown state: " + state);
92 }
93 }
94
95 @Override
96 protected Object decodeLast(ChannelHandlerContext ctx, Channel channel,
97 ChannelBuffer buffer, CompatibleObjectDecoderState state)
98 throws Exception {
99 switch (buffer.readableBytes()) {
100 case 0:
101 return null;
102 case 1:
103 // Ignore the last TC_RESET
104 if (buffer.getByte(buffer.readerIndex()) == ObjectStreamConstants.TC_RESET) {
105 buffer.skipBytes(1);
106 oin.close();
107 return null;
108 }
109 }
110
111 Object decoded = decode(ctx, channel, buffer, state);
112 oin.close();
113 return decoded;
114 }
115 }