package io.craft.atom.protocol.http.model;
import io.craft.atom.util.ByteArrayBuffer;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* Represents an http chunk entity.
* <br>
* Chunked entity format as follows:
* <pre>
* -----------------------------------------------------------------------------
* Chunked-Body = *chunk
* last-chunk
* trailer
* CRLF
* chunk = chunk-size [ chunk-extension ] CRLF
* chunk-data CRLF
* chunk-size = 1*HEX
* last-chunk = 1*("0") [ chunk-extension ] CRLF
* chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
* chunk-ext-name = token
* chunk-ext-val = token | quoted-string
* chunk-data = chunk-size(OCTET)
* trailer = *(entity-header CRLF)
* -----------------------------------------------------------------------------
*
* The chunked data example as follows:
* -----------------------------------------------------------------------------
* Transfer-Encoding: chunked CRLF
* 23;chunk_extension_name=chunk_extension_value CRLF
* This is the data in the first chunk CRLF
* 1A CRLF
* and this is the second one CRLF
* 0 CRLF
* -----------------------------------------------------------------------------
* </pre>
*
* @author mindwind
* @version 1.0, Feb 8, 2013
*/
@ToString(callSuper = true, of = { "chunks", "trailers" })
public class HttpChunkEntity extends HttpEntity {
private static final long serialVersionUID = -8469016024998851045L;
@Getter @Setter private List<HttpChunk> chunks = new ArrayList<HttpChunk>() ;
@Getter @Setter private Map<String, HttpHeader> trailers = new LinkedHashMap<String, HttpHeader>();
// ~ --------------------------------------------------------------------------------------------------------
public HttpChunkEntity() {
super();
}
public HttpChunkEntity(byte[] content) {
super(content);
}
public HttpChunkEntity(List<HttpChunk> chunks) {
this.chunks = chunks;
}
public HttpChunkEntity(List<HttpChunk> chunks, Map<String, HttpHeader> trailers) {
this(chunks);
this.trailers = trailers;
}
// ~ --------------------------------------------------------------------------------------------------------
/**
* Add a chunk
*
* @param chunk
*/
public void addChunk(HttpChunk chunk) {
chunks.add(chunk);
}
/**
* Add a new trailer header to chunk entity, if the exists replace it.
*
* @param trailer
*/
public void addTrailer(HttpHeader trailer) {
if (trailer == null || trailer.getName() == null) {
throw new IllegalArgumentException("trailer or trailer name is null!");
}
trailers.put(trailer.getName(), trailer);
}
public byte[] getContent() {
if (content == null) {
ByteArrayBuffer buf = new ByteArrayBuffer();
for (HttpChunk chunk : chunks) {
buf.append(chunk.getData());
}
this.content = buf.array();
}
return this.content;
}
public String toHttpString() {
StringBuilder sb = new StringBuilder();
for (HttpChunk chunk : getChunks()) {
sb.append(chunk.toHttpString(contentType.getCharset()));
}
for (HttpHeader trailer : trailers.values()) {
sb.append(trailer.toHttpString());
}
return sb.toString();
}
}