View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.filter.codec.statemachine;
    21
    22  import org.apache.mina.core.buffer.IoBuffer;
    23  import org.apache.mina.filter.codec.ProtocolDecoderOutput;
    24
    25  /**
    26   * {@link DecodingState} which consumes all bytes until a <code>CRLF</code>
    27   * has been encountered.
    28   *
    29   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    30   */
    31  public abstract class ConsumeToCrLfDecodingState implements DecodingState {
    32
    33      /**
    34       * Carriage return character
    35       */
    36      private static final byte CR = 13;
    37
    38      /**
    39       * Line feed character
    40       */
    41      private static final byte LF = 10;
    42
    43      private boolean lastIsCR;
    44
    45      private IoBuffer buffer;
    46
    47      /**
    48       * Creates a new instance.
    49       */
    50      public ConsumeToCrLfDecodingState() {
    51          // Do nothing
    52      }
    53
    54      public DecodingState decode(IoBuffer in, ProtocolDecoderOutput out) throws Exception {
    55          int beginPos = in.position();
    56          int limit = in.limit();
    57          int terminatorPos = -1;
    58
    59          for (int i = beginPos; i < limit; i++) {
    60              byte b = in.get(i);
    61              if (b == CR) {
    62                  lastIsCR = true;
    63              } else {
    64                  if (b == LF && lastIsCR) {
    65                      terminatorPos = i;
    66                      break;
    67                  }
    68                  lastIsCR = false;
    69              }
    70          }
    71
    72          if (terminatorPos >= 0) {
    73              IoBuffer product;
    74
    75              int endPos = terminatorPos - 1;
    76
    77              if (beginPos < endPos) {
    78                  in.limit(endPos);
    79
    80                  if (buffer == null) {
    81                      product = in.slice();
    82                  } else {
    83                      buffer.put(in);
    84                      product = buffer.flip();
    85                      buffer = null;
    86                  }
    87
    88                  in.limit(limit);
    89              } else {
    90                  // When input contained only CR or LF rather than actual data...
    91                  if (buffer == null) {
    92                      product = IoBuffer.allocate(0);
    93                  } else {
    94                      product = buffer.flip();
    95                      buffer = null;
    96                  }
    97              }
    98              in.position(terminatorPos + 1);
    99              return finishDecode(product, out);
    100         }
    101
    102         in.position(beginPos);
    103
    104         if (buffer == null) {
    105             buffer = IoBuffer.allocate(in.remaining());
    106             buffer.setAutoExpand(true);
    107         }
    108
    109         buffer.put(in);
    110
    111         if (lastIsCR) {
    112             buffer.position(buffer.position() - 1);
    113         }
    114
    115         return this;
    116     }
    117
    118     /**
    119      * {@inheritDoc}
    120      */
    121     public DecodingState finishDecode(ProtocolDecoderOutput out) throws Exception {
    122         IoBuffer product;
    123         // When input contained only CR or LF rather than actual data...
    124         if (buffer == null) {
    125             product = IoBuffer.allocate(0);
    126         } else {
    127             product = buffer.flip();
    128             buffer = null;
    129         }
    130         return finishDecode(product, out);
    131     }
    132
    133     /**
    134      * Invoked when this state has reached a <code>CRLF</code>.
    135      *
    136      * @param product the read bytes including the <code>CRLF</code>.
    137      * @param out the current {@link ProtocolDecoderOutput} used to write
    138      *        decoded messages.
    139      * @return the next state if a state transition was triggered (use
    140      *         <code>this</code> for loop transitions) or <code>null</code> if
    141      *         the state machine has reached its end.
    142      * @throws Exception if the read data violated protocol specification.
    143      */
    144     protected abstract DecodingState finishDecode(IoBuffer product, ProtocolDecoderOutput out) throws Exception;
    145 }