/*
* 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 java.io.IOException;
import java.nio.BufferUnderflowException;
import org.xlightweb.AbstractHttpConnection.IMessageHandler;
import org.xsocket.connection.INonBlockingConnection;
/**
* server side http protocol handler
*
* @author grro@xlightweb.org
*/
final class HttpProtocolHandlerServerSide extends AbstractHttpProtocolHandler {
/**
* {@inheritDoc}
*/
public void onData(AbstractHttpConnection httpConnection, INonBlockingConnection underlyingConnection, ComposedByteBuffer rawData) throws BadMessageException, IOException {
try {
switch (getState()) {
case INIT:
setHeaderParser(HttpRequestHeaderParser.newInstance());
setState(RECEIVING_HEADER);
onData(httpConnection, underlyingConnection, rawData);
return;
case RECEIVING_HEADER:
HttpRequestHeader requestHeader = (HttpRequestHeader) getHeaderParser().parse(underlyingConnection, rawData);
if (requestHeader != null) {
httpConnection.setLastTimeHeaderReceivedMillis(System.currentTimeMillis());
httpConnection.incCountMessageReceived();
IMessageHandler messageHandler = httpConnection.getMessageHandler();
if (messageHandler == null) {
throw new IOException("no message handler set");
}
HttpRequest request = null;
switch (getBodyType(requestHeader, messageHandler.isBodylessMessageExpected())) {
case BODY_TYPE_EMTPY:
request = new HttpRequest(requestHeader);
reset();
break;
case BODY_TYPE_BOUND:
setBodyParser(new FullMessageBodyParser(httpConnection, requestHeader));
request = new HttpRequest(requestHeader, getBodyParser().getDataSource());
setState(RECEIVING_BODY);
request.getNonBlockingBody().setBodyDataReceiveTimeoutMillis(httpConnection.getBodyDataReceiveTimeoutMillis());
parserBody(rawData);
break;
default: // BODY_TYPE_CHUNKED
setBodyParser(new FullMessageChunkedBodyParser(httpConnection, requestHeader));
request = new HttpRequest(requestHeader, getBodyParser().getDataSource());
setState(RECEIVING_BODY);
request.getNonBlockingBody().setBodyDataReceiveTimeoutMillis(httpConnection.getBodyDataReceiveTimeoutMillis());
parserBody(rawData);
break;
}
messageHandler.onMessage(request);
return;
}
break;
default: // RECEIVING_BODY
parserBody(rawData);
}
} catch (BufferUnderflowException ignore) {
} catch (SimpleResponseMessageException ignore) {
}
}
private static int getBodyType(HttpRequestHeader requestHeader, boolean isBodylessMessageExcpected) throws BadMessageException {
if (isBodylessMessageExcpected) {
return BODY_TYPE_EMTPY;
}
String method = requestHeader.getMethod();
// GET request?
if (method.equals(IHttpMessage.GET_METHOD)) {
return BODY_TYPE_EMTPY;
}
// POST request?
if (method.equals(IHttpMessage.POST_METHOD)) {
return getBodyTypeByHeader(requestHeader);
}
// other bodyless request?
if (method.equals(IHttpMessage.CONNECT_METHOD) ||
method.equals(IHttpMessage.HEAD_METHOD) ||
method.equals(IHttpMessage.TRACE_METHOD)||
method.equals(IHttpMessage.DELETE_METHOD)||
method.equals(IHttpMessage.OPTIONS_METHOD)) {
return BODY_TYPE_EMTPY;
}
// ... no, determine if body by header
return getBodyTypeByHeader(requestHeader);
}
private static int getBodyTypeByHeader(HttpRequestHeader requestHeader) throws BadMessageException {
// contains a non-zero Content-Length header -> bound body
if ((requestHeader.getContentLength() != -1)) {
if (requestHeader.getContentLength() > 0) {
return BODY_TYPE_BOUND;
}
return BODY_TYPE_EMTPY;
}
// transfer encoding header is set with chunked -> chunked body
String transferEncoding = requestHeader.getTransferEncoding();
if ((transferEncoding != null) && (transferEncoding.equalsIgnoreCase("chunked"))) {
return BODY_TYPE_CHUNKED;
}
throw new BadMessageException(requestHeader.toString());
}
}