Uploading an empty zipfile throws specific error (#1909)

Added a counter for the total files extracted from a zip. If no files are extracted a specific error is thrown.

GitOrigin-RevId: 391bb669500c86e2e7fecebd90e2201248a8afd3
This commit is contained in:
Miguel Serrano 2019-07-02 12:48:57 +02:00 committed by sharelatex
parent 67c0a3c2a4
commit 27985458ea
5 changed files with 137 additions and 6 deletions

View file

@ -61,7 +61,7 @@ const ArchiveManager = {
{ source, totalSizeInBytes }, { source, totalSizeInBytes },
'error getting bytes of zip' 'error getting bytes of zip'
) )
return callback(new Error('error getting bytes of zip')) return callback(new Errors.InvalidError('invalid_zip_file'))
} }
const isTooLarge = totalSizeInBytes > ONE_MEG * 300 const isTooLarge = totalSizeInBytes > ONE_MEG * 300
return callback(null, isTooLarge) return callback(null, isTooLarge)
@ -139,6 +139,8 @@ const ArchiveManager = {
zipfile.on('error', callback) zipfile.on('error', callback)
// read all the entries // read all the entries
zipfile.readEntry() zipfile.readEntry()
let entryFileCount = 0
zipfile.on('entry', function(entry) { zipfile.on('entry', function(entry) {
logger.log( logger.log(
{ source, fileName: entry.fileName }, { source, fileName: entry.fileName },
@ -168,6 +170,7 @@ const ArchiveManager = {
zipfile.close() // bail out, stop reading file entries zipfile.close() // bail out, stop reading file entries
return callback(err) return callback(err)
} else { } else {
entryFileCount++
return zipfile.readEntry() return zipfile.readEntry()
} }
} }
@ -179,7 +182,13 @@ const ArchiveManager = {
}) })
}) })
// no more entries to read // no more entries to read
return zipfile.on('end', callback) return zipfile.on('end', () => {
if (entryFileCount > 0) {
callback()
} else {
callback(new Errors.InvalidError('empty_zip_file'))
}
})
}) })
}, },

View file

@ -342,6 +342,66 @@ describe('ProjectStructureChanges', function() {
}) })
}) })
describe('uploading an empty zipfile', function() {
let zipFile = null
before(function(done) {
MockDocUpdaterApi.clearProjectStructureUpdates()
zipFile = fs.createReadStream(
Path.resolve(__dirname + '/../files/test_project_empty.zip')
)
done()
})
it('should fail with 422 error', function(done) {
this.owner.request.post(
{
uri: 'project/new/upload',
formData: {
qqfile: zipFile
}
},
(error, res) => {
if (error != null) {
throw error
}
expect(res.statusCode).to.equal(422)
done()
}
)
})
})
describe('uploading a zipfile containing only empty directories', function() {
let zipFile = null
before(function(done) {
MockDocUpdaterApi.clearProjectStructureUpdates()
zipFile = fs.createReadStream(
Path.resolve(__dirname + '/../files/test_project_with_empty_folder.zip')
)
done()
})
it('should fail with 422 error', function(done) {
this.owner.request.post(
{
uri: 'project/new/upload',
formData: {
qqfile: zipFile
}
},
(error, res) => {
if (error != null) {
throw error
}
expect(res.statusCode).to.equal(422)
done()
}
)
})
})
describe('uploading a project with a shared top-level folder', function() { describe('uploading a project with a shared top-level folder', function() {
before(function(done) { before(function(done) {
MockDocUpdaterApi.clearProjectStructureUpdates() MockDocUpdaterApi.clearProjectStructureUpdates()

View file

@ -70,11 +70,23 @@ describe('ArchiveManager', function() {
describe('successfully', function() { describe('successfully', function() {
beforeEach(function(done) { beforeEach(function(done) {
this.readStream = new events.EventEmitter()
this.readStream.pipe = sinon.stub()
this.zipfile.openReadStream = sinon
.stub()
.callsArgWith(1, null, this.readStream)
this.writeStream = new events.EventEmitter()
this.fs.createWriteStream = sinon.stub().returns(this.writeStream)
this.fse.ensureDir = sinon.stub().callsArg(1)
this.ArchiveManager.extractZipArchive( this.ArchiveManager.extractZipArchive(
this.source, this.source,
this.destination, this.destination,
done done
) )
// entry contains a single file
this.zipfile.emit('entry', { fileName: 'testfile.txt' })
this.readStream.emit('end')
return this.zipfile.emit('end') return this.zipfile.emit('end')
}) })
@ -93,6 +105,60 @@ describe('ArchiveManager', function() {
}) })
}) })
describe('with a zipfile containing an empty directory', function() {
beforeEach(function(done) {
this.readStream = new events.EventEmitter()
this.readStream.pipe = sinon.stub()
this.zipfile.openReadStream = sinon
.stub()
.callsArgWith(1, null, this.readStream)
this.writeStream = new events.EventEmitter()
this.fs.createWriteStream = sinon.stub().returns(this.writeStream)
this.fse.ensureDir = sinon.stub().callsArg(1)
this.ArchiveManager.extractZipArchive(
this.source,
this.destination,
error => {
this.callback(error)
done()
}
)
// entry contains a single, empty directory
this.zipfile.emit('entry', { fileName: 'testdir/' })
this.readStream.emit('end')
return this.zipfile.emit('end')
})
it('should return the callback with an error', function() {
return sinon.assert.calledWithExactly(
this.callback,
new Errors.InvalidError('empty_zip_file')
)
})
})
describe('with an empty zipfile', function() {
beforeEach(function(done) {
this.ArchiveManager.extractZipArchive(
this.source,
this.destination,
error => {
this.callback(error)
return done()
}
)
return this.zipfile.emit('end')
})
it('should return the callback with an error', function() {
return sinon.assert.calledWithExactly(
this.callback,
new Errors.InvalidError('empty_zip_file')
)
})
})
describe('with an error in the zip file header', function() { describe('with an error in the zip file header', function() {
beforeEach(function(done) { beforeEach(function(done) {
this.yauzl.open = sinon this.yauzl.open = sinon
@ -286,10 +352,6 @@ describe('ArchiveManager', function() {
it('should not try to read the entry', function() { it('should not try to read the entry', function() {
return this.zipfile.openReadStream.called.should.equal(false) return this.zipfile.openReadStream.called.should.equal(false)
}) })
it('should not log out a warning', function() {
return this.logger.warn.called.should.equal(false)
})
}) })
describe('with an error opening the file read stream', function() { describe('with an error opening the file read stream', function() {