for(int i = 0; i < reducedRanges.length; i++) { long[] range = reducedRanges[i]; byteRanges[i] = new ByteRange(range[0], range[1], fileLength, contentType, reducedRanges.length > 1);
public int fill(byte[] into, int offset) throws IOException { if(Logger.isTraceEnabled()) Logger.trace("FileService fill at " + offset); int count = 0; for(; offset < into.length && servedHeader < header.length; offset++, servedHeader++, count++) { into[offset] = header[servedHeader]; } if(offset < into.length) { try { raf.seek(start + servedRange); long maxToRead = remaining() > (into.length - offset) ? (into.length - offset) : remaining(); if(maxToRead > Integer.MAX_VALUE) { if(Logger.isDebugEnabled()) Logger.debug("FileService: maxToRead >= 2^32 !"); maxToRead = Integer.MAX_VALUE; } int read = raf.read(into, offset, (int) maxToRead); if(read < 0) { throw new UnexpectedException("error while reading file : no more to read ! length=" + raf.length() + ", seek=" + (start + servedRange)); } count += read; servedRange += read; } catch(IOException e) { throw new UnexpectedException(e); } } return count; }
public void prepareNettyResponse(HttpResponse nettyResponse) { nettyResponse.headers().add("Accept-Ranges", "bytes"); if(unsatisfiable) { nettyResponse.setStatus(HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE); nettyResponse.headers().set("Content-Range", "bytes " + 0 + "-" + (fileLength-1) + "/" + fileLength); nettyResponse.headers().set("Content-length", 0); } else { nettyResponse.setStatus(HttpResponseStatus.PARTIAL_CONTENT); if(byteRanges.length == 1) { ByteRange range = byteRanges[0]; nettyResponse.headers().set("Content-Range", "bytes " + range.start + "-" + range.end + "/" + fileLength); } else { nettyResponse.headers().set("Content-type", "multipart/byteranges; boundary="+DEFAULT_SEPARATOR); } long length = 0; for(ByteRange range: byteRanges) { length += range.computeTotalLength(); } nettyResponse.headers().set("Content-length", length); } }
@Override public Object nextChunk() throws Exception { if(Logger.isTraceEnabled()) Logger.trace("FileService nextChunk"); try { int count = 0; byte[] buffer = new byte[chunkSize]; while(count < chunkSize && currentByteRange < byteRanges.length && byteRanges[currentByteRange] != null) { if(byteRanges[currentByteRange].remaining() > 0) { count += byteRanges[currentByteRange].fill(buffer, count); } else { currentByteRange++; } } if(count == 0){ return null; } return wrappedBuffer(buffer); } catch (Exception e) { Logger.error(e, "error sending file"); throw e; } }
public long computeTotalLength() { return length() + header.length; }
@Override public boolean hasNextChunk() throws Exception { if(Logger.isTraceEnabled()) Logger.trace("FileService hasNextChunk() : " + (currentByteRange < byteRanges.length && byteRanges[currentByteRange].remaining() > 0)); return currentByteRange < byteRanges.length && byteRanges[currentByteRange].remaining() > 0; }