Package tkuri.jxy.arch

Source Code of tkuri.jxy.arch.MessageBodyHandler

/**
* (c) 2012 tkuri
*/
package tkuri.jxy.arch;

import java.nio.channels.WritableByteChannel;

import tkuri.jxy.Util;
import tkuri.uty.Bs;


/**
*
*/
public class MessageBodyHandler {


  public static enum MbhState {
    CHUNK_SIZE,
    CHUNK_BODY,
    CHUNK_CRLF,
    CHUNK_TRAILER,
    CONTENT,
    UNTIL_CLOSE,

    RECV_END,
    RECV_END_CLOSED,
    RECV_END_ERR, // 途中で切断された

    SEND_END,
    SEND_END_CLOSED,
  }

  private MbhState state_ = MbhState.CONTENT;

  private ChannelReader reader_;
  private boolean multipart_ = false;
  private int pointer_ = 0;

  public boolean isInputFine = true;
  public boolean isOutputFine = true;


  /**
   *
   * @param aReader
   * @param aInfo
   */
  public MessageBodyHandler(ChannelReader aReader, GeneralHeaderInfo aInfo) {

    reader_ = aReader;

    if (! aInfo.hasMessageBody) {
      //Util.say("no message body");
      _setState(MbhState.RECV_END);
      // nop

    } else if (aInfo.multipartFinalBorder != null) {
      // TODO
      multipart_ = true;

    } else if (aInfo.chunked) {
      _setState(MbhState.CHUNK_SIZE);

    } else if (aInfo.connectionClose) {
      _setState(MbhState.UNTIL_CLOSE);
      pointer_ = Integer.MAX_VALUE;

    } else {
      _setState(MbhState.CONTENT);
      pointer_ = (int) aInfo.contentLength;
    }
  }


  private void _setState(MbhState aS) {

    //Util.say("bodyhandler: set state: ", aS);
    state_ = aS;
  }


  public void receive() {

    if (state_.ordinal() >= MbhState.RECV_END.ordinal()) {
      return;
    }

    if (multipart_) {
      // TODO
      throw new RuntimeException("not implemented");
    }

    while (state_ == MbhState.CHUNK_SIZE
        || state_ == MbhState.CHUNK_CRLF
        || state_ == MbhState.CHUNK_TRAILER) {

      Bs line = _findNextLF();
      if (line == null) {
        break; // 次のバッファを待つ
      }
      pointer_ += line.length();

      if (state_ == MbhState.CHUNK_SIZE) {
        int size = (int) line.toLong(16);
        pointer_ += size;
        _setState( (size == 0)
            ? MbhState.CHUNK_TRAILER
            : MbhState.CHUNK_CRLF);

      } else if (state_ == MbhState.CHUNK_CRLF) {
        _setState(MbhState.CHUNK_SIZE);

      } else { // TRAILER & CRLF
        _setState(MbhState.RECV_END);
        return; // chunk 正常終了
      }
    }

    if (0 < reader_.available()) {
      // go on

    } else if (state_ == MbhState.UNTIL_CLOSE) {
      state_ = MbhState.RECV_END_CLOSED;

    } else {
      isInputFine = false;
      state_ = MbhState.RECV_END_ERR;
    }
  }


  /**
   * rv > 0   ... 処理続行
   * rv == 0  ... 処理終了,接続は存続
   * rv < 0 ... 処理終了,Connection: close のため接続断
   *
   * @throws 予期せぬ接続断時
   *         もしくは aOut.write()から例外発生時
   */
  public MbhState transferTo(WritableByteChannel aOut) throws Exception {

    if (state_.ordinal() < MbhState.SEND_END.ordinal()) {
      if (isOutputFine) {
        try {
          int wrote = reader_.through(aOut, pointer_);
          //Util.say("message body: wrote: ", wrote);
          pointer_ -= wrote;
        } catch (Exception x) {
          Util.say("message body: through: error: ", x);
          isOutputFine = false;
        }
      }

      if (! isOutputFine) {
        int size = Math.min(reader_.length(), pointer_);
        reader_.consume(size);
        pointer_ -= size;
      }
    }

    if (pointer_ == 0) {
      switch (state_) {
      case RECV_END:
        _setState(MbhState.SEND_END);
        break;

      case RECV_END_CLOSED:
        _setState(MbhState.SEND_END_CLOSED);
        break;

      case RECV_END_ERR:
        _setState(MbhState.SEND_END_CLOSED);
        break;
      }
    }

    return state_; // 処理続行
  }


  // FIXME ChannelReader が用意しているバッファサイズ以上の長さの行は読めない
  private Bs _findNextLF() {

    int lf = reader_.indexOf('\n', pointer_);
    if (lf < 0) {
      return null;
    }

    int len = lf + 1;

    Bs rv = reader_.sub(0, len);
    pointer_ += len;

    return rv;
  }
}
TOP

Related Classes of tkuri.jxy.arch.MessageBodyHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.