View Javadoc

1   /*******************************************************************************
2    * Copyright (c) 2011 Michael Mimo Moratti.
3    *
4    * Michael Mimo Moratti 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 License.
6    * You may obtain a copy of the License at:
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
11   * License for the specific language governing permissions and limitations
12   * under the License.
13   *******************************************************************************/
14  package ch.mimo.netty.handler.codec.icap;
15  
16  import java.io.UnsupportedEncodingException;
17  import java.util.Map;
18  
19  import org.jboss.netty.buffer.ChannelBuffer;
20  import org.jboss.netty.buffer.ChannelBuffers;
21  import org.jboss.netty.channel.Channel;
22  import org.jboss.netty.channel.ChannelHandlerContext;
23  import org.jboss.netty.handler.codec.http.HttpRequest;
24  import org.jboss.netty.handler.codec.http.HttpResponse;
25  import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
26  import org.jboss.netty.logging.InternalLogger;
27  import org.jboss.netty.logging.InternalLoggerFactory;
28  
29  /**
30   * Main ICAP message encoder. This encoder is based on @see {@link OneToOneEncoder}
31   * 
32   * @author Michael Mimo Moratti (mimo@mimo.ch)
33   *
34   * @see IcapRequestEncoder
35   * @see IcapResponseEncoder
36   */
37  public abstract class IcapMessageEncoder extends OneToOneEncoder {
38  	
39  	private final InternalLogger LOG;
40  	
41  	public IcapMessageEncoder() {
42  		LOG = InternalLoggerFactory.getInstance(getClass());
43  	}
44  	
45  	@Override
46  	protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
47  		LOG.debug("Encoding [" + msg.getClass().getName() + "]");
48  		if(msg instanceof IcapMessage) {
49  			IcapMessage message = (IcapMessage)msg;
50              ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(channel.getConfig().getBufferFactory());
51  			encodeInitialLine(buffer,message);
52  			encodeHeaders(buffer,message);
53  			ChannelBuffer httpRequestBuffer = encodeHttpRequestHeader(message.getHttpRequest());
54  			ChannelBuffer httpResponseBuffer = encodeHttpResponseHeader(message.getHttpResponse());
55              int index = 0;
56              Encapsulated encapsulated = new Encapsulated();
57              if(httpRequestBuffer.readableBytes() > 0) {
58              	encapsulated.addEntry(IcapMessageElementEnum.REQHDR,index);
59              	httpRequestBuffer.writeBytes(IcapCodecUtil.CRLF);
60              	index += httpRequestBuffer.readableBytes();
61              }
62              if(httpResponseBuffer.readableBytes() > 0) {
63              	encapsulated.addEntry(IcapMessageElementEnum.RESHDR,index);
64              	httpResponseBuffer.writeBytes(IcapCodecUtil.CRLF);
65              	index += httpResponseBuffer.readableBytes();
66              }
67              if(message.getBodyType() != null) {
68              	encapsulated.addEntry(message.getBodyType(),index);
69              } else {
70              	encapsulated.addEntry(IcapMessageElementEnum.NULLBODY,index);
71              }
72              encapsulated.encode(buffer);
73              buffer.writeBytes(httpRequestBuffer);
74              buffer.writeBytes(httpResponseBuffer);
75              return buffer;
76  		} else if(msg instanceof IcapChunk) {
77  			ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(channel.getConfig().getBufferFactory());
78  			IcapChunk chunk = (IcapChunk)msg;
79  			if(chunk.isLast()) {
80  				if(chunk.isEarlyTerminated()) {
81  					buffer.writeBytes(IcapCodecUtil.NATIVE_IEOF_SEQUENCE);
82  					buffer.writeBytes(IcapCodecUtil.CRLF);
83  					buffer.writeBytes(IcapCodecUtil.CRLF);
84  				} else if(msg instanceof IcapChunkTrailer) { 
85  					buffer.writeByte((byte) '0');
86  					buffer.writeBytes(IcapCodecUtil.CRLF);
87  					encodeTrailingHeaders(buffer,(IcapChunkTrailer)msg);
88  					buffer.writeBytes(IcapCodecUtil.CRLF);
89  				} else {
90  					buffer.writeByte((byte) '0');
91  					buffer.writeBytes(IcapCodecUtil.CRLF);
92  					buffer.writeBytes(IcapCodecUtil.CRLF);
93  				}
94  			} else {
95  				ChannelBuffer chunkBuffer = chunk.getContent();
96  				int contentLength = chunkBuffer.readableBytes();
97  				buffer.writeBytes(Integer.toHexString(contentLength).getBytes(IcapCodecUtil.ASCII_CHARSET));
98  				buffer.writeBytes(IcapCodecUtil.CRLF);
99  				buffer.writeBytes(chunkBuffer);
100 				buffer.writeBytes(IcapCodecUtil.CRLF);
101 			}
102 			return buffer;
103 		}
104 		return null;
105 	}
106 
107 	protected abstract int encodeInitialLine(ChannelBuffer buffer, IcapMessage message)  throws Exception;
108 	
109 	private ChannelBuffer encodeHttpRequestHeader(HttpRequest httpRequest) throws UnsupportedEncodingException {
110 		ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
111 		if(httpRequest != null) {
112 			buffer.writeBytes(httpRequest.getMethod().toString().getBytes(IcapCodecUtil.ASCII_CHARSET));
113 			buffer.writeByte(IcapCodecUtil.SPACE);
114 			buffer.writeBytes(httpRequest.getUri().getBytes(IcapCodecUtil.ASCII_CHARSET));
115 			buffer.writeByte(IcapCodecUtil.SPACE);
116 			buffer.writeBytes(httpRequest.getProtocolVersion().toString().getBytes(IcapCodecUtil.ASCII_CHARSET));
117 			buffer.writeBytes(IcapCodecUtil.CRLF);
118             for (Map.Entry<String, String> h: httpRequest.getHeaders()) {
119                 encodeHeader(buffer, h.getKey(), h.getValue());
120             }
121 		}
122 		return buffer;
123 	}
124 	
125 	private ChannelBuffer encodeHttpResponseHeader(HttpResponse httpResponse) throws UnsupportedEncodingException {
126 		ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
127 		if(httpResponse != null) {
128 			buffer.writeBytes(httpResponse.getProtocolVersion().toString().getBytes(IcapCodecUtil.ASCII_CHARSET));
129 			buffer.writeByte(IcapCodecUtil.SPACE);
130 			buffer.writeBytes(httpResponse.getStatus().toString().getBytes(IcapCodecUtil.ASCII_CHARSET));
131 			buffer.writeBytes(IcapCodecUtil.CRLF);
132             for (Map.Entry<String, String> h: httpResponse.getHeaders()) {
133                 encodeHeader(buffer, h.getKey(), h.getValue());
134             }
135 		}
136 		return buffer;
137 	}
138 	
139     private int encodeTrailingHeaders(ChannelBuffer buffer, IcapChunkTrailer chunkTrailer) {
140     	int index = buffer.readableBytes();
141         for (Map.Entry<String, String> h: chunkTrailer.getHeaders()) {
142             encodeHeader(buffer, h.getKey(), h.getValue());
143         }
144         return buffer.readableBytes() - index;
145     }
146 	
147     private int encodeHeaders(ChannelBuffer buffer, IcapMessage message) {
148     	int index = buffer.readableBytes();
149         for (Map.Entry<String, String> h: message.getHeaders()) {
150             encodeHeader(buffer, h.getKey(), h.getValue());
151         }
152         return buffer.readableBytes() - index;
153     }
154     
155     private void encodeHeader(ChannelBuffer buf, String header, String value) {
156 		buf.writeBytes(header.getBytes(IcapCodecUtil.ASCII_CHARSET));
157 		buf.writeByte(IcapCodecUtil.COLON);
158 		buf.writeByte(IcapCodecUtil.SPACE);
159 		buf.writeBytes(value.getBytes(IcapCodecUtil.ASCII_CHARSET));
160 		buf.writeBytes(IcapCodecUtil.CRLF);
161     }
162 }