msgraph-sdk-java-core icon indicating copy to clipboard operation
msgraph-sdk-java-core copied to clipboard

LargeFileTaskUpload's constructor checks for available bytes (it should not)

Open kekolab opened this issue 1 year ago • 0 comments

When creating a LargeFileTaskUpload, the constructor checks whether the stream has available bytes or not https://github.com/microsoftgraph/msgraph-sdk-java-core/blob/3d9a4611de682c0f5a890ade08f0c55f89e9092c/src/main/java/com/microsoft/graph/core/tasks/LargeFileUploadTask.java#L91, but, the javadoc of InputStream.available() clearly states that:

Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking, which may be 0, or 0 when end of stream is detected [...] Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.

While it is true that, in LargeFileUploadTask's constructor, it is not used to allocate a buffer, when available() returns 0, an exception is raised and the stream cannot be used (although it contains bytes).

The funny side is that when called of a stream returned by the SDK, available() returns 0!!! So, and it is a paradox, the stream of a file returned by the API cannot be used in the API itself to upload its content to another location and/or drive.

I am using version 3.1.10

Expected behavior

You should be able to construct a LargeFileUploadTask also when InputStream.available() returns 0.

Actual behavior

You cannot construct a LargeFileUploadTask also when InputStream.available() returns 0.

Steps to reproduce the behavior

The stream returned by the SDK itself reports 0 bytes available

The following test fails

    @Test
    public void bug_NoBytesAvailables() throws IOException {
        GraphServiceClient client = // obtain it somehow
        Drive drive = client.me().drive().get();
        DriveItem root = client.drives().byDriveId(drive.getId()).root().get();
        DriveItem file = client.drives().byDriveId(drive.getId()).items()
                .byDriveItemId(root.getId()).children().get().getValue().stream()
                .filter(child -> child.getFile() != null).findAny().get();
        InputStream fileContent = client.drives().byDriveId(drive.getId()).items()
                .byDriveItemId(file.getId()).content().get();
        assertTrue(fileContent.available() > 0);
    }

The stream returned by the SDK actually has available bytes

Same code, but I do not call the available method and read the stream. This test passes

    @Test
    public void bug_BytesAreActuallyThere() throws IOException {
        GraphServiceClient client = // obtain it somehow
        Drive drive = client.me().drive().get();
        DriveItem root = client.drives().byDriveId(drive.getId()).root().get();
        DriveItem file = client.drives().byDriveId(drive.getId()).items()
                .byDriveItemId(root.getId()).children().get().getValue().stream()
                .filter(child -> child.getFile() != null).findAny().get();
        InputStream fileContent = client.drives().byDriveId(drive.getId()).items()
                .byDriveItemId(file.getId()).content().get();
        byte[] content = fileContent.readAllBytes();
        assertTrue(content.length > 0);
    }

Conclusions

A stream returned by the SDK itself cannot be used to create a LargeFileUploadTask.

kekolab avatar May 22 '24 10:05 kekolab