/* * 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.Headers; import jlibs.nio.http.msg.Message; import jlibs.nio.http.msg.Status; import jlibs.nio.http.msg.AsciiString; import jlibs.nio.util.Parser; import java.nio.ByteBuffer; import static jlibs.nio.http.util.USAscii.*; /** * @author Santhosh Kumar Tekuri */ public class HeadersParser implements Parser{ protected final StringBuilder builder = new StringBuilder(); private static final int LINE_BEGIN = 0; private static final int NAME = 1; private static final int VALUE_BEGIN = 2; private static final int VALUE = 3; private int state = LINE_BEGIN; private AsciiString name; @Override public boolean parse(ByteBuffer buffer, boolean eof){ char ch; while(buffer.hasRemaining()){ switch(state){ case LINE_BEGIN: ch = (char)buffer.get(); if(ch==COLON) throw errorStatus.with("Empty Header Name"); if(ch==CR){ if(buffer.hasRemaining()){ if(buffer.get()!=LF) throw errorStatus.with("Bad EOL"); if(name!=null) addHeader(); return true; }else{ buffer.position(buffer.position()-1); return false; } }else if(ch==LF){ if(name!=null) addHeader(); return true; } if(name!=null){ if(WS[ch]){ builder.append(SP); state = VALUE; if(buffer.hasRemaining()) break; else return false; }else addHeader(); } builder.append(ch); state = NAME; if(!buffer.hasRemaining()) return false; case NAME: while(buffer.hasRemaining()){ ch = (char)buffer.get(); if(ch==COLON){ name = AsciiString.valueOf(builder); builder.setLength(0); state = VALUE_BEGIN; break; }else{ if(!TOKEN[ch]) throw errorStatus.with("Bad Header Name"); builder.append(ch); } } if(!buffer.hasRemaining()) return false; case VALUE_BEGIN: while(buffer.hasRemaining()){ if(!WS[buffer.get()]){ buffer.position(buffer.position()-1); state = VALUE; break; } } if(!buffer.hasRemaining()) return false; case VALUE: while(buffer.hasRemaining()){ ch = (char)buffer.get(); if(ch==CR){ if(buffer.hasRemaining()){ if(buffer.get()!=LF) throw errorStatus.with("Bad EOL"); state = LINE_BEGIN; break; }else{ buffer.position(buffer.position()-1); return false; } }else if(ch==LF){ state = LINE_BEGIN; break; }else builder.append(ch); } if(!buffer.hasRemaining()) return false; } } return false; } private void addHeader(){ int end = builder.length(); while(end>0 && WS[builder.charAt(end-1)]) --end; if(headers==null) headers = message.trailers = new Headers(); headers.add(name, builder.substring(0, end)); name = null; builder.setLength(0); } private Status errorStatus; private Headers headers; private Message message; public void reset(Headers headers, Status errorStatus){ this.headers = headers; this.errorStatus = errorStatus; builder.setLength(0); name = null; state = LINE_BEGIN; } public void resetForTrailers(Message message){ reset(message.trailers, message.badMessageStatus()); this.message = message; } public Headers getHeaders(){ return headers; } }