Skip to content

Commit 694cef4

Browse files
authored
Merge pull request #147 from gjeanmart/feature/http_client_timeout
Implement HTTP client side timeout
2 parents 5a8bcbc + f6ea7ce commit 694cef4

File tree

2 files changed

+44
-15
lines changed

2 files changed

+44
-15
lines changed

src/main/java/io/ipfs/api/IPFS.java

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ public class IPFS {
1818
public enum PinType {all, direct, indirect, recursive}
1919
public List<String> ObjectTemplates = Arrays.asList("unixfs-dir");
2020
public List<String> ObjectPatchTypes = Arrays.asList("add-link", "rm-link", "set-data", "append-data");
21+
private static final int DEFAULT_TIMEOUT = 0;
2122

2223
public final String host;
2324
public final int port;
2425
public final String protocol;
2526
private final String version;
27+
private int timeout = DEFAULT_TIMEOUT;
2628
public final Key key = new Key();
2729
public final Pin pin = new Pin();
2830
public final Repo repo = new Repo();
@@ -73,6 +75,17 @@ public IPFS(String host, int port, String version, boolean ssl) {
7375
throw new RuntimeException(e);
7476
}
7577
}
78+
79+
/**
80+
* Configure a HTTP client timeout
81+
* @param timeout (default 0: infinite timeout)
82+
* @return current IPFS object with configured timeout
83+
*/
84+
public IPFS timeout(int timeout) {
85+
if(timeout < 0) throw new IllegalArgumentException("timeout must be zero or positive");
86+
this.timeout = timeout;
87+
return this;
88+
}
7689

7790
public List<MerkleNode> add(NamedStreamable file) throws IOException {
7891
return add(file, false);
@@ -659,13 +672,11 @@ private void retrieveAndParseStream(String path, Consumer<Object> results, Consu
659672

660673
private byte[] retrieve(String path) throws IOException {
661674
URL target = new URL(protocol, host, port, version + path);
662-
return IPFS.get(target);
675+
return IPFS.get(target, timeout);
663676
}
664677

665-
private static byte[] get(URL target) throws IOException {
666-
HttpURLConnection conn = (HttpURLConnection) target.openConnection();
667-
conn.setRequestMethod("GET");
668-
conn.setRequestProperty("Content-Type", "application/json");
678+
private static byte[] get(URL target, int timeout) throws IOException {
679+
HttpURLConnection conn = configureConnection(target, "GET", timeout);
669680

670681
try {
671682
InputStream in = conn.getInputStream();
@@ -678,6 +689,8 @@ private static byte[] get(URL target) throws IOException {
678689
return resp.toByteArray();
679690
} catch (ConnectException e) {
680691
throw new RuntimeException("Couldn't connect to IPFS daemon at "+target+"\n Is IPFS running?");
692+
} catch (SocketTimeoutException e) {
693+
throw new RuntimeException(String.format("timeout (%d ms) has been exceeded", timeout));
681694
} catch (IOException e) {
682695
String err = new String(readFully(conn.getErrorStream()));
683696
throw new RuntimeException("IOException contacting IPFS daemon.\nTrailer: " + conn.getHeaderFields().get("Trailer") + " " + err, e);
@@ -725,28 +738,24 @@ private List<Object> getAndParseStream(String path) throws IOException {
725738

726739
private InputStream retrieveStream(String path) throws IOException {
727740
URL target = new URL("http", host, port, version + path);
728-
return IPFS.getStream(target);
741+
return IPFS.getStream(target, timeout);
729742
}
730743

731-
private static InputStream getStream(URL target) throws IOException {
732-
HttpURLConnection conn = (HttpURLConnection) target.openConnection();
733-
conn.setRequestMethod("GET");
734-
conn.setRequestProperty("Content-Type", "application/json");
744+
private static InputStream getStream(URL target, int timeout) throws IOException {
745+
HttpURLConnection conn = configureConnection(target, "GET", timeout);
735746
return conn.getInputStream();
736747
}
737748

738749
private Map postMap(String path, byte[] body, Map<String, String> headers) throws IOException {
739750
URL target = new URL(protocol, host, port, version + path);
740-
return (Map) JSONParser.parse(new String(post(target, body, headers)));
751+
return (Map) JSONParser.parse(new String(post(target, body, headers, timeout)));
741752
}
742753

743-
private static byte[] post(URL target, byte[] body, Map<String, String> headers) throws IOException {
744-
HttpURLConnection conn = (HttpURLConnection) target.openConnection();
754+
private static byte[] post(URL target, byte[] body, Map<String, String> headers, int timeout) throws IOException {
755+
HttpURLConnection conn = configureConnection(target, "POST", timeout);
745756
for (String key: headers.keySet())
746757
conn.setRequestProperty(key, headers.get(key));
747758
conn.setDoOutput(true);
748-
conn.setRequestMethod("POST");
749-
conn.setRequestProperty("Content-Type", "application/json");
750759
OutputStream out = conn.getOutputStream();
751760
out.write(body);
752761
out.flush();
@@ -768,4 +777,12 @@ private static final byte[] readFully(InputStream in) throws IOException {
768777
private static boolean detectSSL(MultiAddress multiaddress) {
769778
return multiaddress.toString().contains("/https");
770779
}
780+
781+
private static HttpURLConnection configureConnection(URL target, String method, int timeout) throws IOException {
782+
HttpURLConnection conn = (HttpURLConnection) target.openConnection();
783+
conn.setRequestMethod(method);
784+
conn.setRequestProperty("Content-Type", "application/json");
785+
conn.setReadTimeout(timeout);
786+
return conn;
787+
}
771788
}

src/test/java/io/ipfs/api/APITest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,18 @@ public void toolsTest() throws IOException {
720720
Map commands = ipfs.commands();
721721
}
722722

723+
@Test(expected = RuntimeException.class)
724+
public void testTimeoutFail() throws IOException {
725+
IPFS ipfs = new IPFS(new MultiAddress("/ip4/127.0.0.1/tcp/5001")).timeout(1000);
726+
ipfs.cat(Multihash.fromBase58("QmYpbSXyiCTYCbyMpzrQNix72nBYB8WRv6i39JqRc8C1ry"));
727+
}
728+
729+
@Test
730+
public void testTimeoutOK() throws IOException {
731+
IPFS ipfs = new IPFS(new MultiAddress("/ip4/127.0.0.1/tcp/5001")).timeout(1000);
732+
ipfs.cat(Multihash.fromBase58("Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a"));
733+
}
734+
723735
// this api is disabled until deployment over IPFS is enabled
724736
public void updateTest() throws IOException {
725737
Object check = ipfs.update.check();

0 commit comments

Comments
 (0)