1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.mimo.netty.handler.codec.icap;
15
16 import org.jboss.netty.buffer.ChannelBuffer;
17 import org.jboss.netty.buffer.ChannelBuffers;
18 import org.jboss.netty.channel.ChannelHandlerContext;
19 import org.jboss.netty.channel.Channels;
20 import org.jboss.netty.channel.MessageEvent;
21 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
22 import org.jboss.netty.handler.codec.frame.TooLongFrameException;
23 import org.jboss.netty.handler.codec.http.HttpMessage;
24 import org.jboss.netty.logging.InternalLogger;
25 import org.jboss.netty.logging.InternalLoggerFactory;
26
27
28
29
30
31
32
33
34
35
36
37 public class IcapChunkAggregator extends SimpleChannelUpstreamHandler {
38
39 private static final InternalLogger LOG = InternalLoggerFactory.getInstance(IcapChunkAggregator.class);
40
41 private long maxContentLength;
42 private IcapMessageWrapper message;
43
44
45
46
47
48
49
50 public static ChannelBuffer extractHttpBodyContentFromIcapMessage(IcapMessage message) {
51 ChannelBuffer buffer = null;
52 if(message.getBodyType().equals(IcapMessageElementEnum.REQBODY) && message.getHttpRequest() != null) {
53 buffer = message.getHttpRequest().getContent();
54 } else if(message.getBodyType().equals(IcapMessageElementEnum.RESBODY) && message.getHttpResponse() != null) {
55 buffer = message.getHttpResponse().getContent();
56 } else if(message instanceof IcapResponse && message.getBodyType().equals(IcapMessageElementEnum.OPTBODY)) {
57 IcapResponse response = (IcapResponse)message;
58 buffer = response.getContent();
59 }
60 return buffer;
61 }
62
63
64
65
66
67 public IcapChunkAggregator(long maxContentLength) {
68 this.maxContentLength = maxContentLength;
69 }
70
71 @Override
72 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
73 Object msg = e.getMessage();
74 if(msg instanceof IcapMessage) {
75 LOG.debug("Aggregation of message [" + msg.getClass().getName() + "] ");
76 IcapMessage currentMessage = (IcapMessage)msg;
77 message = new IcapMessageWrapper(currentMessage);
78 if(!message.hasBody()) {
79 Channels.fireMessageReceived(ctx,message.getIcapMessage(),e.getRemoteAddress());
80 message = null;
81 return;
82 }
83 } else if(msg instanceof IcapChunkTrailer) {
84 LOG.debug("Aggregation of chunk trailer [" + msg.getClass().getName() + "] ");
85 if(message == null) {
86 ctx.sendUpstream(e);
87 } else {
88 IcapChunkTrailer trailer = (IcapChunkTrailer)msg;
89 if(trailer.getHeaderNames().size() > 0) {
90 for(String name : trailer.getHeaderNames()) {
91 message.addHeader(name,trailer.getHeader(name));
92 }
93 }
94 Channels.fireMessageReceived(ctx,message.getIcapMessage(),e.getRemoteAddress());
95 }
96 } else if(msg instanceof IcapChunk) {
97 LOG.debug("Aggregation of chunk [" + msg.getClass().getName() + "] ");
98 IcapChunk chunk = (IcapChunk)msg;
99 if(message == null) {
100 ctx.sendUpstream(e);
101 } else if(chunk.isLast()) {
102 Channels.fireMessageReceived(ctx,message.getIcapMessage(),e.getRemoteAddress());
103 message = null;
104 } else {
105 ChannelBuffer chunkBuffer = chunk.getContent();
106 ChannelBuffer content = message.getContent();
107 if(content.readableBytes() > maxContentLength - chunkBuffer.readableBytes()) {
108 throw new TooLongFrameException("ICAP content length exceeded [" + maxContentLength + "] bytes");
109 } else {
110 content.writeBytes(chunkBuffer);
111 }
112 }
113 } else {
114 ctx.sendUpstream(e);
115 }
116 }
117
118 private final class IcapMessageWrapper {
119
120 private IcapMessage message;
121 private HttpMessage relevantHttpMessage;
122 private IcapResponse icapResponse;
123 private boolean messageWithBody;
124
125 public IcapMessageWrapper(IcapMessage message) {
126 this.message = message;
127 if(message.getBodyType() != null) {
128 if(message.getBodyType().equals(IcapMessageElementEnum.REQBODY)) {
129 relevantHttpMessage = message.getHttpRequest();
130 messageWithBody = true;
131 } else if(message.getBodyType().equals(IcapMessageElementEnum.RESBODY)) {
132 relevantHttpMessage = message.getHttpResponse();
133 messageWithBody = true;
134 } else if(message instanceof IcapResponse && message.getBodyType().equals(IcapMessageElementEnum.OPTBODY)) {
135 icapResponse = (IcapResponse)message;
136 messageWithBody = true;
137 }
138 }
139 if(messageWithBody) {
140 if(relevantHttpMessage != null) {
141 if(relevantHttpMessage.getContent() == null || relevantHttpMessage.getContent().readableBytes() <= 0) {
142 relevantHttpMessage.setContent(ChannelBuffers.dynamicBuffer());
143 }
144 } else if(icapResponse != null) {
145 if(icapResponse.getContent() == null || icapResponse.getContent().readableBytes() <= 0) {
146 icapResponse.setContent(ChannelBuffers.dynamicBuffer());
147 }
148 }
149 }
150 }
151
152 public boolean hasBody() {
153 return messageWithBody;
154 }
155
156 public IcapMessage getIcapMessage() {
157 return message;
158 }
159
160 public void addHeader(String name, String value) {
161 if(messageWithBody) {
162 relevantHttpMessage.addHeader(name,value);
163 } else {
164 throw new IcapDecodingError("A message without body cannot carry trailing headers.");
165 }
166 }
167
168 public ChannelBuffer getContent() {
169 if(messageWithBody) {
170 if(relevantHttpMessage != null) {
171 return relevantHttpMessage.getContent();
172 } else if(icapResponse != null) {
173 return icapResponse.getContent();
174 }
175 }
176 throw new IcapDecodingError("Message stated that there is a body but nothing found in message.");
177 }
178 }
179 }