diff --git a/src/main/java/io/tus/java/client/TusClient.java b/src/main/java/io/tus/java/client/TusClient.java index 3bda521..1b23e76 100644 --- a/src/main/java/io/tus/java/client/TusClient.java +++ b/src/main/java/io/tus/java/client/TusClient.java @@ -21,6 +21,7 @@ public class TusClient { private URL uploadCreationURL; private boolean resumingEnabled; private boolean removeFingerprintOnSuccessEnabled; + private boolean chunkedTransferEncodingEnabled = true; private TusURLStore urlStore; private Map headers; private int connectTimeout = 5000; @@ -115,6 +116,39 @@ public boolean removeFingerprintOnSuccessEnabled() { return removeFingerprintOnSuccessEnabled; } + /** + * Enable chunked transfer encoding. + * + * @see https://en.wikipedia.org/wiki/Chunked_transfer_encoding + * @see #disableChunkedTransferEncoding() + */ + public void enableChunkedTransferEncoding() { + chunkedTransferEncodingEnabled = true; + } + + /** + * Disable chunked transfer encoding. + * + * @see https://en.wikipedia.org/wiki/Chunked_transfer_encoding + * @see #enableChunkedTransferEncoding() + */ + public void disableChunkedTransferEncoding() { + chunkedTransferEncodingEnabled = false; + } + + /** + * Get the current status of chunked transfer encoding. + * + * @see https://en.wikipedia.org/wiki/Chunked_transfer_encoding + * @see #enableChunkedTransferEncoding() + * @see #disableChunkedTransferEncoding() + * + * @return True if chunked transfer encoding has been enabled. + */ + public boolean chunkedTransferEncodingEnabled() { + return chunkedTransferEncodingEnabled; + } + /** * Set headers which will be added to every HTTP requestes made by this TusClient instance. diff --git a/src/main/java/io/tus/java/client/TusUploader.java b/src/main/java/io/tus/java/client/TusUploader.java index 282d18e..973d250 100644 --- a/src/main/java/io/tus/java/client/TusUploader.java +++ b/src/main/java/io/tus/java/client/TusUploader.java @@ -77,7 +77,9 @@ private void openConnection() throws IOException, ProtocolException { } connection.setDoOutput(true); - connection.setChunkedStreamingMode(0); + if (client.chunkedTransferEncodingEnabled()) { + connection.setChunkedStreamingMode(0); + } try { output = connection.getOutputStream(); } catch(java.net.ProtocolException pe) { @@ -176,7 +178,15 @@ public int getRequestPayloadSize() { public int uploadChunk() throws IOException, ProtocolException { openConnection(); - int bytesToRead = Math.min(getChunkSize(), bytesRemainingForRequest); + final int bytesToRead; + if (client.chunkedTransferEncodingEnabled()) { + bytesToRead = Math.min(getChunkSize(), bytesRemainingForRequest); + } else { + // No chunked tranfer encoding, so we upload a single chunk. + bytesToRead = getChunkSize(); + // The connection should be closed after single write. + bytesRemainingForRequest = 0; + } int bytesRead = input.read(buffer, bytesToRead); if(bytesRead == -1) { diff --git a/src/test/java/io/tus/java/client/TestTusUploader.java b/src/test/java/io/tus/java/client/TestTusUploader.java index e3c5f5f..e15692b 100644 --- a/src/test/java/io/tus/java/client/TestTusUploader.java +++ b/src/test/java/io/tus/java/client/TestTusUploader.java @@ -63,6 +63,63 @@ public void testTusUploader() throws IOException, ProtocolException { uploader.finish(); } + @Test + public void testTusUploaderFixedLength() throws IOException, ProtocolException { + byte[] content = "hello world".getBytes(); + + mockServer.when(new HttpRequest() + .withPath("/files/fixed") + .withHeader("Tus-Resumable", TusClient.TUS_VERSION) + .withHeader("Upload-Offset", "5") + .withHeader("Content-Type", "application/offset+octet-stream") + .withHeader(isOpenJDK6 ? "": "Expect: 100-continue") + .withBody(Arrays.copyOfRange(content, 5, 10))) + .respond(new HttpResponse() + .withStatusCode(204) + .withHeader("Tus-Resumable", TusClient.TUS_VERSION) + .withHeader("Upload-Offset", "10")); + mockServer.when(new HttpRequest() + .withPath("/files/fixed") + .withHeader("Tus-Resumable", TusClient.TUS_VERSION) + .withHeader("Upload-Offset", "10") + .withHeader("Content-Type", "application/offset+octet-stream") + .withHeader(isOpenJDK6 ? "": "Expect: 100-continue") + .withBody(Arrays.copyOfRange(content, 10, 11))) + .respond(new HttpResponse() + .withStatusCode(204) + .withHeader("Tus-Resumable", TusClient.TUS_VERSION) + .withHeader("Upload-Offset", "11")); + mockServer.when(new HttpRequest() + .withPath("/files/fixed") + .withHeader("Tus-Resumable", TusClient.TUS_VERSION) + .withHeader("Upload-Offset", "11") + .withHeader("Content-Type", "application/offset+octet-stream") + .withHeader(isOpenJDK6 ? "": "Expect: 100-continue")) + .respond(new HttpResponse() + .withStatusCode(204) + .withHeader("Tus-Resumable", TusClient.TUS_VERSION) + .withHeader("Upload-Offset", "11")); + + TusClient client = new TusClient(); + client.disableChunkedTransferEncoding(); + URL uploadUrl = new URL(mockServerURL + "/fixed"); + TusInputStream input = new TusInputStream(new ByteArrayInputStream(content)); + long offset = 5; + + TusUpload upload = new TusUpload(); + + TusUploader uploader = new TusUploader(client, upload, uploadUrl, input, offset); + + uploader.setChunkSize(5); + assertEquals(uploader.getChunkSize(), 5); + + assertEquals(5, uploader.uploadChunk()); + assertEquals(1, uploader.uploadChunk()); + assertEquals(-1, uploader.uploadChunk()); + assertEquals(11, uploader.getOffset()); + uploader.finish(); + } + @Test public void testTusUploaderClientUploadFinishedCalled() throws IOException, ProtocolException {