1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.marshalling;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.Channel;
20 import io.netty.channel.ChannelHandlerContext;
21 import io.netty.handler.codec.ReplayingDecoder;
22 import io.netty.handler.codec.TooLongFrameException;
23 import org.jboss.marshalling.ByteInput;
24 import org.jboss.marshalling.Unmarshaller;
25
26 import java.io.ObjectStreamConstants;
27 import java.util.List;
28
29
30
31
32
33
34 public class CompatibleMarshallingDecoder extends ReplayingDecoder<Void> {
35 protected final UnmarshallerProvider provider;
36 protected final int maxObjectSize;
37 private boolean discardingTooLongFrame;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public CompatibleMarshallingDecoder(UnmarshallerProvider provider, int maxObjectSize) {
53 this.provider = provider;
54 this.maxObjectSize = maxObjectSize;
55 }
56
57 @Override
58 protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
59 if (discardingTooLongFrame) {
60 buffer.skipBytes(actualReadableBytes());
61 checkpoint();
62 return;
63 }
64
65 Unmarshaller unmarshaller = provider.getUnmarshaller(ctx);
66 ByteInput input = new ChannelBufferByteInput(buffer);
67 if (maxObjectSize != Integer.MAX_VALUE) {
68 input = new LimitingByteInput(input, maxObjectSize);
69 }
70 try {
71 unmarshaller.start(input);
72 Object obj = unmarshaller.readObject();
73 unmarshaller.finish();
74 out.add(obj);
75 } catch (LimitingByteInput.TooBigObjectException ignored) {
76 discardingTooLongFrame = true;
77 throw new TooLongFrameException();
78 } finally {
79
80
81 unmarshaller.close();
82 }
83 }
84
85 @Override
86 protected void decodeLast(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
87 switch (buffer.readableBytes()) {
88 case 0:
89 return;
90 case 1:
91
92 if (buffer.getByte(buffer.readerIndex()) == ObjectStreamConstants.TC_RESET) {
93 buffer.skipBytes(1);
94 return;
95 }
96 }
97
98 decode(ctx, buffer, out);
99 }
100
101 @Override
102 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
103 if (cause instanceof TooLongFrameException) {
104 ctx.close();
105 } else {
106 super.exceptionCaught(ctx, cause);
107 }
108 }
109 }