package org.simpleframework.http.validate;
import java.io.IOException;
import java.io.InputStream;
import org.simpleframework.common.buffer.Buffer;
class HeaderParser {
private Token name = new Token();
private Token value = new Token();
private byte[] buf;
private int count;
private int off;
private int len;
private boolean parsed = false;
public HeaderParser(Buffer buffer) throws IOException {
InputStream source = buffer.open();
this.buf = new byte[source.available()];
this.len = source.read(buf, 0, buf.length);
}
public Header next() {
if(hasMore()) {
parsed = false;
return new Entry(name, value, buf);
}
return null;
}
public boolean hasMore() {
if(parsed) return true;
if(count + 1 < len) { /* check for CRLF ending */
byte a = buf[off];
byte b = buf[off + 1];
if(a == 13 && b == 10) {
return false;
}
}
parse();
if(name.len > 0){
parsed = true;
return true;
}
return false;
}
private void description() {
while(count < len) {
if(buf[off] == 10){ /* cannot be folded see RFC 2616 pg35 */
count++; /* skip past LF */
off++;
break;
}
count++;
off++;
}
}
private void parse() {
name(); /* Some-Header: */
value(); /* some-value CRLF */
}
private void name() {
whitespace();
name.off = off;
name.len = 0;
while(count < len){
if(buf[off] == ':') {
off++; /* skip past the colon */
count++;
break;
}
name.len++;
count++;
off++;
}
}
private void value() {
whitespace();
value.off = off;
value.len = 0;
for(int mark= 0; count < len;){
if(terminal(buf[off])) { /* CR or LF */
for(int i = 0; count < len; i++){
if(buf[off] == 10) {
count++; /* skip the LF */
off++;
if(space(buf[off])) {
value.len += i; /* acount for bytes examined */
break; /* folding line */
}
return; /* not a folding line */
}
count++;
off++;
}
} else {
if(!space(buf[off])){
value.len= ++mark;
} else {
mark++;
}
count++;
off++;
}
}
}
private void whitespace() {
while(count < len) {
if(!space(buf[off])){
break;
}
count++;
off++;
}
}
private boolean space(byte b) {
return b == ' ' || b == '\t';
}
private boolean terminal(byte b){
return b == 13 || b == 10;
}
private class Entry implements Header{
private Token name = new Token();
private Token value = new Token();
private Cache cache = new Cache();
private String str;
private byte[] buf;
public Entry(Token name, Token value, byte[] buf) {
this.name.off = name.off;
this.name.len = name.len;
this.value.off = value.off;
this.value.len = value.len;
this.buf = buf;
}
public String getName(){
if(cache.name == null){
cache.name = name.toString();
}
return cache.name;
}
public String getValue(){
if(cache.val == null){
cache.val = value.toString();
}
return cache.val;
}
public String toString(){
if(str == null){
str = getName()+ ": "+getValue();
}
return str;
}
public boolean nameMatches(String name) {
if(name == null) return false;
if(this.name.len != name.length()) {
return false;
}
if(cache.name != null){
return cache.name.equalsIgnoreCase(name);
}
for(int i = 0; i < this.name.len; i++) {
byte a = toLower(buf[this.name.off + i]);
byte b = toLower(name.charAt(i));
if(a != b) {
return false;
}
}
return true;
}
private byte toLower(char c) {
return toLower((byte)c);
}
private byte toLower(byte b) {
if(b >= 'A' && b <= 'Z') {
return (byte)((b - 'A') + 'a');
}
return b;
}
private class Cache{
public String name;
public String val;
}
}
private class Token {
public String text;
public int off;
public int len;
public String toString() {
try {
if(text == null) {
text = new String(buf, off, len, "ISO-8859-1");
}
} catch(IOException e) {
return null;
}
return text;
}
}
}