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 != null) {
53 if(message.getHttpRequest() != null && message.getHttpRequest().getContent().readableBytes() > 0) {
54 buffer = message.getHttpRequest().getContent();
55 } else if(message.getHttpResponse() != null && message.getHttpResponse().getContent().readableBytes() > 0) {
56 buffer = message.getHttpResponse().getContent();
57 } else if(message instanceof IcapResponse) {
58 if(((IcapResponse) message).getContent().readableBytes() > 0) {
59 buffer = ((IcapResponse) message).getContent();
60 }
61 }
62 }
63 return buffer;
64 }
65
66
67
68
69
70 public IcapChunkAggregator(long maxContentLength) {
71 this.maxContentLength = maxContentLength;
72 }
73
74 @Override
75 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
76 Object msg = e.getMessage();
77 if(msg instanceof IcapMessage) {
78 LOG.debug("Aggregation of message [" + msg.getClass().getName() + "] ");
79 IcapMessage currentMessage = (IcapMessage)msg;
80 message = new IcapMessageWrapper(currentMessage);
81 if(!message.hasBody()) {
82 Channels.fireMessageReceived(ctx,message.getIcapMessage(),e.getRemoteAddress());
83 message = null;
84 return;
85 }
86 } else if(msg instanceof IcapChunkTrailer) {
87 LOG.debug("Aggregation of chunk trailer [" + msg.getClass().getName() + "] ");
88 if(message == null) {
89 ctx.sendUpstream(e);
90 } else {
91 IcapChunkTrailer trailer = (IcapChunkTrailer)msg;
92 if(trailer.getHeaderNames().size() > 0) {
93 for(String name : trailer.getHeaderNames()) {
94 message.addHeader(name,trailer.getHeader(name));
95 }
96 }
97 Channels.fireMessageReceived(ctx,message.getIcapMessage(),e.getRemoteAddress());
98 }
99 } else if(msg instanceof IcapChunk) {
100 LOG.debug("Aggregation of chunk [" + msg.getClass().getName() + "] ");
101 IcapChunk chunk = (IcapChunk)msg;
102 if(message == null) {
103 ctx.sendUpstream(e);
104 } else if(chunk.isLast()) {
105 Channels.fireMessageReceived(ctx,message.getIcapMessage(),e.getRemoteAddress());
106 message = null;
107 } else {
108 ChannelBuffer chunkBuffer = chunk.getContent();
109 ChannelBuffer content = message.getContent();
110 if(content.readableBytes() > maxContentLength - chunkBuffer.readableBytes()) {
111 throw new TooLongFrameException("ICAP content length exceeded [" + maxContentLength + "] bytes");
112 } else {
113 content.writeBytes(chunkBuffer);
114 }
115 }
116 } else {
117 ctx.sendUpstream(e);
118 }
119 }
120
121 private final class IcapMessageWrapper {
122
123 private IcapMessage message;
124 private HttpMessage relevantHttpMessage;
125 private IcapResponse icapResponse;
126 private boolean messageWithBody;
127
128 public IcapMessageWrapper(IcapMessage message) {
129 this.message = message;
130 if(message.getBodyType() != null) {
131 if(message.getBodyType().equals(IcapMessageElementEnum.REQBODY)) {
132 relevantHttpMessage = message.getHttpRequest();
133 messageWithBody = true;
134 } else if(message.getBodyType().equals(IcapMessageElementEnum.RESBODY)) {
135 relevantHttpMessage = message.getHttpResponse();
136 messageWithBody = true;
137 } else if(message instanceof IcapResponse && message.getBodyType().equals(IcapMessageElementEnum.OPTBODY)) {
138 icapResponse = (IcapResponse)message;
139 messageWithBody = true;
140 }
141 }
142 if(messageWithBody) {
143 if(relevantHttpMessage != null) {
144 if(relevantHttpMessage.getContent() == null || relevantHttpMessage.getContent().readableBytes() <= 0) {
145 relevantHttpMessage.setContent(ChannelBuffers.dynamicBuffer());
146 }
147 } else if(icapResponse != null) {
148 if(icapResponse.getContent() == null || icapResponse.getContent().readableBytes() <= 0) {
149 icapResponse.setContent(ChannelBuffers.dynamicBuffer());
150 }
151 }
152 }
153 }
154
155 public boolean hasBody() {
156 return messageWithBody;
157 }
158
159 public IcapMessage getIcapMessage() {
160 return message;
161 }
162
163 public void addHeader(String name, String value) {
164 if(messageWithBody) {
165 relevantHttpMessage.addHeader(name,value);
166 } else {
167 throw new IcapDecodingError("A message without body cannot carry trailing headers.");
168 }
169 }
170
171 public ChannelBuffer getContent() {
172 if(messageWithBody) {
173 if(relevantHttpMessage != null) {
174 return relevantHttpMessage.getContent();
175 } else if(icapResponse != null) {
176 return icapResponse.getContent();
177 }
178 }
179 throw new IcapDecodingError("Message stated that there is a body but nothing found in message.");
180 }
181 }
182 }