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 }