Skip to content

Commit 227d53d

Browse files
committed
Added disableMD5 option to GridFSBucket
JAVA-2761
1 parent 0da4dc6 commit 227d53d

File tree

22 files changed

+421
-427
lines changed

22 files changed

+421
-427
lines changed

driver-async/src/main/com/mongodb/async/client/gridfs/GridFSBucket.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ public interface GridFSBucket {
7373
*/
7474
ReadConcern getReadConcern();
7575

76+
/**
77+
* Returns true if computing MD5 checksums when uploading files is disabled.
78+
*
79+
* @return true if computing MD5 checksums when uploading files is disabled.
80+
* @since 3.8
81+
*/
82+
boolean getDisableMD5();
83+
7684
/**
7785
* Create a new GridFSBucket instance with a new chunk size in bytes.
7886
*
@@ -107,6 +115,15 @@ public interface GridFSBucket {
107115
*/
108116
GridFSBucket withReadConcern(ReadConcern readConcern);
109117

118+
/**
119+
* Create a new GridFSBucket instance with the set disable MD5 value.
120+
*
121+
* @param disableMD5 true if computing MD5 checksums when uploading files should be disabled.
122+
* @return a new GridFSBucket instance with the new disable MD5 value.
123+
* @since 3.8
124+
*/
125+
GridFSBucket withDisableMD5(boolean disableMD5);
126+
110127
/**
111128
* Opens a AsyncOutputStream that the application can write the contents of the file to.
112129
* <p>

driver-async/src/main/com/mongodb/async/client/gridfs/GridFSBucketImpl.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ final class GridFSBucketImpl implements GridFSBucket {
6060
private final int chunkSizeBytes;
6161
private final MongoCollection<GridFSFile> filesCollection;
6262
private final MongoCollection<Document> chunksCollection;
63+
private final boolean disableMD5;
6364

6465
GridFSBucketImpl(final MongoDatabase database) {
6566
this(database, "fs");
@@ -68,15 +69,16 @@ final class GridFSBucketImpl implements GridFSBucket {
6869
GridFSBucketImpl(final MongoDatabase database, final String bucketName) {
6970
this(notNull("bucketName", bucketName), DEFAULT_CHUNKSIZE_BYTES,
7071
getFilesCollection(notNull("database", database), bucketName),
71-
getChunksCollection(database, bucketName));
72+
getChunksCollection(database, bucketName), false);
7273
}
7374

7475
GridFSBucketImpl(final String bucketName, final int chunkSizeBytes, final MongoCollection<GridFSFile> filesCollection,
75-
final MongoCollection<Document> chunksCollection) {
76+
final MongoCollection<Document> chunksCollection, final boolean disableMD5) {
7677
this.bucketName = notNull("bucketName", bucketName);
7778
this.chunkSizeBytes = chunkSizeBytes;
7879
this.filesCollection = notNull("filesCollection", filesCollection);
7980
this.chunksCollection = notNull("chunksCollection", chunksCollection);
81+
this.disableMD5 = disableMD5;
8082
}
8183

8284
@Override
@@ -104,30 +106,40 @@ public ReadConcern getReadConcern() {
104106
return filesCollection.getReadConcern();
105107
}
106108

109+
@Override
110+
public boolean getDisableMD5() {
111+
return disableMD5;
112+
}
113+
107114
@Override
108115
public GridFSBucket withChunkSizeBytes(final int chunkSizeBytes) {
109-
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection, chunksCollection);
116+
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection, chunksCollection, disableMD5);
110117
}
111118

112119
@Override
113120
public GridFSBucket withReadPreference(final ReadPreference readPreference) {
114121
notNull("readPreference", readPreference);
115122
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withReadPreference(readPreference),
116-
chunksCollection.withReadPreference(readPreference));
123+
chunksCollection.withReadPreference(readPreference), disableMD5);
117124
}
118125

119126
@Override
120127
public GridFSBucket withWriteConcern(final WriteConcern writeConcern) {
121128
notNull("writeConcern", writeConcern);
122129
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withWriteConcern(writeConcern),
123-
chunksCollection.withWriteConcern(writeConcern));
130+
chunksCollection.withWriteConcern(writeConcern), disableMD5);
124131
}
125132

126133
@Override
127134
public GridFSBucket withReadConcern(final ReadConcern readConcern) {
128135
notNull("readConcern", readConcern);
129136
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withReadConcern(readConcern),
130-
chunksCollection.withReadConcern(readConcern));
137+
chunksCollection.withReadConcern(readConcern), disableMD5);
138+
}
139+
140+
@Override
141+
public GridFSBucket withDisableMD5(final boolean disableMD5) {
142+
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection, chunksCollection, disableMD5);
131143
}
132144

133145
@Override
@@ -178,8 +190,8 @@ private GridFSUploadStream createGridFSUploadStream(@Nullable final ClientSessio
178190
notNull("options", options);
179191
Integer chunkSizeBytes = options.getChunkSizeBytes();
180192
int chunkSize = chunkSizeBytes == null ? this.chunkSizeBytes : chunkSizeBytes;
181-
return new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, id, filename, chunkSize, options.getMetadata(),
182-
new GridFSIndexCheckImpl(clientSession, filesCollection, chunksCollection));
193+
return new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, id, filename, chunkSize, disableMD5,
194+
options.getMetadata(), new GridFSIndexCheckImpl(clientSession, filesCollection, chunksCollection));
183195
}
184196

185197
@Override

driver-async/src/main/com/mongodb/async/client/gridfs/GridFSUploadStreamImpl.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ final class GridFSUploadStreamImpl implements GridFSUploadStream {
4949
private final int chunkSizeBytes;
5050
private final Document metadata;
5151
private final MessageDigest md5;
52+
private final boolean disableMD5;
5253
private final GridFSIndexCheck indexCheck;
5354
private final Object closeAndWritingLock = new Object();
5455

@@ -68,7 +69,8 @@ final class GridFSUploadStreamImpl implements GridFSUploadStream {
6869

6970
GridFSUploadStreamImpl(@Nullable final ClientSession clientSession, final MongoCollection<GridFSFile> filesCollection,
7071
final MongoCollection<Document> chunksCollection, final BsonValue fileId, final String filename,
71-
final int chunkSizeBytes, @Nullable final Document metadata, final GridFSIndexCheck indexCheck) {
72+
final int chunkSizeBytes, final boolean disableMD5, @Nullable final Document metadata,
73+
final GridFSIndexCheck indexCheck) {
7274
this.clientSession = clientSession;
7375
this.filesCollection = notNull("files collection", filesCollection);
7476
this.chunksCollection = notNull("chunks collection", chunksCollection);
@@ -77,7 +79,8 @@ final class GridFSUploadStreamImpl implements GridFSUploadStream {
7779
this.chunkSizeBytes = chunkSizeBytes;
7880
this.metadata = metadata;
7981
this.indexCheck = indexCheck;
80-
md5 = getDigest();
82+
this.disableMD5 = disableMD5;
83+
md5 = createMD5Digest();
8184
chunkIndex = 0;
8285
bufferOffset = 0;
8386
buffer = new byte[chunkSizeBytes];
@@ -176,7 +179,7 @@ public void onResult(final Void result, final Throwable t) {
176179
errHandlingCallback.onResult(null, t);
177180
} else {
178181
GridFSFile gridFSFile = new GridFSFile(fileId, filename, lengthInBytes, chunkSizeBytes, new Date(),
179-
toHex(md5.digest()), metadata);
182+
getMD5Digest(), metadata);
180183

181184
SingleResultCallback<Void> insertCallback = new SingleResultCallback<Void>() {
182185
@Override
@@ -248,8 +251,9 @@ private <T> boolean takeWritingLock(final SingleResultCallback<T> errHandlingCal
248251
}
249252

250253
private void writeChunk(final SingleResultCallback<Void> callback) {
251-
if (md5 == null) {
252-
callback.onResult(null, new MongoGridFSException("No MD5 message digest available, cannot upload file"));
254+
if (md5 == null && !disableMD5) {
255+
callback.onResult(null, new MongoGridFSException("No MD5 message digest available. "
256+
+ "Use `GridFSBucket.withDisableMD5(true)` to disable creating a MD5 hash."));
253257
} else if (bufferOffset > 0) {
254258
Document insertDocument = new Document("files_id", fileId).append("n", chunkIndex).append("data", getData());
255259
SingleResultCallback<Void> insertCallback = new SingleResultCallback<Void>() {
@@ -258,7 +262,7 @@ public void onResult(final Void result, final Throwable t) {
258262
if (t != null) {
259263
callback.onResult(null, t);
260264
} else {
261-
md5.update(buffer);
265+
updateMD5();
262266
chunkIndex++;
263267
bufferOffset = 0;
264268
callback.onResult(null, null);
@@ -316,11 +320,26 @@ private <T> void callbackIsWritingException(final SingleResultCallback<T> callba
316320
}
317321

318322
@Nullable
319-
private static MessageDigest getDigest() {
320-
try {
321-
return MessageDigest.getInstance("MD5");
322-
} catch (NoSuchAlgorithmException e) {
323+
private MessageDigest createMD5Digest() {
324+
if (disableMD5) {
323325
return null;
326+
} else {
327+
try {
328+
return MessageDigest.getInstance("MD5");
329+
} catch (NoSuchAlgorithmException e) {
330+
return null;
331+
}
332+
}
333+
}
334+
335+
@Nullable
336+
private String getMD5Digest() {
337+
return md5 != null ? toHex(md5.digest()) : null;
338+
}
339+
340+
private void updateMD5() {
341+
if (md5 != null) {
342+
md5.update(buffer);
324343
}
325344
}
326345
}

driver-async/src/test/functional/com/mongodb/async/client/gridfs/GridFSBucketSmokeTestSpecification.groovy

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,15 @@ class GridFSBucketSmokeTestSpecification extends FunctionalSpecification {
7878
def content = multiChunk ? multiChunkString : singleChunkString
7979
def contentBytes = content as byte[]
8080
def expectedLength = contentBytes.length
81-
def expectedMD5 = MessageDigest.getInstance('MD5').digest(contentBytes).encodeHex().toString()
81+
def expectedMD5 = md5Disabled ? null : MessageDigest.getInstance('MD5').digest(contentBytes).encodeHex().toString()
82+
def bucket = gridFSBucket.withDisableMD5(md5Disabled)
8283
ObjectId fileId
8384

8485
when:
8586
if (direct) {
86-
fileId = run(gridFSBucket.&uploadFromStream, 'myFile', toAsyncInputStream(content.getBytes()));
87+
fileId = run(bucket.&uploadFromStream, 'myFile', toAsyncInputStream(content.getBytes()));
8788
} else {
88-
def outputStream = gridFSBucket.openUploadStream('myFile')
89+
def outputStream = bucket.openUploadStream('myFile')
8990
run(outputStream.&write, ByteBuffer.wrap(contentBytes))
9091
run(outputStream.&close)
9192
fileId = outputStream.getObjectId()
@@ -96,34 +97,36 @@ class GridFSBucketSmokeTestSpecification extends FunctionalSpecification {
9697
run(chunksCollection.&count) == chunkCount
9798

9899
when:
99-
def fileInfo = run(gridFSBucket.find().filter(eq('_id', fileId)).&first)
100+
def fileInfo = run(bucket.find().filter(eq('_id', fileId)).&first)
100101

101102
then:
102103
fileInfo.getId().getValue() == fileId
103-
fileInfo.getChunkSize() == gridFSBucket.getChunkSizeBytes()
104+
fileInfo.getChunkSize() == bucket.getChunkSizeBytes()
104105
fileInfo.getLength() == expectedLength
105106
fileInfo.getMD5() == expectedMD5
106107
fileInfo.getMetadata() == null
107108

108109
when:
109110
def byteBuffer = ByteBuffer.allocate(fileInfo.getLength() as int)
110111
if (direct) {
111-
run(gridFSBucket.openDownloadStream(fileId).&read, byteBuffer)
112+
run(bucket.openDownloadStream(fileId).&read, byteBuffer)
112113
} else {
113114
def outputStream = toAsyncOutputStream(byteBuffer)
114-
run(gridFSBucket.&downloadToStream, fileId, outputStream)
115+
run(bucket.&downloadToStream, fileId, outputStream)
115116
run(outputStream.&close)
116117
}
117118

118119
then:
119120
byteBuffer.array() == contentBytes
120121

121122
where:
122-
description | multiChunk | chunkCount | direct
123-
'a small file directly' | false | 1 | true
124-
'a small file to stream' | false | 1 | false
125-
'a large file directly' | true | 5 | true
126-
'a large file to stream' | true | 5 | false
123+
description | multiChunk | chunkCount | direct | md5Disabled
124+
'a small file directly' | false | 1 | true | false
125+
'a small file to stream' | false | 1 | false | false
126+
'a large file directly' | true | 5 | true | false
127+
'a large file to stream' | true | 5 | false | false
128+
'a small file directly no md5' | false | 1 | true | true
129+
'a small file to stream no md5' | false | 1 | false | true
127130
}
128131

129132
@Category(Slow)

driver-async/src/test/functional/com/mongodb/async/client/gridfs/GridFSTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,18 +326,23 @@ private void doUpload(final BsonDocument rawArguments, final BsonDocument assert
326326
final String filename = arguments.getString("filename").getValue();
327327
final InputStream inputStream = new ByteArrayInputStream(arguments.getBinary("source").getData());
328328
final GridFSUploadOptions options = new GridFSUploadOptions();
329+
GridFSBucket bucket = gridFSBucket;
329330
BsonDocument rawOptions = arguments.getDocument("options", new BsonDocument());
330331
if (rawOptions.containsKey("chunkSizeBytes")) {
331332
options.chunkSizeBytes(rawOptions.getInt32("chunkSizeBytes").getValue());
332333
}
333334
if (rawOptions.containsKey("metadata")) {
334335
options.metadata(Document.parse(rawOptions.getDocument("metadata").toJson()));
335336
}
337+
if (rawOptions.containsKey("disableMD5")) {
338+
bucket = bucket.withDisableMD5(rawOptions.getBoolean("disableMD5").getValue());
339+
}
340+
final GridFSBucket gridFSUploadBucket = bucket;
336341

337342
objectId = new MongoOperation<ObjectId>() {
338343
@Override
339344
public void execute() {
340-
gridFSBucket.uploadFromStream(filename, toAsyncInputStream(inputStream), options, getCallback());
345+
gridFSUploadBucket.uploadFromStream(filename, toAsyncInputStream(inputStream), options, getCallback());
341346
}
342347
}.get();
343348
} catch (Throwable e) {

0 commit comments

Comments
 (0)