Skip to content

Commit 2478d89

Browse files
committed
Add TUS protocol selection proof
1 parent 7c2305a commit 2478d89

6 files changed

Lines changed: 362 additions & 14 deletions

File tree

example/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ tasks.register('api2DevdockTusParallelUploadConcat', JavaExec) {
7272
workingDir = rootProject.projectDir
7373
}
7474

75+
tasks.register('api2DevdockTusProtocolVersionSelection', JavaExec) {
76+
classpath = sourceSets.main.runtimeClasspath
77+
mainClass = 'io.tus.java.example.Api2DevdockTusProtocolVersionSelection'
78+
workingDir = rootProject.projectDir
79+
}
80+
7581
tasks.register('api2DevdockTusRequestLifecycleHooks', JavaExec) {
7682
classpath = sourceSets.main.runtimeClasspath
7783
mainClass = 'io.tus.java.example.Api2DevdockTusRequestLifecycleHooks'
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package io.tus.java.example;
2+
3+
import io.tus.java.client.TusClient;
4+
import io.tus.java.client.TusUpload;
5+
import io.tus.java.client.TusUploader;
6+
import org.json.JSONObject;
7+
8+
import java.io.ByteArrayInputStream;
9+
import java.net.URL;
10+
import java.util.Map;
11+
12+
public final class Api2DevdockTusProtocolVersionSelection {
13+
/**
14+
* Run the API2 devdock TUS protocol-version selection example.
15+
*
16+
* @param args ignored
17+
*/
18+
public static void main(String[] args) {
19+
try {
20+
System.setProperty("http.strictPostRedirect", "true");
21+
22+
final JSONObject scenario = Api2DevdockScenario.loadScenario();
23+
final JSONObject result = uploadWithSelectedProtocol(scenario);
24+
Api2DevdockScenario.writeResult(result);
25+
26+
System.out.println(
27+
"Java TUS SDK devdock scenario "
28+
+ scenario.getString("scenarioId")
29+
+ " created upload "
30+
+ result.getString("uploadUrl")
31+
);
32+
} catch (Exception e) {
33+
e.printStackTrace();
34+
System.exit(1);
35+
}
36+
}
37+
38+
private static JSONObject uploadWithSelectedProtocol(JSONObject scenario) throws Exception {
39+
final JSONObject conformanceScenario = Api2DevdockScenario.conformanceScenario(scenario);
40+
final byte[] content = Api2DevdockScenario.conformanceInputSourceBytes(
41+
conformanceScenario
42+
);
43+
final URL endpointOrigin = new URL(Api2DevdockScenario.conformanceInputStringOption(
44+
conformanceScenario,
45+
"endpointUrl"
46+
));
47+
final Map<String, String> metadata = Api2DevdockScenario.conformanceInputStringMapOption(
48+
conformanceScenario,
49+
"metadata"
50+
);
51+
final String protocol = Api2DevdockScenario.conformanceInputStringOption(
52+
conformanceScenario,
53+
"protocol"
54+
);
55+
final boolean uploadDataDuringCreation =
56+
Api2DevdockScenario.conformanceInputBooleanOption(
57+
conformanceScenario,
58+
"uploadDataDuringCreation",
59+
false
60+
);
61+
if (!uploadDataDuringCreation) {
62+
throw new IllegalArgumentException(
63+
"Java protocol-version selection proof expects creation with upload"
64+
);
65+
}
66+
67+
final JSONObject completion = conformanceScenario.getJSONObject("completion");
68+
try (Api2DevdockTusConformanceServer conformanceServer =
69+
new Api2DevdockTusConformanceServer(conformanceScenario, endpointOrigin)) {
70+
final TusClient client = new TusClient();
71+
client.setProtocol(protocol);
72+
client.setUploadCreationURL(conformanceServer.endpointUrl());
73+
74+
final TusUpload upload = new TusUpload();
75+
upload.setInputStream(new ByteArrayInputStream(content));
76+
upload.setSize(content.length);
77+
upload.setFingerprint(
78+
scenario.getString("scenarioId") + "-java-protocol-version-selection"
79+
);
80+
upload.setMetadata(metadata);
81+
82+
final TusUploader uploader = client.createUploadWithData(upload, content.length);
83+
uploader.finish();
84+
85+
conformanceServer.assertExhausted();
86+
final JSONObject result = conformanceServer.result();
87+
result.put("completionKind", completion.getString("kind"));
88+
result.put("errorCalled", false);
89+
result.put("requestCount", result.getJSONArray("requestMethods").length());
90+
result.put("successCalled", true);
91+
result.put(
92+
"uploadUrl",
93+
conformanceServer.canonicalUrl(uploader.getUploadURL().toString())
94+
);
95+
96+
return result;
97+
}
98+
}
99+
100+
private Api2DevdockTusProtocolVersionSelection() {
101+
throw new IllegalStateException("Utility class");
102+
}
103+
}

src/main/java/io/tus/java/client/TusClient.java

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class TusClient {
2828
private boolean addRequestId;
2929
private TusURLStore urlStore;
3030
private Map<String, String> headers;
31+
private String protocol = TusProtocol.DEFAULT_CLIENT_PROTOCOL;
3132
private int connectTimeout = 5000;
3233
private TusRequestLifecycleHooks requestLifecycleHooks;
3334
private volatile HttpURLConnection currentConnection;
@@ -169,6 +170,31 @@ public Map<String, String> getHeaders() {
169170
return headers;
170171
}
171172

173+
/**
174+
* Select the TUS client protocol mode used for generated protocol headers.
175+
*
176+
* @param protocol The protocol mode, e.g. {@code tus-v1} or {@code ietf-draft-05}.
177+
*/
178+
public void setProtocol(@Nullable String protocol) {
179+
final String normalizedProtocol = TusProtocol.normalizeProtocol(protocol);
180+
if (normalizedProtocol == null) {
181+
throw new IllegalArgumentException(
182+
TusProtocol.START_OPTION_VALIDATION_UNSUPPORTED_PROTOCOL_PREFIX + protocol
183+
);
184+
}
185+
186+
this.protocol = normalizedProtocol;
187+
}
188+
189+
/**
190+
* Return the selected TUS client protocol mode.
191+
*
192+
* @return The selected protocol mode.
193+
*/
194+
public String getProtocol() {
195+
return protocol;
196+
}
197+
172198
/**
173199
* Enable generated request IDs for every HTTP request made by this TusClient instance.
174200
*/
@@ -363,10 +389,7 @@ private TusUploader createUpload(
363389
prepareUploadCreationHeaders(connection, upload);
364390

365391
if (bytesToUpload > 0) {
366-
connection.setRequestProperty(
367-
TusProtocol.UPLOAD_BODY_CONTENT_TYPE_HEADER_NAME,
368-
TusProtocol.UPLOAD_BODY_CONTENT_TYPE
369-
);
392+
prepareUploadBodyHeaders(connection, bytesToUpload >= upload.getSize());
370393
connection.setDoOutput(true);
371394
connection.setFixedLengthStreamingMode(bytesToUpload);
372395
}
@@ -535,6 +558,30 @@ private static void prepareUploadMetadataHeaders(
535558
}
536559
}
537560

561+
private void prepareUploadBodyHeaders(
562+
@NotNull HttpURLConnection connection,
563+
boolean requestCompletesUpload
564+
) {
565+
final String contentType = TusProtocol.protocolUploadBodyContentType(protocol);
566+
if (contentType != null) {
567+
connection.setRequestProperty(
568+
TusProtocol.UPLOAD_BODY_CONTENT_TYPE_HEADER_NAME,
569+
contentType
570+
);
571+
}
572+
573+
final String uploadCompleteHeaderName =
574+
TusProtocol.protocolUploadCompleteHeaderName(protocol);
575+
if (uploadCompleteHeaderName == null) {
576+
return;
577+
}
578+
579+
connection.setRequestProperty(
580+
uploadCompleteHeaderName,
581+
TusProtocol.protocolUploadCompleteHeaderValue(protocol, requestCompletesUpload)
582+
);
583+
}
584+
538585
private static String finalUploadConcatValue(@NotNull List<URL> uploadURLs) {
539586
StringBuilder value = new StringBuilder(TusProtocol.CONCATENATION_FINAL_PREFIX);
540587
for (int index = 0; index < uploadURLs.size(); index++) {
@@ -814,7 +861,7 @@ public void prepareConnection(@NotNull HttpURLConnection connection) {
814861
connection.setInstanceFollowRedirects(Boolean.getBoolean("http.strictPostRedirect"));
815862

816863
connection.setConnectTimeout(connectTimeout);
817-
TusProtocol.prepareRequestHeaders(connection, headers, addRequestId);
864+
TusProtocol.prepareRequestHeaders(connection, headers, addRequestId, protocol);
818865
}
819866

820867
final void runBeforeRequest(

0 commit comments

Comments
 (0)