/* * 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.Version; import java.nio.ByteBuffer; import static jlibs.nio.http.util.USAscii.DIGIT; /** * @author Santhosh Kumar Tekuri */ public abstract class MessageParser extends HeadersParser{ private static final byte VERSION_PREFIX[] = { 'H', 'T', 'T', 'P', '/' }; private static final int STATE_PREFIX = 0; private static final int STATE_MAJOR_BEGIN = 1; private static final int STATE_MAJOR = 2; private static final int STATE_MINOR_BEGIN = 3; private static final int STATE_MINOR = 4; private int vstate = STATE_PREFIX; private int vi; private int major, minor; protected final boolean parseVersion(ByteBuffer buffer){ char ch; switch(vstate){ case STATE_PREFIX: while(buffer.hasRemaining()){ if(buffer.get()!=VERSION_PREFIX[vi]) throw message.badMessage("Bad Version"); if(++vi==5){ if(buffer.remaining()>3){ int bpos = buffer.position(); if(!DIGIT[buffer.get(bpos+3)]){ if(buffer.get(bpos)=='1' && buffer.get(bpos+1)=='.'){ char t = (char)buffer.get(bpos+2); if(t=='0'){ message.version = Version.HTTP_1_0; buffer.position(bpos+3); return true; }else if(t=='1'){ message.version = Version.HTTP_1_1; buffer.position(bpos+3); return true; } } } } vstate = STATE_MAJOR_BEGIN; break; } } if(!buffer.hasRemaining()) return false; case STATE_MAJOR_BEGIN: ch = (char)buffer.get(); if(!DIGIT[ch]) throw message.badMessage("Bad Major Version"); major = ch-'0'; vstate = STATE_MAJOR; if(!buffer.hasRemaining()) return false; case STATE_MAJOR: while(buffer.hasRemaining()){ ch = (char)buffer.get(); if(ch=='.'){ vstate = STATE_MINOR_BEGIN; break; } if(!DIGIT[ch]) throw message.badMessage("Bad Major Version"); major = major*10+(ch-'0'); } if(!buffer.hasRemaining()) return false; case STATE_MINOR_BEGIN: ch = (char)buffer.get(); if(!DIGIT[ch]) throw message.badMessage("Bad Minor Version"); minor = ch-'0'; vstate = STATE_MINOR; case STATE_MINOR: while(buffer.hasRemaining()){ ch = (char)buffer.get(); if(DIGIT[ch]) minor = minor*10+(ch-'0'); else{ buffer.position(buffer.position()-1); message.version = Version.valueOf(major, minor); return true; } } return false; } return false; } protected Message message; public long consumed; public <T extends Message> void reset(T message){ reset(message.headers, message.badMessageStatus()); this.message = message; vstate = STATE_PREFIX; vi = 0; major = 0; minor = 0; consumed = 0; } }