package com.fineqt.fpb.protocol;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
import com.fineqt.fpb.lib.api.IBooleanValue;
import com.fineqt.fpb.lib.api.ICharstringValue;
import com.fineqt.fpb.lib.api.IContainerValue;
import com.fineqt.fpb.lib.api.IFactory;
import com.fineqt.fpb.lib.api.IIntegerValue;
import com.fineqt.fpb.lib.api.IListValue;
import com.fineqt.fpb.lib.api.IOctetstringValue;
import com.fineqt.fpb.lib.api.IRecordSetValue;
import com.fineqt.fpb.lib.api.IValue;
import com.fineqt.fpb.lib.api.util.DecodeException;
import com.fineqt.fpb.lib.api.util.buffer.IBitBuffer;
import com.fineqt.fpb.lib.api.util.buffer.IReadableBitBuffer;
import com.fineqt.fpb.lib.codec.DecodeParameters;
import com.fineqt.fpb.lib.codec.DecodeResult;
import com.fineqt.fpb.lib.constraint.PTypeConstraintStorage;
import com.fineqt.fpb.lib.meta.PModuleExt;
import com.fineqt.fpb.lib.meta.context.CommonContext;
import com.fineqt.fpb.lib.meta.context.DecodeContext;
import com.fineqt.fpb.lib.meta.context.EncodeContext;
import com.fineqt.fpb.lib.meta.exception.InitMetaException;
import com.fineqt.fpb.lib.meta.user.PUserTypeEVExtFactoryBase;
import com.fineqt.fpb.lib.model.fpbmodule.ByteOrder;
import com.fineqt.fpb.lib.model.fpbmodule.PFpbTypeEV;
import com.fineqt.fpb.lib.type.PContainerTypeExt;
import com.fineqt.fpb.lib.type.PFieldExt;
import com.fineqt.fpb.lib.type.PFpbTypeEVAttrs;
import com.fineqt.fpb.lib.type.PFpbTypeEVExt;
import com.fineqt.fpb.lib.type.PListItemExt;
import com.fineqt.fpb.lib.type.PTypeExt;
import com.fineqt.fpb.lib.type.impl.PRecordOfTypeExtBase.PFpbRecordOfEVExt;
import com.fineqt.fpb.lib.type.impl.PRecordTypeExtBase.PFpbRecordEVExt;
import com.fineqt.fpb.lib.util.FpbConstants;
import com.fineqt.fpb.lib.value.PValue;
public class HttpTypeEVExtFactory extends PUserTypeEVExtFactoryBase {
public static int HTTP_MESSAGE;
public static int HTTP_MESSAGE__HEADERS;
public static int HTTP_MESSAGE__HTTP_BODY;
public static int HTTP_MESSAGE__TRAILERS;
public static int HTTP_HEADER;
public static int HTTP_HEADER__NAME;
public static int HTTP_HEADER__VALUE;
public static int HTTP_CHUNK;
public static int HTTP_CHUNK__LENGTH_LINE;
public static int HTTP_CHUNK__CHUNK_DATA;
public static int HTTP_CHUNK_LENGTH_LINE;
public static int HTTP_CHUNK_LENGTH_LINE__CHUNK_LENGTH;
public static int HTTP_CHUNK_DATA;
public static int HTTP_CHUNK_DATA__DATA;
public static int HTTP_BODY;
public static int HTTP_BODY__DATA;
public static int HTTP_BODY__CHUNKS;
public static int HTTP_HEADER_LIST;
public static int HTTP_CHUNK_LIST;
@Override
public void postInitModule(PModuleExt module) throws InitMetaException {
PContainerTypeExt containerType;
//取得类型和字段的ID
containerType = (PContainerTypeExt)module.pPType(Names.HTTP_MESSAGE);
HTTP_MESSAGE = containerType.getID();
HTTP_MESSAGE__HEADERS = containerType.getFieldID(Names.HTTP_MESSAGE__HEADERS);
HTTP_MESSAGE__HTTP_BODY = containerType.getFieldID(Names.HTTP_MESSAGE__HTTP_BODY);
HTTP_MESSAGE__TRAILERS = containerType.getFieldID(Names.HTTP_MESSAGE__TRAILERS);
containerType = (PContainerTypeExt)module.pPType(Names.HTTP_HEADER);
HTTP_HEADER = containerType.getID();
HTTP_HEADER__NAME = containerType.getFieldID(Names.HTTP_HEADER__NAME);
HTTP_HEADER__VALUE = containerType.getFieldID(Names.HTTP_HEADER__VALUE);
containerType = (PContainerTypeExt)module.pPType(Names.HTTP_CHUNK);
HTTP_CHUNK = containerType.getID();
HTTP_CHUNK__LENGTH_LINE = containerType.getFieldID(Names.HTTP_CHUNK__LENGTH_LINE);
HTTP_CHUNK__CHUNK_DATA = containerType.getFieldID(Names.HTTP_CHUNK__CHUNK_DATA);
containerType = (PContainerTypeExt)module.pPType(Names.HTTP_CHUNK_LENGTH_LINE);
HTTP_CHUNK_LENGTH_LINE = containerType.getID();
HTTP_CHUNK_LENGTH_LINE__CHUNK_LENGTH = containerType.getFieldID(
Names.HTTP_CHUNK_LENGTH_LINE__CHUNK_LENGTH);
containerType = (PContainerTypeExt)module.pPType(Names.HTTP_CHUNK_DATA);
HTTP_CHUNK_DATA__DATA = containerType.getFieldID(Names.HTTP_CHUNK_DATA__DATA);
containerType = (PContainerTypeExt)module.pPType(Names.HTTP_BODY);
HTTP_BODY__DATA = containerType.getFieldID(Names.HTTP_BODY__DATA);
HTTP_BODY__CHUNKS = containerType.getFieldID(Names.HTTP_BODY__CHUNKS);
HTTP_HEADER_LIST = module.pPType(Names.HTTP_HEADER_LIST).getID();
HTTP_CHUNK_LIST = module.pPType(Names.HTTP_CHUNK_LIST).getID();
}
@Override
protected PFpbTypeEVExt createTypeEVExt4FPB(PTypeExt typeMeta,
PFpbTypeEV evModel) {
String typeName = typeMeta.getName();
if (typeName.equals(Names.HTTP_MESSAGE)) {
return new HttpMessageTypeEVExt(evModel);
} else if (typeName.equals(Names.HTTP_CHUNK)) {
return new HttpChunkTypeEVExt(evModel);
} else if (typeName.equals(Names.HTTP_HEADER)) {
return new HttpHeaderTypeEVExt(evModel);
} else if (typeName.equals(Names.HTTP_HEADER_LIST)) {
return new HttpHeaderListTypeEVExt(evModel);
} else if (typeName.equals(Names.HTTP_CHUNK_LIST)) {
return new HttpChunkListTypeEVExt(evModel);
} else if (typeName.equals(Names.HTTP_CHUNK_LENGTH_LINE)) {
return new HttpChunkLengthLineTypeEVExt(evModel);
}
return super.createTypeEVExt4FPB(typeMeta, evModel);
}
private static class HttpMessageTypeEVExt extends PFpbRecordEVExt {
public HttpMessageTypeEVExt(PFpbTypeEV model) {
super(model);
}
@Override
protected void preEncode(EncodeContext cxt, PValue value, int parentLength,
PTypeConstraintStorage constraint, ByteOrder byteOrder,
PFpbTypeEVAttrs priorityAttrs) {
//父亲方法
super.preEncode(cxt, value, parentLength, constraint, byteOrder, priorityAttrs);
if (cxt.withCalculateAction()) {
//更新Content-Length首部字段
updateContentLength(value);
}
}
private void updateContentLength(PValue value) {
IContainerValue msgValue = (IContainerValue)value;
//取得Content-Length首部字段
@SuppressWarnings("unchecked")
IListValue<IRecordSetValue> headers = (IListValue<IRecordSetValue>)
msgValue.getField(HTTP_MESSAGE__HEADERS);
IValue contentLengthValue = null;
if (headers != null) {
for (int i = 0; i < headers.getLength(); i++) {
IRecordSetValue header = headers.getItem(i);
if (header == null) {
continue;
}
IValue name = header.getField(HTTP_HEADER__NAME);
if (name == null) {
continue;
}
if (HeaderNames.CONTENT_LENGTH.equals(name.getText())) {
contentLengthValue = header.getField(HTTP_HEADER__VALUE);
}
}
}
//根据httpBody/data来更新
if (contentLengthValue != null) {
IContainerValue httpBody = (IContainerValue)msgValue.getField(
HTTP_MESSAGE__HTTP_BODY);
if (httpBody != null && !httpBody.notPresent()) {
IOctetstringValue data = (IOctetstringValue)httpBody.getField(
HTTP_BODY__DATA);
if (data != null) {
String text = Integer.toString(data.getLength());
contentLengthValue.setText(text);
}
}
}
}
}
private static class HttpChunkTypeEVExt extends PFpbRecordEVExt {
public HttpChunkTypeEVExt(PFpbTypeEV model) {
super(model);
}
@Override
protected void preEncode(EncodeContext cxt, PValue value, int parentLength,
PTypeConstraintStorage constraint, ByteOrder byteOrder,
PFpbTypeEVAttrs priorityAttrs) {
//父亲方法
super.preEncode(cxt, value, parentLength, constraint, byteOrder, priorityAttrs);
if (cxt.withCalculateAction()) {
//更新chunkLength字段
updateChunkLength(value);
}
}
private void updateChunkLength(PValue value) {
IContainerValue chunkValue = (IContainerValue)value;
//取得chunkLength字段
IValue chunkLength = null;
IContainerValue lengthLine = (IContainerValue)chunkValue.getField(
HTTP_CHUNK__LENGTH_LINE);
if (lengthLine != null) {
chunkLength = lengthLine.getField(HTTP_CHUNK_LENGTH_LINE__CHUNK_LENGTH);
}
//根据chunkData/data来更新
if (chunkLength != null) {
IContainerValue chunkData = (IContainerValue)chunkValue.getField(
HTTP_CHUNK__CHUNK_DATA);
//默认为0
String text = "0";
if (chunkData != null && !chunkData.notPresent()) {
IOctetstringValue data = (IOctetstringValue)chunkData.getField(
HTTP_CHUNK_DATA__DATA);
if (data != null) {
text = Integer.toString(data.getLength());
}
}
chunkLength.setText(text);
}
}
@Override
protected boolean postDecodeField(DecodeContext cxt, IReadableBitBuffer input,
DecodeParameters paras, DecodeResult parentResult,
DecodeResult fieldResult, PFieldExt fieldMeta) throws DecodeException {
boolean ret = super.postDecodeField(cxt, input, paras, parentResult,
fieldResult, fieldMeta);
if (fieldMeta.getFieldID() == HTTP_CHUNK__LENGTH_LINE) {
IFactory factory = getPModule().getFactory();
IContainerValue lengthLine = (IContainerValue)fieldResult.getValue();
if (lengthLine != null) {
ICharstringValue lenValue = (ICharstringValue)lengthLine.getField(
HTTP_CHUNK_LENGTH_LINE__CHUNK_LENGTH);
IBooleanValue chunked = factory.createBoolean();
if (lenValue != null && !lenValue.getText().equals("0")){
//hasChunkData
chunked.setBoolean(true);
} else {
//hasChunkData
chunked.setBoolean(false);
}
cxt.getFieldStackMap().setTopField(StackFields.HAS_CHUNK_DATA,
chunked);
}
}
return ret;
}
}
private static class HttpHeaderTypeEVExt extends PFpbRecordEVExt {
public HttpHeaderTypeEVExt(PFpbTypeEV model) {
super(model);
}
@Override
protected boolean preDecode(DecodeContext cxt, IReadableBitBuffer input,
DecodeParameters paras, DecodeResult result) throws DecodeException {
boolean ret = super.preDecode(cxt, input, paras, result);
if (!ret) {
return ret;
}
//排除空行的情况
// System.out.println("HypFixedLength:"+paras.getHypFixedLength()/8+" input:"+input.limit()/8);
return paras.getHypFixedLength() > CRLF_BITS;
}
}
private static class HttpHeaderListTypeEVExt extends PFpbRecordOfEVExt {
public HttpHeaderListTypeEVExt(PFpbTypeEV model) {
super(model);
}
@Override
protected DecodeResult postDecode(DecodeContext cxt, IReadableBitBuffer input,
DecodeParameters paras, DecodeResult result) throws DecodeException {
DecodeResult ret = super.postDecode(cxt, input, paras, result);
PFieldExt fieldMeta = (PFieldExt)paras.getItemFieldMeta();
//已解码Header的处理
if (fieldMeta != null && fieldMeta.getFieldID() == HTTP_MESSAGE__HEADERS) {
IFactory factory = getPModule().getFactory();
CommonContext.FieldStackMap fieldStack = cxt.getFieldStackMap();
@SuppressWarnings("unchecked")
IListValue<IRecordSetValue> headers =
(IListValue<IRecordSetValue>)result.getValue();
if (headers != null) {
for (int i = 0; i < headers.getLength(); i++) {
IRecordSetValue header = headers.getItem(i);
assert header != null;
processHeadersItem(factory, fieldStack, header);
}
}
}
return ret;
}
@Override
protected boolean postDecodeItem(DecodeContext cxt, IBitBuffer input,
DecodeParameters paras, DecodeResult parentResult,
DecodeResult itemResult, PListItemExt itemMeta) {
boolean ret = super.postDecodeItem(cxt, input, paras, parentResult,
itemResult, itemMeta);
if (!ret) {
return ret;
}
PFieldExt fieldMeta = (PFieldExt)paras.getItemFieldMeta();
CommonContext.FieldStackMap fieldStack = cxt.getFieldStackMap();
if (fieldMeta != null && fieldMeta.getFieldID() == HTTP_MESSAGE__TRAILERS) {
@SuppressWarnings("unchecked")
Set<String> nameSet = (Set<String>)fieldStack.peekField(
StackFields.TRAILER_NAMES);
assert nameSet != null;
IRecordSetValue trailer = (IRecordSetValue)itemResult.getValue();
if (trailer == null) {
return ret;
}
ICharstringValue name = (ICharstringValue)trailer.getField(HTTP_HEADER__NAME);
ICharstringValue value = (ICharstringValue)trailer.getField(HTTP_HEADER__VALUE);
if (name == null || value == null) {
return false;
}
nameSet.remove(name.getText());
//仍然有未处理的Trailer才继续List的循环
return nameSet.size() > 0;
}
return ret;
}
private void processHeadersItem(IFactory factory,
CommonContext.FieldStackMap fieldStack, IRecordSetValue header) {
ICharstringValue name = (ICharstringValue)header.getField(HTTP_HEADER__NAME);
ICharstringValue value = (ICharstringValue)header.getField(HTTP_HEADER__VALUE);
if (name != null && value != null) {
String nameText = name.getText();
//Transfer-Encoding
if (HeaderNames.TRANSFER_ENCODING.equals(nameText)) {
if (HeaderValues.CHUNKED.equals(value.getText())) {
//chunked
IBooleanValue chunked = factory.createBoolean();
chunked.setBoolean(true);
fieldStack.setTopField(StackFields.CHUNCKED, chunked);
//hasBody
IBooleanValue hasBody = factory.createBoolean();
hasBody.setBoolean(true);
fieldStack.setTopField(StackFields.HAS_BODY, hasBody);
}
//Content-Length
} else if (HeaderNames.CONTENT_LENGTH.equals(nameText)) {
try {
int contentLength = Integer.parseInt(value.getText());
if (contentLength > 0) {
//hasBody
IBooleanValue hasBody = factory.createBoolean();
hasBody.setBoolean(true);
fieldStack.setTopField(StackFields.HAS_BODY, hasBody);
//contentLength
IIntegerValue lenValue = factory.createInteger();
lenValue.setInteger(contentLength);
fieldStack.setTopField(StackFields.CONTENT_LENGTH, lenValue);
}
} catch (NumberFormatException e) {
//忽略错误长度
}
//Trailer
} else if (HeaderNames.TRAILER.equals(nameText)) {
String[] names = SPACE_DELIMITER.split(value.getText());
Set<String> nameSet = new TreeSet<String>();
for (int i = 0; i < names.length; i++) {
String trailerName = names[i].trim();
if (trailerName.length() > 0) {
nameSet.add(trailerName);
}
}
if (nameSet.size() > 0) {
//hasTrailers
IBooleanValue hasTrailers = factory.createBoolean();
hasTrailers.setBoolean(true);
fieldStack.setTopField(StackFields.HAS_TRAILERS, hasTrailers);
//trailerNames
fieldStack.setTopField(StackFields.TRAILER_NAMES, nameSet);
}
}
}
}
}
private static class HttpChunkListTypeEVExt extends PFpbRecordOfEVExt {
public HttpChunkListTypeEVExt(PFpbTypeEV model) {
super(model);
}
@Override
protected boolean postDecodeItem(DecodeContext cxt, IBitBuffer input,
DecodeParameters paras, DecodeResult parentResult,
DecodeResult itemResult, PListItemExt itemMeta) {
boolean ret = super.postDecodeItem(cxt, input, paras, parentResult,
itemResult, itemMeta);
if (!ret) {
return ret;
}
IBooleanValue hasValue = (IBooleanValue)cxt.getFieldStackMap().peekField(
StackFields.HAS_CHUNK_DATA);
if (hasValue == null || !hasValue.getBoolean()) {
return false;
}
return true;
}
}
private static class HttpChunkLengthLineTypeEVExt extends PFpbRecordEVExt {
public HttpChunkLengthLineTypeEVExt(PFpbTypeEV model) {
super(model);
}
@Override
protected DecodeResult postDecode(DecodeContext cxt, IReadableBitBuffer input,
DecodeParameters paras, DecodeResult result) throws DecodeException {
DecodeResult ret = super.postDecode(cxt, input, paras, result);
if (ret.getValue() != null) {
//设置chunkLength
IContainerValue value = (IContainerValue)ret.getValue();
IValue lenValue = value.getField(HTTP_CHUNK_LENGTH_LINE__CHUNK_LENGTH);
IIntegerValue intValue = (IIntegerValue)cxt.getFieldStackMap().peekField(
StackFields.CHUNK_LENGTH);
if (intValue == null) {
intValue = getPModule().getFactory().createInteger();
cxt.getFieldStackMap().setTopField(StackFields.CHUNK_LENGTH, intValue);
}
try {
intValue.setInteger(Integer.parseInt(lenValue.getText(), 16));
} catch (NumberFormatException e) {
//有错误时认为是0
intValue.setInteger(0);
}
}
return ret;
}
}
interface Names {
String HTTP_MESSAGE = "HttpMessage";
String HTTP_MESSAGE__HEADERS = "headers";
String HTTP_MESSAGE__HTTP_BODY = "httpBody";
String HTTP_MESSAGE__TRAILERS = "trailers";
String HTTP_HEADER = "HttpHeader";
String HTTP_HEADER__NAME = "name";
String HTTP_HEADER__VALUE = "value";
String HTTP_CHUNK = "HttpChunk";
String HTTP_CHUNK__LENGTH_LINE = "lengthLine";
String HTTP_CHUNK__CHUNK_DATA = "chunkData";
String HTTP_CHUNK_LENGTH_LINE = "HttpChunkLengthLine";
String HTTP_CHUNK_LENGTH_LINE__CHUNK_LENGTH = "chunkLength";
String HTTP_CHUNK_DATA = "HttpChunkData";
String HTTP_CHUNK_DATA__DATA = "data";
String HTTP_BODY = "HttpBody";
String HTTP_BODY__DATA = "data";
String HTTP_BODY__CHUNKS = "chunks";
String HTTP_HEADER_LIST = "HttpHeaderList";
String HTTP_CHUNK_LIST = "HttpChunkList";
}
interface HeaderNames {
String CONTENT_LENGTH = "Content-Length";
String TRANSFER_ENCODING = "Transfer-Encoding";
String TRAILER = "Trailer";
}
interface StackFields {
String CHUNCKED = "chunked";
String CONTENT_LENGTH = "contentLength";
String HAS_BODY = "hasBody";
String HAS_TRAILERS = "hasTrailers";
String TRAILER_NAMES = "trailerNames";
String HAS_CHUNK_DATA = "hasChunkData";
String CHUNK_LENGTH = "chunkLength";
}
interface HeaderValues {
String CHUNKED = "chunked";
}
final private static int CRLF_BITS = 4 * FpbConstants.OCTET_BITS;
final private static Pattern SPACE_DELIMITER = Pattern.compile(",");
}