@Override public int read() throws IOException { final int b = getInputStream().read(); update((b == -1) ? -1 : 1); return b; }
@Override public int read(long position, byte[] buffer, int offset, int length) throws IOException { try (InputStream in = openInputStream(position).in) { return in.read(buffer, offset, length); } }
@Override public int read(long position, byte[] buffer, int offset, int length) throws IOException { validatePositionedReadArgs(position, buffer, offset, length); if (length == 0) { return 0; } try (InputStream in = openInputStream(position).in) { return in.read(buffer, offset, length); } }
InputStreamAndFileLength mockStream = new InputStreamAndFileLength(1L, mock(InputStream.class)); doReturn(mockStream).when(bris).openInputStream(Mockito.anyLong()); Whitebox.setInternalState(bris, "status", ByteRangeInputStream.StreamStatus.SEEK); bris.getInputStream(); verify(bris, times(++brisOpens)).openInputStream(Mockito.anyLong()); verify(bris, times(brisCloses)).close(); verify(mockStream.in, times(isCloses)).close(); bris.getInputStream(); verify(bris, times(brisOpens)).openInputStream(Mockito.anyLong()); verify(bris, times(brisCloses)).close(); verify(mockStream.in, times(isCloses)).close(); bris.seek(1); bris.getInputStream(); verify(bris, times(++brisOpens)).openInputStream(Mockito.anyLong()); verify(bris, times(brisCloses)).close(); verify(mockStream.in, times(++isCloses)).close(); bris.getInputStream(); verify(bris, times(brisOpens)).openInputStream(Mockito.anyLong()); verify(bris, times(brisCloses)).close(); verify(mockStream.in, times(isCloses)).close(); bris.seek(1); bris.getInputStream();
InputStreamAndFileLength mockStream = new InputStreamAndFileLength(65535L, mock(InputStream.class)); doReturn(mockStream).when(bris).openInputStream(Mockito.anyLong()); Whitebox.setInternalState(bris, "status", ByteRangeInputStream.StreamStatus.SEEK); 65535, bris.available()); verify(bris, times(1)).openInputStream(Mockito.anyLong()); bris.seek(10); assertEquals("Seek 10 bytes, available should return filelength - 10" , 65525, bris.available()); bris.seek(65535); assertEquals("Seek till end of file, available should return 0 bytes", 0, bris.available()); bris.seek(0); bris.read(); assertEquals("Read 1 byte, available must return filelength - 1", 65534, bris.available()); bris.read(); assertEquals("Read another 1 byte, available must return filelength - 2", 65533, bris.available()); bris.seek(100); bris.read();
@VisibleForTesting protected InputStreamAndFileLength openInputStream(long startOffset) throws IOException { // Use the original url if no resolved url exists, eg. if // it's the first time a request is made. final boolean resolved = resolvedURL.getURL() != null; final URLOpener opener = resolved? resolvedURL: originalURL; final HttpURLConnection connection = opener.connect(startOffset, resolved); resolvedURL.setURL(getResolvedUrl(connection)); InputStream in = connection.getInputStream(); final Long length; final Map<String, List<String>> headers = connection.getHeaderFields(); if (isChunkedTransferEncoding(headers)) { // file length is not known length = null; } else { // for non-chunked transfer-encoding, get content-length long streamlength = getStreamLength(connection, headers); length = startOffset + streamlength; // Java has a bug with >2GB request streams. It won't bounds check // the reads so the transfer blocks until the server times out in = new BoundedInputStream(in, streamlength); } return new InputStreamAndFileLength(length, in); }
bris.seek(0); assertEquals("getPos wrong", 0, bris.getPos()); bris.read(); bris.getPos()); verify(oMock, times(1)).connect(0, false); bris.read(); bris.getPos()); bris.seek(100); bris.read(); bris.getPos()); verify(rMock, times(1)).connect(100, true); bris.seek(101); bris.read(); bris.seek(2500); bris.read(); bris.seek(500); try { bris.read(); fail("Exception should be thrown when content-length is not given");
@Test public void testAvailableStreamClosed() throws IOException { ByteRangeInputStream bris = mock(ByteRangeInputStream.class, CALLS_REAL_METHODS); InputStreamAndFileLength mockStream = new InputStreamAndFileLength(null, mock(InputStream.class)); doReturn(mockStream).when(bris).openInputStream(Mockito.anyLong()); Whitebox.setInternalState(bris, "status", ByteRangeInputStream.StreamStatus.SEEK); bris.close(); try{ bris.available(); fail("Exception should be thrown when stream is closed"); }catch(IOException e){ assertTrue("Exception when stream is closed", e.getMessage().equals("Stream closed")); } }
/** * Create with the specified URLOpeners. Original url is used to open the * stream for the first time. Resolved url is used in subsequent requests. * @param o Original url * @param r Resolved url */ public ByteRangeInputStream(URLOpener o, URLOpener r) throws IOException { this.originalURL = o; this.resolvedURL = r; getInputStream(); }
resolvedURL.setURL(getResolvedUrl(connection)); if (isChunkedTransferEncoding(headers)) {
@Test public void testAvailableLengthNotKnown() throws IOException { ByteRangeInputStream bris = mock(ByteRangeInputStream.class, CALLS_REAL_METHODS); //Length is null for chunked transfer-encoding InputStreamAndFileLength mockStream = new InputStreamAndFileLength(null, mock(InputStream.class)); doReturn(mockStream).when(bris).openInputStream(Mockito.anyLong()); Whitebox.setInternalState(bris, "status", ByteRangeInputStream.StreamStatus.SEEK); assertEquals(Integer.MAX_VALUE, bris.available()); }
private static long getStreamLength(HttpURLConnection connection, Map<String, List<String>> headers) throws IOException { String cl = connection.getHeaderField(HttpHeaders.CONTENT_LENGTH); if (cl == null) { // Try to get the content length by parsing the content range // because HftpFileSystem does not return the content length // if the content is partial. if (connection.getResponseCode() == HttpStatus.SC_PARTIAL_CONTENT) { cl = connection.getHeaderField(HttpHeaders.CONTENT_RANGE); return getLengthFromRange(cl); } else { throw new IOException(HttpHeaders.CONTENT_LENGTH + " is missing: " + headers); } } return Long.parseLong(cl); }
InputStreamAndFileLength mockStream = new InputStreamAndFileLength(1L, mock(InputStream.class)); doReturn(mockStream).when(bris).openInputStream(Mockito.anyLong()); Whitebox.setInternalState(bris, "status", ByteRangeInputStream.StreamStatus.SEEK); bris.getInputStream(); verify(bris, times(++brisOpens)).openInputStream(Mockito.anyLong()); verify(bris, times(brisCloses)).close(); verify(mockStream.in, times(isCloses)).close(); bris.getInputStream(); verify(bris, times(brisOpens)).openInputStream(Mockito.anyLong()); verify(bris, times(brisCloses)).close(); verify(mockStream.in, times(isCloses)).close(); bris.seek(1); bris.getInputStream(); verify(bris, times(++brisOpens)).openInputStream(Mockito.anyLong()); verify(bris, times(brisCloses)).close(); verify(mockStream.in, times(++isCloses)).close(); bris.getInputStream(); verify(bris, times(brisOpens)).openInputStream(Mockito.anyLong()); verify(bris, times(brisCloses)).close(); verify(mockStream.in, times(isCloses)).close(); bris.seek(1); bris.getInputStream();
@VisibleForTesting protected InputStream openInputStream() throws IOException { // Use the original url if no resolved url exists, eg. if // it's the first time a request is made. final boolean resolved = resolvedURL.getURL() != null; final URLOpener opener = resolved? resolvedURL: originalURL; final HttpURLConnection connection = opener.connect(startPos, resolved); resolvedURL.setURL(getResolvedUrl(connection)); InputStream in = connection.getInputStream(); final Map<String, List<String>> headers = connection.getHeaderFields(); if (isChunkedTransferEncoding(headers)) { // file length is not known fileLength = null; } else { // for non-chunked transfer-encoding, get content-length long streamlength = getStreamLength(connection, headers); fileLength = startPos + streamlength; // Java has a bug with >2GB request streams. It won't bounds check // the reads so the transfer blocks until the server times out in = new BoundedInputStream(in, streamlength); } return in; }
bris.seek(0); assertEquals("getPos wrong", 0, bris.getPos()); bris.read(); bris.getPos()); verify(oMock, times(1)).connect(0, false); bris.read(); bris.getPos()); bris.seek(100); bris.read(); bris.getPos()); verify(rMock, times(1)).connect(100, true); bris.seek(101); bris.read(); bris.seek(2500); bris.read(); bris.seek(500); try { bris.read(); fail("Exception should be thrown when content-length is not given");
/** * Create with the specified URLOpeners. Original url is used to open the * stream for the first time. Resolved url is used in subsequent requests. * @param o Original url * @param r Resolved url */ public ByteRangeInputStream(URLOpener o, URLOpener r) throws IOException { this.originalURL = o; this.resolvedURL = r; getInputStream(); }
@Override public void readFully(long position, byte[] buffer, int offset, int length) throws IOException { validatePositionedReadArgs(position, buffer, offset, length); if (length == 0) { return; } final InputStreamAndFileLength fin = openInputStream(position); try { if (fin.length != null && length + position > fin.length) { throw new EOFException("The length to read " + length + " exceeds the file length " + fin.length); } int nread = 0; while (nread < length) { int nbytes = fin.in.read(buffer, offset + nread, length - nread); if (nbytes < 0) { throw new EOFException(FSExceptionMessages.EOF_IN_READ_FULLY); } nread += nbytes; } } finally { fin.in.close(); } }
private static long getStreamLength(HttpURLConnection connection, Map<String, List<String>> headers) throws IOException { String cl = connection.getHeaderField(HttpHeaders.CONTENT_LENGTH); if (cl == null) { // Try to get the content length by parsing the content range // because HftpFileSystem does not return the content length // if the content is partial. if (connection.getResponseCode() == HttpStatus.SC_PARTIAL_CONTENT) { cl = connection.getHeaderField(HttpHeaders.CONTENT_RANGE); return getLengthFromRange(cl); } else { throw new IOException(HttpHeaders.CONTENT_LENGTH + " is missing: " + headers); } } return Long.parseLong(cl); }
@Override public int read() throws IOException { final int b = getInputStream().read(); update((b == -1) ? -1 : 1); return b; }