* @param done <code>true</code> if this is the last data to encode
*/
private void partialContentEncodeData(IOBuffer iobuffer, boolean done) {
try {
int len = iobuffer.availableBytes();
IOBuffer newIOBuffer = new IOBuffer();
while (len > 0) {
// If we're already past the last range, simply skip data.
if (rangeIndex == range.getNumRanges()) {
iobuffer.skipBytes(len);
rangeCurrentPos += len;
len = 0;
continue;
}
Range.Pair p = range.getRange(rangeIndex, rangeContentLength);
// If necessary, skip to the start of the current range.
int skip = p.getStart() - rangeCurrentPos;
if (skip > 0) {
int skipped = (int) iobuffer.skipBytes(skip);
rangeCurrentPos += skipped;
len -= skipped;
// If there is no data left, continue.
if (len == 0) {
continue;
}
}
// The byte range is inclusive, so we must transfer 1 + getEnd().
int transfer = Math.min((p.getEnd() - rangeCurrentPos + 1), len);
if (transfer < 0) {
throw new IllegalStateException();
}
if (transfer > 0) {
// If we're at the start of a multipart byterange, output boundary.
if (range.getNumRanges() > 1 && rangeCurrentPos == p.getStart()) {
// It's ok for additional CRLFs to preceed first boundary.
newIOBuffer.writeBytes("\r\n--".getBytes());
newIOBuffer.writeBytes(rangeBoundary.getBytes());
if (rangeContentType != null) {
newIOBuffer.writeBytes("\r\n".getBytes());
newIOBuffer.writeBytes("Content-Type: ".getBytes());
newIOBuffer.writeBytes(rangeContentType.getBytes());
}
newIOBuffer.writeBytes("\r\n".getBytes());
newIOBuffer.writeBytes("Content-Range: ".getBytes());
newIOBuffer.writeBytes(("bytes " + p.getStart() + "-" + p.getEnd()
+ "/" + rangeContentLength).getBytes());
newIOBuffer.writeBytes("\r\n\r\n".getBytes());
}
newIOBuffer.transfer(iobuffer, transfer);
rangeCurrentPos += transfer;
len -= transfer;
}
// Advance to the next range if we completed the current one.
if (rangeCurrentPos == (p.getEnd() + 1)) {
rangeIndex += 1;
}
}
if (done && !head_request) {
// Sanity checks
if (rangeIndex < range.getNumRanges()) {
Range.Pair p = range.getRange(rangeIndex, rangeContentLength);
if (p.getStart() != rangeContentLength) {
throw new IllegalStateException();
}
} else {
if (rangeIndex != range.getNumRanges()) {
throw new IllegalStateException();
}
}
// If we encoded as multipart/byteranges, output final boundary.
if (range.getNumRanges() > 1) {
newIOBuffer.writeBytes("\r\n--".getBytes());
newIOBuffer.writeBytes(rangeBoundary.getBytes());
newIOBuffer.writeBytes("--\r\n".getBytes());
}
}
// Prepend new iobuffer
if (iobuffer.availableBytes() != 0) {
throw new IllegalStateException();
}
if (newIOBuffer.isEmpty() == false) {
iobuffer.prepend(newIOBuffer);
}
} catch (IOException e) {
// should never reach this statement. IOException in IOBuffers only are
// thrown from handling consume callbacks. new_iobuf doesn't have a