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 org.jboss.netty.buffer.ChannelBuffer;
    17
    18  /**
    19   * Decoder State that reads chunk size
    20   *
    21   * @author Michael Mimo Moratti (mimo@mimo.ch)
    22   *
    23   * @see IcapMessageDecoder
    24   * @see StateEnum
    25   */
    26  public class ReadChunkSizeState extends State<ReadChunkSizeState.DecisionState> {
    27
    28  	/**
    29  	 * Used to decide what state has to be processed next.
    30  	 *
    31  	 * @author Michael Mimo Moratti (mimo@mimo.ch)
    32  	 *
    33  	 */
    34  	public static enum DecisionState {
    35  		READ_CHUNK(StateEnum.READ_CHUNK_STATE),
    36  		READ_HUGE_CHUNK_IN_SMALER_CHUNKS(StateEnum.READ_CHUNKED_CONTENT_AS_CHUNKS_STATE),
    37  		READ_TRAILING_HEADERS(StateEnum.READ_TRAILING_HEADERS_STATE),
    38  		IS_LAST_PREVIEW_CHUNK(StateEnum.READ_CHUNK_SIZE_STATE),
    39  		IS_LAST_CHUNK(StateEnum.SKIP_CONTROL_CHARS),
    40  		RESET(null);
    41
    42  		private StateEnum state;
    43
    44  		DecisionState(StateEnum nextState) {
    45  			state = nextState;
    46  		}
    47
    48  		public StateEnum getNextState() {
    49  			return state;
    50  		}
    51  	}
    52
    53  	public ReadChunkSizeState(String name) {
    54  		super(name);
    55  	}
    56
    57  	@Override
    58  	public void onEntry(ChannelBuffer buffer, IcapMessageDecoder icapMessageDecoder) throws DecodingException {
    59  	}
    60
    61  	@Override
    62  	/**
    63  	 * 1. chunk size is not 0 --> normal chunk reading is required. (go to chunk reading)
    64  	 * 2. chunk size is 0 --> end of body (end of processing)
    65  	 * 3. chunk size is 0 and we are in preview mode / preview is therefore sent and possible more is to come. (stay in state)
    66  	 * 4. chunk size is 0; ieof early end of preview (stay in state)
    67  	 * 5. next message arrives and we are still in preview mode. (step out and start over)
    68  	 *
    69  	 * Strategy:
    70  	 *
    71  	 * 1. preview read next line
    72  	 * 2. attempt to parse chunk length
    73  	 * 2a. chunk length could not be parsed step out (END STATE/reset).
    74  	 * 2b. chunk length could be parsed, adjust readerIndex by reading the line.
    75  	 * 3. chunk size > 0, read the next chunk. (END STATE).
    76  	 * 4. chunk size == -1, early termination of preview reading process. Stay in state and wait for more data.
    77  	 * 5. chunk size == 0 and message is preview message. Stay in state and wait for more data.
    78  	 * 6. chunk size == 0 step out (END STATE/reset).
    79  	 */
    80  	public StateReturnValue execute(ChannelBuffer buffer, IcapMessageDecoder icapMessageDecoder) throws DecodingException {
    81  		int chunkSize = 0;
    82  		String previewLine = IcapDecoderUtil.previewLine(buffer,icapMessageDecoder.maxInitialLineLength);
    83  		try {
    84  			chunkSize = IcapDecoderUtil.getChunkSize(previewLine);
    85  			IcapDecoderUtil.readLine(buffer,icapMessageDecoder.maxInitialLineLength);
    86  		} catch(DecodingException de) {
    87  			return StateReturnValue.createIrrelevantResultWithDecisionInformation(DecisionState.RESET);
    88  		}
    89  		icapMessageDecoder.currentChunkSize = chunkSize;
    90  		if(chunkSize > 0) {
    91  			if(chunkSize >= icapMessageDecoder.maxChunkSize) {
    92  				return StateReturnValue.createIrrelevantResultWithDecisionInformation(DecisionState.READ_HUGE_CHUNK_IN_SMALER_CHUNKS);
    93  			} else {
    94  				return StateReturnValue.createIrrelevantResultWithDecisionInformation(DecisionState.READ_CHUNK);
    95  			}
    96  		} else if(chunkSize == -1) {
    97  			icapMessageDecoder.currentChunkSize = 0;
    98  			IcapDecoderUtil.readLine(buffer,Integer.MAX_VALUE);
    99  			return StateReturnValue.createRelevantResultWithDecisionInformation(new DefaultIcapChunkTrailer(true,true),DecisionState.IS_LAST_PREVIEW_CHUNK);
    100 		} else if(chunkSize == 0) {
    101 			if(!checkForLineBreak(buffer)) {
    102 				return StateReturnValue.createIrrelevantResultWithDecisionInformation(DecisionState.READ_TRAILING_HEADERS);
    103 			}
    104 			IcapDecoderUtil.readLine(buffer,10);
    105 			if(icapMessageDecoder.message.isPreviewMessage()) {
    106 				return StateReturnValue.createRelevantResultWithDecisionInformation(new DefaultIcapChunkTrailer(true,false),DecisionState.IS_LAST_PREVIEW_CHUNK);
    107 			} else {
    108 				return StateReturnValue.createRelevantResultWithDecisionInformation(new DefaultIcapChunkTrailer(icapMessageDecoder.message.isPreviewMessage(),false),DecisionState.IS_LAST_CHUNK);
    109 			}
    110 		} else {
    111 			return StateReturnValue.createIrrelevantResultWithDecisionInformation(DecisionState.RESET);
    112 		}
    113 	}
    114
    115 	@Override
    116 	public StateEnum onExit(ChannelBuffer buffer, IcapMessageDecoder icapMessageDecoder, DecisionState decisionInformation) throws DecodingException {
    117 		return decisionInformation.getNextState();
    118 	}
    119
    120 	private boolean checkForLineBreak(ChannelBuffer buffer) {
    121 		byte previewByte = buffer.getByte(buffer.readerIndex() + 1);
    122 		return previewByte == IcapCodecUtil.CR | previewByte == IcapCodecUtil.LF;
    123 	}
    124 }