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.util.List;
    17
    18  import org.jboss.netty.buffer.ChannelBuffer;
    19
    20  /**
    21   * Decoder State that reads icap headers.
    22   *
    23   * @author Michael Mimo Moratti (mimo@mimo.ch)
    24   *
    25   * @see IcapMessageDecoder
    26   * @see StateEnum
    27   */
    28  public class ReadIcapHeaderState extends State<Object> {
    29
    30  	public ReadIcapHeaderState(String name) {
    31  		super(name);
    32  	}
    33
    34  	@Override
    35  	public void onEntry(ChannelBuffer buffer, IcapMessageDecoder icapMessageDecoder) throws DecodingException {
    36  		if(icapMessageDecoder.message == null) {
    37  			throw new IllegalArgumentException("This state requires a valid IcapMessage instance");
    38  		}
    39  	}
    40
    41  	@Override
    42  	public StateReturnValue execute(ChannelBuffer buffer, IcapMessageDecoder icapMessageDecoder) throws DecodingException {
    43  		List<String[]> headerList = IcapDecoderUtil.readHeaders(buffer,icapMessageDecoder.maxIcapHeaderSize);
    44  		icapMessageDecoder.message.clearHeaders();
    45  		for(String[] header : headerList) {
    46  			icapMessageDecoder.message.addHeader(header[0],header[1]);
    47  		}
    48  		boolean isRequest = icapMessageDecoder.message instanceof IcapRequest;
    49  		boolean isOptionsRequest = isRequest && ((IcapRequest)icapMessageDecoder.message).getMethod().equals(IcapMethod.OPTIONS);
    50
    51  		validateMandatoryMessageHeaders(icapMessageDecoder.message,icapMessageDecoder.isDecodingResponse(),isOptionsRequest);
    52
    53  		Encapsulated encapsulated = null;
    54  		String headerValue = icapMessageDecoder.message.getHeader(IcapHeaders.Names.ENCAPSULATED);
    55  		if(headerValue != null) {
    56  			encapsulated = new Encapsulated(icapMessageDecoder.message.getHeader(IcapHeaders.Names.ENCAPSULATED));
    57  			icapMessageDecoder.message.setEncapsulatedHeader(encapsulated);
    58  		}
    59  		if(isOptionsRequest) {
    60  			return StateReturnValue.createRelevantResult(icapMessageDecoder.message);
    61  		} else if(encapsulated != null && !encapsulated.containsEntry(IcapMessageElementEnum.REQHDR) & !encapsulated.containsEntry(IcapMessageElementEnum.RESHDR)) {
    62  			return StateReturnValue.createRelevantResult(icapMessageDecoder.message);
    63  		}
    64  		return StateReturnValue.createIrrelevantResult();
    65  	}
    66
    67  	@Override
    68  	public StateEnum onExit(ChannelBuffer buffer, IcapMessageDecoder icapMessageDecoder, Object decisionInformation) throws DecodingException {
    69  		IcapMessage message = icapMessageDecoder.message;
    70  		Encapsulated encapsulated = message.getEncapsulatedHeader();
    71  		if(message instanceof IcapRequest && ((IcapRequest)message).getMethod().equals(IcapMethod.OPTIONS)) {
    72  			if(encapsulated != null && encapsulated.containsEntry(IcapMessageElementEnum.OPTBODY)) {
    73  				return StateEnum.READ_CHUNK_SIZE_STATE;
    74  			} else {
    75  				return null;
    76  			}
    77  		} else {
    78  			IcapMessageElementEnum entry = encapsulated.getNextEntry();
    79  			if(entry != null) {
    80  				if(entry.equals(IcapMessageElementEnum.REQHDR)) {
    81  					return StateEnum.READ_HTTP_REQUEST_INITIAL_AND_HEADERS;
    82  				} else if(entry.equals(IcapMessageElementEnum.RESHDR)) {
    83  					return StateEnum.READ_HTTP_RESPONSE_INITIAL_AND_HEADERS;
    84  				} else if(entry.equals(IcapMessageElementEnum.REQBODY)) {
    85  					return StateEnum.READ_CHUNK_SIZE_STATE;
    86  				} else if(entry.equals(IcapMessageElementEnum.RESBODY)) {
    87  					return StateEnum.READ_CHUNK_SIZE_STATE;
    88  				}
    89  			}
    90  		}
    91  		return null;
    92  	}
    93
    94  	private void validateMandatoryMessageHeaders(IcapMessage message, boolean isDecodingResponse, boolean isDecodingOptionsRequest) {
    95  		if(!isDecodingResponse) {
    96  			if(!message.containsHeader(IcapHeaders.Names.HOST)) {
    97  				throw new IcapDecodingError("Mandatory ICAP message header [Host] is missing");
    98  			}
    99  		}
    100 		if(!isDecodingOptionsRequest) {
    101 			if(!message.containsHeader(IcapHeaders.Names.ENCAPSULATED)) {
    102 				throw new IcapDecodingError("Mandatory ICAP message header [Encapsulated] is missing");
    103 			}
    104 		}
    105 	}
    106
    107 }