private void finishConnection() throws ProtocolException, IOException { if(output != null) output.close(); if(connection != null) { int responseCode = connection.getResponseCode(); connection.disconnect(); if (!(responseCode >= 200 && responseCode < 300)) { throw new ProtocolException("unexpected status code (" + responseCode + ") while uploading chunk", connection); } // TODO detect changes and seek accordingly long serverOffset = getHeaderFieldLong(connection, "Upload-Offset"); if(serverOffset == -1) { throw new ProtocolException("response to PATCH request contains no or invalid Upload-Offset header", connection); } if(offset != serverOffset) { throw new ProtocolException( String.format("response contains different Upload-Offset value (%d) than expected (%d)", serverOffset, offset), connection); } connection = null; } }
/** * Try to resume an upload using {@link #resumeUpload(TusUpload)}. If the method call throws * an {@link ResumingNotEnabledException} or {@link FingerprintNotFoundException}, a new upload * will be created using {@link #createUpload(TusUpload)}. * * @param upload The file for which an upload will be resumed * @throws ProtocolException Thrown if the remote server sent an unexpected response, e.g. * wrong status codes or missing/invalid headers. * @throws IOException Thrown if an exception occurs while issuing the HTTP request. */ public TusUploader resumeOrCreateUpload(@NotNull TusUpload upload) throws ProtocolException, IOException { try { return resumeUpload(upload); } catch(FingerprintNotFoundException e) { return createUpload(upload); } catch(ResumingNotEnabledException e) { return createUpload(upload); } catch(ProtocolException e) { // If the attempt to resume returned a 404 Not Found, we immediately try to create a new // one since TusExectuor would not retry this operation. HttpURLConnection connection = e.getCausingConnection(); if(connection != null && connection.getResponseCode() == 404) { return createUpload(upload); } throw e; } }
} catch(ProtocolException e) { if(!e.shouldRetry()) { throw e;
@Test public void testTusUploaderFailedExpectation() throws IOException, ProtocolException { Assume.assumeFalse(isOpenJDK6); FailingExpectationServer server = new FailingExpectationServer(); server.start(); byte[] content = "hello world".getBytes(); TusClient client = new TusClient(); URL uploadUrl = new URL(server.getURL() + "/expect"); TusInputStream input = new TusInputStream(new ByteArrayInputStream(content)); long offset = 3; boolean exceptionThrown = false; TusUploader uploader = new TusUploader(client, uploadUrl, input, offset); try { uploader.uploadChunk(); } catch(ProtocolException e) { assertTrue(e.getMessage().contains("500")); exceptionThrown = true; } finally { assertTrue(exceptionThrown); } }
@Test public void testMissingUploadOffsetHeader() throws Exception { byte[] content = "hello world".getBytes(); mockServer.when(new HttpRequest() .withPath("/files/missingHeader")) .respond(new HttpResponse() .withStatusCode(204) .withHeader("Tus-Resumable", TusClient.TUS_VERSION)); TusClient client = new TusClient(); URL uploadUrl = new URL(mockServerURL + "/missingHeader"); TusInputStream input = new TusInputStream(new ByteArrayInputStream(content)); TusUploader uploader = new TusUploader(client, uploadUrl, input, 0); boolean exceptionThrown = false; try { assertEquals(11, uploader.uploadChunk()); uploader.finish(); } catch(ProtocolException e) { assertTrue(e.getMessage().contains("no or invalid Upload-Offset header")); exceptionThrown = true; } finally { assertTrue(exceptionThrown); } }
throw new ProtocolException("unexpected status code (" + responseCode + ") while resuming upload", connection); throw new ProtocolException("missing upload offset in response for resuming upload", connection);
@Test public void testUnmatchingUploadOffsetHeader() throws Exception { byte[] content = "hello world".getBytes(); mockServer.when(new HttpRequest() .withPath("/files/unmatchingHeader")) .respond(new HttpResponse() .withStatusCode(204) .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Offset", "44")); TusClient client = new TusClient(); URL uploadUrl = new URL(mockServerURL + "/unmatchingHeader"); TusInputStream input = new TusInputStream(new ByteArrayInputStream(content)); TusUploader uploader = new TusUploader(client, uploadUrl, input, 0); boolean exceptionThrown = false; try { assertEquals(11, uploader.uploadChunk()); uploader.finish(); } catch(ProtocolException e) { assertTrue(e.getMessage().contains("different Upload-Offset value (44) than expected (11)")); exceptionThrown = true; } finally { assertTrue(exceptionThrown); } } }
throw new ProtocolException("unexpected status code (" + responseCode + ") while creating upload", connection); throw new ProtocolException("missing upload URL in response for creating upload", connection);
@Test public void testCreateUploadWithMissingLocationHeader() throws IOException, Exception { mockServer.when(new HttpRequest() .withMethod("POST") .withPath("/files") .withHeader("Tus-Resumable", TusClient.TUS_VERSION) .withHeader("Upload-Length", "10")) .respond(new HttpResponse() .withStatusCode(201) .withHeader("Tus-Resumable", TusClient.TUS_VERSION)); TusClient client = new TusClient(); client.setUploadCreationURL(mockServerURL); TusUpload upload = new TusUpload(); upload.setSize(10); upload.setInputStream(new ByteArrayInputStream(new byte[10])); try { TusUploader uploader = client.createUpload(upload); throw new Exception("unreachable code reached"); } catch(ProtocolException e) { assertEquals(e.getMessage(), "missing upload URL in response for creating upload"); } }
@Override protected void makeAttempt() throws ProtocolException, IOException { super.makeAttempt(); throw new ProtocolException("something happened", new MockHttpURLConnection(500)); } };
@Override protected void makeAttempt() throws ProtocolException, IOException { super.makeAttempt(); throw new ProtocolException("something happened", new MockHttpURLConnection(404)); } };