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 }