/*
* JLibs: Common Utilities for Java
* Copyright (C) 2009 Santhosh Kumar T <santhosh.tekuri@gmail.com>
*
* 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.
*/
package jlibs.nio.http.msg.parser;
import jlibs.nio.http.msg.Message;
import jlibs.nio.http.msg.Method;
import jlibs.nio.http.msg.Request;
import jlibs.nio.http.msg.Status;
import java.nio.ByteBuffer;
import static jlibs.nio.http.util.USAscii.*;
/**
* @author Santhosh Kumar Tekuri
*/
public class RequestParser extends MessageParser{
private static final int BEGIN = 0;
private static final int METHOD = 1;
private static final int URI = 2;
private static final int VERSION = 3;
private static final int EOL = 4;
private static final int HEADERS = 5;
private final long maxURISize;
public RequestParser(long maxURISize){
this.maxURISize = maxURISize;
}
private int state = BEGIN;
@Override
public boolean parse(ByteBuffer buffer, boolean eof){
int bpos = buffer.position();
char ch;
while(buffer.hasRemaining()){
switch(state){
case METHOD:
while(true){
if(!buffer.hasRemaining())
return false;
ch = (char)buffer.get();
if(ch==SP){
if(builder.length()==0)
throw Status.BAD_REQUEST.with("Method Missing");
request.method = Method.valueOf(builder);
builder.setLength(0);
beforeURI = consumed+buffer.position()-bpos;
state = URI;
break;
}else{
if(!TOKEN[ch])
throw Status.BAD_REQUEST.with("Bad Method");
builder.append(ch);
}
}
break;
case BEGIN:
if(buffer.remaining()>3 && buffer.get(bpos)=='G' && buffer.get(bpos+1)=='E' && buffer.get(bpos+2)=='T' && buffer.get(bpos+3)==' '){
request.method = Method.GET;
buffer.position(buffer.position()+4);
beforeURI = consumed + buffer.position()-bpos;
state = URI;
}else{
state = METHOD;
break;
}
case URI:
while(true){
if(!buffer.hasRemaining())
return false;
ch = (char)buffer.get();
if(ch==SP){
if(builder.length()==0)
throw Status.BAD_REQUEST.with("Path Missing");
request.uri = builder.toString();
builder.setLength(0);
if(maxURISize>0){
long uriSize = (consumed+buffer.position()-bpos)-beforeURI-1;
if(uriSize>maxURISize)
throw Status.REQUEST_URI_TOO_LONG;
}
state = VERSION;
break;
}else
builder.append(ch);
}
case VERSION:
if(parseVersion(buffer)){
state = EOL;
if(!buffer.hasRemaining())
return false;
}else
return false;
case EOL:
ch = (char)buffer.get();
if(ch==CR){
if(buffer.hasRemaining())
ch = (char)buffer.get();
else{
buffer.position(buffer.position()-1);
return false;
}
}
if(ch!=LF)
throw Status.BAD_REQUEST.with("Bad Version");
state = HEADERS;
builder.setLength(0);
case HEADERS:
return super.parse(buffer, eof);
}
}
return false;
}
private long beforeURI;
private Request request;
public void reset(Message request){
super.reset(request);
this.request = (Request)request;
state = BEGIN;
}
}