Package org.xlightweb

Source Code of org.xlightweb.AbstractHttpProtocolHandler

/*
*  Copyright (c) xlightweb.org, 2008 - 2009. All rights reserved.
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; either
*  version 2.1 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
* The latest copy of this software may be found on http://www.xlightweb.org/
*/
package org.xlightweb;

import static org.xlightweb.HttpUtils.CR;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.xlightweb.AbstractHttpConnection.IMessageHandler;
import org.xlightweb.AbstractHttpConnection.IMessageHeaderHandler;
import org.xsocket.DataConverter;



/**
* protocol handler definition
* @author grro@xlightweb.org
*/
abstract class AbstractHttpProtocolHandler {
   
    private static final Logger LOG = Logger.getLogger(AbstractHttpProtocolHandler.class.getName());
   
   
  static final int BODY_TYPE_EMTPY = 0;
  static final int FULL_MESSAGE = 1;
  static final int BODY_TYPE_CHUNKED = 2;
  static final int BODY_TYPE_SIMPLE = 3;
  static final int BODY_TYPE_MULTIPART_BYTERANGE = 4;
 
 
  static final int RECEIVING_HEADER = 5;
  static final int RECEIVING_BODY = 10;

  private int state = RECEIVING_HEADER;

  private AbstractNetworkBodyDataSource dataSource = null;
    private IMessageHandler messageHandler = null;
   
   
    // statisitics
    int received = 0;
   
   
    final void incReveived(int addSize) {
        received += addSize;
    }
   
    final int getReceived() {
        return received;
    }
   
   
  final void setState(int state) {
    this.state = state;
  }
 
  final int getState() {
    return state;
  }
   
    final void setBodyDataSource(AbstractNetworkBodyDataSource dataSource) {
        this.dataSource = dataSource;
    }
 
    final AbstractNetworkBodyDataSource getBodyDataSource() {
        return dataSource;
    }
   
  final void setMessageHandler(IMessageHandler messageHandler) {
      this.messageHandler = messageHandler;
  }
 
  final IMessageHandler getMessageHandler() {
        return messageHandler;
    }
 

 
  static String extractString(int posStart, int length, ByteBuffer buffer) {
        byte[] data = new byte[length];
       
        buffer.position(posStart);
        buffer.get(data);

        try {
            return new String(data, "ISO-8859-1");
        } catch (UnsupportedEncodingException usee) {
            throw new RuntimeException(usee);
        }
    }
   
 
  static void updateMergedBuffers(ByteBuffer buffer, int offset, ByteBuffer[] rawBuffer) {
        int length = buffer.position() - offset;
           
        for (ByteBuffer buf : rawBuffer) {
            int remaining = buf.remaining();
            if (remaining < length) {
                buf.position(buf.limit());
                length -= remaining;
            } else {
                buf.position(buf.position() + length);
                break;
            }
        }
    }
 

    static String extractStringWithoutTailingCR(int posStart, int length, ByteBuffer buffer) {
        buffer.position(posStart + length - 1);
        if (buffer.get() == CR) {
            length -= 1;
            if (length == -1) { // no value?
                return "";
            }
        }
       
        byte[] data = new byte[length];
       
        buffer.position(posStart);
        buffer.get(data);

        try {
            return new String(data, "ISO-8859-1");
        } catch (UnsupportedEncodingException usee) {
            throw new RuntimeException(usee);
        }
    }

   
    static int extractInt(int posStart, int length, ByteBuffer buffer) {
        String s = extractString(posStart, length, buffer);
        return Integer.parseInt(s);
    }

 
 
  public final ByteBuffer[] onData(AbstractHttpConnection httpConnection, ByteBuffer[] rawData) throws BadMessageException, IOException {
   
    try {
      switch (state) {
     
        case RECEIVING_HEADER:
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("parsing header");
            }
          return parseHeader(httpConnection, rawData);
                   
        default// RECEIVING_BODY
                    if (LOG.isLoggable(Level.FINE)) {
                        LOG.fine("parsing body (" + this.getClass().getName() + "#" + this.hashCode() + ")");
                    }
          rawData = parserBody(httpConnection, rawData);
          if (rawData != null) {
            return onData(httpConnection, rawData);
          }
      }
     
    } catch (BufferUnderflowException ignore) {
       
    } catch (Exception e) {
        IOException ioe = null;
        if (e instanceof IOException) {
            ioe = (IOException) e;
        } else {
            ioe = HttpUtils.toIOException(e);
        }
        if (messageHandler != null) {
            messageHandler.onBodyException(ioe, rawData);
        }
            throw ioe;
    }
   
    return HttpUtils.compact(rawData);
  }
 
 
 
    final ByteBuffer[] parserBody(AbstractHttpConnection httpConnection, ByteBuffer[] rawData) throws IOException {

        dataSource.parse(rawData);
        if (dataSource.isComplete()) {
            IMessageHandler mh = messageHandler;
            reset();
           
            if (mh != null) {
                mh.onMessageReceived();
            }
        }
       
        rawData = HttpUtils.compact(rawData);
       
        // next response? (-> pipelining)
        if (rawData != null) {
            return this.onData(httpConnection, rawData);
           
        } else {
            return rawData;
        }
    }    

    void reset() {
        setState(RECEIVING_HEADER);
        messageHandler = null;
        dataSource = null;
    }
   

    abstract ByteBuffer[] parseHeader(AbstractHttpConnection httpConnection, ByteBuffer[] rawData) throws BadMessageException, IOException;
   
  
 
 
 
  final void onDisconnect(AbstractHttpConnection httpConnection, ByteBuffer[] rawData) {


     
         // state receiving header
        if (getState() == RECEIVING_HEADER) {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("[" + httpConnection.getId() + "] connection disconnected while receving header");
            }

            // already data recevied?
            if (!HttpUtils.isEmpty(rawData)) {
                try {
                    onDisconnectInHeader(httpConnection, rawData);
                } catch (IOException ioe) {
                    if (LOG.isLoggable(Level.FINE)) {
                        LOG.fine("[" + httpConnection.getId() + "] Error occured by calling on disconnect while receiving header " + ioe.toString());
                    }
                    IMessageHeaderHandler messageHeaderHandler = httpConnection.getMessageHeaderHandler();
                    if (messageHeaderHandler != null) {
                        messageHeaderHandler.onHeaderException(ioe, rawData);
                    }
                }

            // ... no
            } else {
                onDisconnectInHeaderNothingReceived(httpConnection, rawData);
            }

           
        // state receiving body  
        } else {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.fine("[" + httpConnection.getId() + "] connection disconnected while receving body");
            }
            AbstractNetworkBodyDataSource ds = getBodyDataSource();
            if (ds != null) {
                try {
                    ds.onDisconnect();
                } catch (IOException ioe) {
                    if (LOG.isLoggable(Level.FINE)) {
                        LOG.fine("[" + httpConnection.getId() + "] Error occured by calling on disconnect while receiving header  " + ioe.toString());
                    }
                    if (messageHandler != null) {
                        messageHandler.onBodyException(ioe, rawData);
                    }
                }
            }
        }
  }
 
 
    void onDisconnectInHeader(AbstractHttpConnection httpConnection, ByteBuffer[] rawData) throws IOException {
        ByteBuffer[] received = HttpUtils.copy(rawData);
        throw new ProtocolException("connection " + httpConnection.getId() + " has been disconnected while receiving header. Already received: " + DataConverter.toString(received, IHttpHeader.DEFAULT_ENCODING), null);
    }

   
    void onDisconnectInHeaderNothingReceived(AbstractHttpConnection httpConnection, ByteBuffer[] rawData) {
        ProtocolException pe = new ProtocolException("connection " + httpConnection.getId() + " has been disconnected while receiving header. non data recevied (closeReason=" + httpConnection.getCloseReason() + ")", null);
       
        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("[" + httpConnection.getId() + "] error occured " + pe.toString());
        }       
       
        IMessageHeaderHandler messageHeaderHandler = httpConnection.getMessageHeaderHandler();
        if (messageHeaderHandler != null) {
            messageHeaderHandler.onHeaderException(pe, rawData);
        }
    }
   
   
   
    /**
     * call back if a exception is occured
     *
     * @param  httpConnection   the underlying http conection
     * @param  ioe              the exception
     * @param  rawData          the unready networkdata
     */
    public final void onException(AbstractHttpConnection httpConnection, IOException ioe, ByteBuffer[] rawData) {
       
        switch (getState()) {
       
            case RECEIVING_HEADER:
                if (LOG.isLoggable(Level.FINE)) {
                    try {
                        LOG.info("error occured by receiving header. Reason: " + ioe.toString() + " received" + DataConverter.toString(HttpUtils.copy(rawData)));
                    } catch (UnsupportedEncodingException use) {
                        LOG.info("error occured by receiving header. Reason: " + ioe.toString());
                    }
                }
                break;
   
               
            default:
                if (dataSource != null) {
                    dataSource.onException(ioe, rawData);
                }
        }
    }
}

TOP

Related Classes of org.xlightweb.AbstractHttpProtocolHandler

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.