Skip to content

Commit c3076d3

Browse files
committed
Merge branch 'read-from-url' of github.com:mdaniel/MaxMind-DB-Reader-java into greg/input-stream
2 parents 3eef6f5 + 0cc4dfb commit c3076d3

3 files changed

Lines changed: 129 additions & 17 deletions

File tree

src/main/java/com/maxmind/db/Reader.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.Closeable;
44
import java.io.File;
55
import java.io.IOException;
6+
import java.io.InputStream;
67
import java.net.InetAddress;
78
import java.nio.ByteBuffer;
89

@@ -52,6 +53,17 @@ public Reader(File database) throws IOException {
5253
this(database, FileMode.MEMORY_MAPPED);
5354
}
5455

56+
/**
57+
* Constructs a Reader as if in mode {@link FileMode#MEMORY}, without using
58+
* a <code>File</code> instance.
59+
* @param source the InputStream that contains the MaxMind DB file.
60+
* @throws IOException
61+
* if there is an error reading from the Stream.
62+
*/
63+
public Reader(InputStream source) throws IOException {
64+
this(ThreadBuffer.newInstance(source), "an InputStream");
65+
}
66+
5567
/**
5668
* Constructs a Reader for the MaxMind DB format. The file passed to it must
5769
* be a valid MaxMind DB file such as a GeoIP2 database file.
@@ -64,8 +76,12 @@ public Reader(File database) throws IOException {
6476
* if there is an error opening or reading from the file.
6577
*/
6678
public Reader(File database, FileMode fileMode) throws IOException {
67-
this.threadBuffer = new ThreadBuffer(database, fileMode);
68-
int start = this.findMetadataStart(database.getName());
79+
this(new ThreadBuffer(database, fileMode), database.getName());
80+
}
81+
82+
private Reader(ThreadBuffer buffer, String name) throws IOException {
83+
this.threadBuffer = buffer;
84+
int start = this.findMetadataStart(name);
6985

7086
Decoder metadataDecoder = new Decoder(this.threadBuffer, start);
7187
this.metadata = new Metadata(metadataDecoder.decode(start).getNode());

src/main/java/com/maxmind/db/ThreadBuffer.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.maxmind.db;
22

3+
import java.io.ByteArrayOutputStream;
34
import java.io.Closeable;
45
import java.io.File;
6+
import java.io.InputStream;
57
import java.io.IOException;
68
import java.io.RandomAccessFile;
79
import java.nio.ByteBuffer;
@@ -11,6 +13,27 @@
1113
import com.maxmind.db.Reader.FileMode;
1214

1315
final class ThreadBuffer extends ThreadLocal<ByteBuffer> implements Closeable {
16+
/**
17+
* Construct a ThreadBuffer from the provided URL.
18+
* @param stream the source of my bytes.
19+
* @return a newly constructed instance based on the contents of your URL.
20+
* @throws IOException if unable to read from your source.
21+
* @throws NullPointerException if you provide a NULL InputStream
22+
*/
23+
public static ThreadBuffer newInstance(InputStream stream) throws IOException {
24+
if (null == stream) {
25+
throw new NullPointerException("Unable to use a NULL InputStream");
26+
}
27+
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
28+
final byte[] buffer = new byte[16 * 1024];
29+
int br;
30+
while (-1 != (br = stream.read(buffer))) {
31+
baos.write(buffer, 0, br);
32+
}
33+
final ByteBuffer bBuffer = ByteBuffer.wrap(baos.toByteArray());
34+
return new ThreadBuffer(bBuffer);
35+
}
36+
1437
// DO NOT PASS THESE OUTSIDE THIS CLASS. Doing so will remove thread
1538
// safety.
1639
private final ByteBuffer buffer;
@@ -49,4 +72,4 @@ public void close() throws IOException {
4972
this.raf.close();
5073
}
5174
}
52-
}
75+
}

src/test/java/com/maxmind/db/ReaderTest.java

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
import java.io.File;
1010
import java.io.IOException;
11+
import java.io.InputStream;
1112
import java.math.BigInteger;
1213
import java.net.InetAddress;
1314
import java.net.URI;
1415
import java.net.URISyntaxException;
15-
import java.net.UnknownHostException;
1616
import java.util.HashMap;
1717
import java.util.Map;
1818

@@ -23,15 +23,12 @@
2323
import com.fasterxml.jackson.databind.JsonNode;
2424
import com.fasterxml.jackson.databind.ObjectMapper;
2525
import com.fasterxml.jackson.databind.node.ObjectNode;
26-
import com.maxmind.db.InvalidDatabaseException;
27-
import com.maxmind.db.Reader;
28-
import com.maxmind.db.Metadata;
2926

3027
public class ReaderTest {
3128
private final ObjectMapper om = new ObjectMapper();
3229

3330
@Test
34-
public void test() throws InvalidDatabaseException, IOException,
31+
public void test() throws IOException,
3532
URISyntaxException {
3633
for (long recordSize : new long[] { 24, 28, 32 }) {
3734
for (int ipVersion : new int[] { 4, 6 }) {
@@ -55,12 +52,24 @@ public void test() throws InvalidDatabaseException, IOException,
5552
}
5653

5754
@Test
58-
public void testNoIpV4SearchTree() throws IOException, URISyntaxException {
55+
public void testNoIpV4SearchTreeFile() throws IOException, URISyntaxException {
5956
URI file = ReaderTest.class.getResource(
6057
"/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb")
6158
.toURI();
6259

6360
Reader reader = new Reader(new File(file));
61+
testNoIpV4SearchTree(reader);
62+
}
63+
@Test
64+
public void testNoIpV4SearchTreeURL() throws IOException, URISyntaxException {
65+
InputStream stream = ReaderTest.class.getResource(
66+
"/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb")
67+
.openStream();
68+
Reader reader = new Reader(stream);
69+
testNoIpV4SearchTree(reader);
70+
}
71+
private void testNoIpV4SearchTree(Reader reader) throws IOException, URISyntaxException {
72+
6473

6574
assertEquals("::/64", reader.get(InetAddress.getByName("1.1.1.1"))
6675
.textValue());
@@ -69,11 +78,23 @@ public void testNoIpV4SearchTree() throws IOException, URISyntaxException {
6978
}
7079

7180
@Test
72-
public void testDecodingTypes() throws URISyntaxException, IOException {
81+
public void testDecodingTypesFile() throws URISyntaxException, IOException {
7382
URI file = ReaderTest.class.getResource(
7483
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();
7584

7685
Reader reader = new Reader(new File(file));
86+
testDecodingTypes(reader);
87+
}
88+
@Test
89+
public void testDecodingTypesURL() throws URISyntaxException, IOException {
90+
InputStream stream = ReaderTest.class.getResource(
91+
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb")
92+
.openStream();
93+
94+
Reader reader = new Reader(stream);
95+
testDecodingTypes(reader);
96+
}
97+
private void testDecodingTypes(Reader reader) throws URISyntaxException, IOException {
7798
JsonNode record = reader.get(InetAddress.getByName("::1.1.1.0"));
7899

79100
assertEquals(true, record.get("boolean").booleanValue());
@@ -117,11 +138,23 @@ public void testDecodingTypes() throws URISyntaxException, IOException {
117138
}
118139

119140
@Test
120-
public void testZeros() throws URISyntaxException, IOException {
141+
public void testZerosFile() throws URISyntaxException, IOException {
121142
URI file = ReaderTest.class.getResource(
122143
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb").toURI();
123144

124145
Reader reader = new Reader(new File(file));
146+
testZeros(reader);
147+
}
148+
@Test
149+
public void testZerosURL() throws URISyntaxException, IOException {
150+
InputStream stream = ReaderTest.class.getResource(
151+
"/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb")
152+
.openStream();
153+
154+
Reader reader = new Reader(stream);
155+
testZeros(reader);
156+
}
157+
private void testZeros(Reader reader) throws URISyntaxException, IOException {
125158
JsonNode record = reader.get(InetAddress.getByName("::"));
126159

127160
assertEquals(false, record.get("boolean").booleanValue());
@@ -149,13 +182,26 @@ public void testZeros() throws URISyntaxException, IOException {
149182
public ExpectedException thrown = ExpectedException.none();
150183

151184
@Test
152-
public void testBrokenDatabase() throws URISyntaxException, IOException {
185+
public void testBrokenDatabaseFile() throws URISyntaxException, IOException {
153186
URI file = ReaderTest.class
154187
.getResource(
155188
"/maxmind-db/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb")
156189
.toURI();
157190

158191
Reader reader = new Reader(new File(file));
192+
testBrokenDatabase(reader);
193+
}
194+
@Test
195+
public void testBrokenDatabaseURL() throws URISyntaxException, IOException {
196+
InputStream stream = ReaderTest.class
197+
.getResource(
198+
"/maxmind-db/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb")
199+
.openStream();
200+
201+
Reader reader = new Reader(stream);
202+
testBrokenDatabase(reader);
203+
}
204+
private void testBrokenDatabase(Reader reader) throws URISyntaxException, IOException {
159205

160206
this.thrown.expect(InvalidDatabaseException.class);
161207
this.thrown
@@ -165,14 +211,29 @@ public void testBrokenDatabase() throws URISyntaxException, IOException {
165211
}
166212

167213
@Test
168-
public void testBrokenSearchTreePointer() throws URISyntaxException,
214+
public void testBrokenSearchTreePointerFile() throws URISyntaxException,
169215
IOException {
170216
URI file = ReaderTest.class
171217
.getResource(
172218
"/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb")
173219
.toURI();
174220

175221
Reader reader = new Reader(new File(file));
222+
testBrokenSearchTreePointer(reader);
223+
}
224+
@Test
225+
public void testBrokenSearchTreePointerURL() throws URISyntaxException,
226+
IOException {
227+
InputStream stream = ReaderTest.class
228+
.getResource(
229+
"/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb")
230+
.openStream();
231+
232+
Reader reader = new Reader(stream);
233+
testBrokenSearchTreePointer(reader);
234+
}
235+
private void testBrokenSearchTreePointer(Reader reader) throws URISyntaxException,
236+
IOException {
176237

177238
this.thrown.expect(InvalidDatabaseException.class);
178239
this.thrown
@@ -182,14 +243,26 @@ public void testBrokenSearchTreePointer() throws URISyntaxException,
182243
}
183244

184245
@Test
185-
public void testBrokenDataPointer() throws UnknownHostException,
186-
IOException, URISyntaxException {
246+
public void testBrokenDataPointerFile() throws IOException, URISyntaxException {
187247
URI file = ReaderTest.class
188248
.getResource(
189249
"/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb")
190250
.toURI();
191251

192252
Reader reader = new Reader(new File(file));
253+
testBrokenDataPointer(reader);
254+
}
255+
@Test
256+
public void testBrokenDataPointerURL() throws IOException, URISyntaxException {
257+
InputStream stream = ReaderTest.class
258+
.getResource(
259+
"/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb")
260+
.openStream();
261+
262+
Reader reader = new Reader(stream);
263+
testBrokenDataPointer(reader);
264+
}
265+
private void testBrokenDataPointer(Reader reader) throws IOException, URISyntaxException {
193266

194267
this.thrown.expect(InvalidDatabaseException.class);
195268
this.thrown
@@ -219,7 +292,7 @@ private void testMetadata(Reader reader, int ipVersion,
219292
}
220293

221294
private void testIpV4(Reader reader, URI file)
222-
throws InvalidDatabaseException, IOException {
295+
throws IOException {
223296

224297
for (int i = 0; i <= 5; i++) {
225298
String address = "1.1.1." + (int) Math.pow(2, i);
@@ -253,7 +326,7 @@ private void testIpV4(Reader reader, URI file)
253326

254327
// XXX - logic could be combined with above
255328
private void testIpV6(Reader reader, URI file)
256-
throws InvalidDatabaseException, IOException {
329+
throws IOException {
257330
String[] subnets = new String[] { "::1:ffff:ffff", "::2:0:0",
258331
"::2:0:40", "::2:0:50", "::2:0:58" };
259332

0 commit comments

Comments
 (0)