package tkuri.jxy.server;
import tkuri.jxy.Const;
import tkuri.jxy.Util;
import tkuri.jxy.arch.ChannelReader;
import tkuri.jxy.arch.GeneralHeaderInfo;
import tkuri.jxy.arch.HeaderList;
import tkuri.jxy.arch.HeaderReader;
import tkuri.jxy.arch.MessageBodyHandler;
import tkuri.uty.Bs;
import tkuri.uty.Buf;
import tkuri.uty.IByteSequenceMatcher;
/**
* ClientRequest
*
* HTTPかHTTPSかを判定できる情報を持つ.
* メッセージボディについては管理しない.
*/
public class ClientRequest {
static final int STS_NONE = 0;
static final int STS_HEADER = 1;
private int state_ = STS_NONE;
private HeaderReader headerReader_;
public Bs method = Bs.BLANK;
public Bs host = Bs.BLANK;
public int port = 0;
public Bs path = Bs.BLANK;
public Bs version = Bs.BLANK;
public HeaderList headerList = new HeaderList();
public GeneralHeaderInfo headerInfo = null;
/**
* ctor
* @param aReader
*/
public ClientRequest(ChannelReader aReader) {
headerReader_ = new HeaderReader(aReader);
}
/**
*
* @return
*/
public int queryState() {
if (STS_HEADER <= state_) {
return state_;
}
if (! _parseRequestLine(this, headerReader_.queryFirstLine())) {
return state_;
}
for (Bs line: headerReader_) {
headerList.addLine(line);
}
boolean defConnClose = !Const.S_HTTP_VER11.equals(version);
headerInfo = new GeneralHeaderInfo(headerList, defConnClose);
headerInfo.hasMessageBody = Const.S_POST.equals(method)
|| Const.S_PUT.equals(method);
return state_;
}
private static boolean _parseRequestLine(ClientRequest aSelf, Bs aLine) {
if (aLine == null) {
return false;
}
Util.say("parsing: request line: ", aLine.trim());
final IByteSequenceMatcher IS_NOT_TABSP = IByteSequenceMatcher.IS_NOT_TABSP;
final IByteSequenceMatcher IS_TABSP = IByteSequenceMatcher.IS_TABSP;
int head = 0;
int len = aLine.match(head, IS_NOT_TABSP);
aSelf.method = aLine.sub(head, len);
head += len;
head += aLine.match(head, IS_TABSP);
len = aLine.match(head, IS_NOT_TABSP);
Bs path = aLine.sub(head, len);
head += len;
head += aLine.match(head, IS_TABSP);
aSelf.version = aLine.sub(head).trim();
// http://host:port/path
Bs host = Bs.BLANK;
int port = 0;
if (Const.S_CONNECT.equals(aSelf.method)) {
int colon = path.indexOf(':');
if (0 <= colon) {
host = path.slice(0, colon);
port = (int) path.sub(colon + 1).toLong();
} else {
host = path;
port = 443;
}
path = Bs.BLANK;
} else if (path.startsWith("http://")) {
path = path.sub(7);
int r = path.indexOf('/');
if (r >= 0) {
host = path.slice(0, r);
path = path.sub(r);
} else {
host = path;
path = Bs.valueOf("/");
}
int c = host.indexOf(':');
if (c < 0) {
port = 80;
} else {
port = (int) host.sub(c + 1).toLong();
host = host.slice(0, c);
}
} else {
host = Bs.valueOf("localhost");
port = 80;
}
aSelf.path = path;
aSelf.host = host;
aSelf.port = port;
return true;
}
@Override
public String toString() {
Buf buf = new Buf();
buf.appendAll("<<", host, ":" + port + ">> ", method, " ", path.sub(0, 32));
if (headerInfo != null && headerInfo.connectionClose) {
buf.appendAll(" (conn:close)");
}
return buf.toString();
}
}