Henry Oswald 10 лет назад
Родитель
Сommit
6664b67fba

+ 40 - 21
services/web/app/coffee/Features/Uploads/ArchiveManager.coffee

@@ -4,38 +4,57 @@ metrics = require "../../infrastructure/Metrics"
 fs      = require "fs"
 fs      = require "fs"
 Path    = require "path"
 Path    = require "path"
 
 
+ONE_MEG = 1024 * 1024
+
 module.exports = ArchiveManager =
 module.exports = ArchiveManager =
 	extractZipArchive: (source, destination, _callback = (err) ->) ->
 	extractZipArchive: (source, destination, _callback = (err) ->) ->
 		callback = (args...) ->
 		callback = (args...) ->
 			_callback(args...)
 			_callback(args...)
 			_callback = () ->
 			_callback = () ->
 
 
-		timer = new metrics.Timer("unzipDirectory")
-		logger.log source: source, destination: destination, "unzipping file"
+		child.exec "unzip -l #{source} | tail -n 1", (err, result)->
+			if err?
+				logger.err err:err, "error checking size of zip file"
+				return callback(err)
+
+			totalSizeInBytes = result.trim()?.split(" ")?[0]
+			
+			if !totalSizeInBytes?
+				logger.err source:source, "error getting bytes of zip"
+				return callback(new Error("something went wrong"))
+
+			if totalSizeInBytes > ONE_MEG * 300
+				logger.log source:source, totalSizeInBytes:totalSizeInBytes, "zip file too large"
+				return callback(new Error("zip_too_large"))
+					
+
+
+			timer = new metrics.Timer("unzipDirectory")
+			logger.log source: source, destination: destination, "unzipping file"
 
 
-		unzip = child.spawn("unzip", [source, "-d", destination])
+			unzip = child.spawn("unzip", [source, "-d", destination])
 
 
-		# don't remove this line, some zips need
-		# us to listen on this for some unknow reason
-		unzip.stdout.on "data", (d)->
+			# don't remove this line, some zips need
+			# us to listen on this for some unknow reason
+			unzip.stdout.on "data", (d)->
 
 
-		error = null
-		unzip.stderr.on "data", (chunk) ->
-			error ||= ""
-			error += chunk
+			error = null
+			unzip.stderr.on "data", (chunk) ->
+				error ||= ""
+				error += chunk
 
 
-		unzip.on "error", (err) ->
-			logger.error {err, source, destination}, "unzip failed"
-			if err.code == "ENOENT"
-				logger.error "unzip command not found. Please check the unzip command is installed"
-			callback(err)
+			unzip.on "error", (err) ->
+				logger.error {err, source, destination}, "unzip failed"
+				if err.code == "ENOENT"
+					logger.error "unzip command not found. Please check the unzip command is installed"
+				callback(err)
 
 
-		unzip.on "exit", () ->
-			timer.done()
-			if error?
-				error = new Error(error)
-				logger.error err:error, source: source, destination: destination, "error unzipping file"
-			callback(error)
+			unzip.on "exit", () ->
+				timer.done()
+				if error?
+					error = new Error(error)
+					logger.error err:error, source: source, destination: destination, "error unzipping file"
+				callback(error)
 	
 	
 	findTopLevelDirectory: (directory, callback = (error, topLevelDir) ->) ->
 	findTopLevelDirectory: (directory, callback = (error, topLevelDir) ->) ->
 		fs.readdir directory, (error, files) ->
 		fs.readdir directory, (error, files) ->

+ 14 - 0
services/web/test/UnitTests/coffee/Uploads/ArchiveManagerTests.coffee

@@ -15,6 +15,7 @@ describe "ArchiveManager", ->
 		@process.stderr = new events.EventEmitter
 		@process.stderr = new events.EventEmitter
 		@child =
 		@child =
 			spawn: sinon.stub().returns(@process)
 			spawn: sinon.stub().returns(@process)
+			exec: sinon.stub().callsArgWith(1, null, "   109042                   2 files")
 		@metrics =
 		@metrics =
 			Timer: class Timer
 			Timer: class Timer
 				done: sinon.stub()
 				done: sinon.stub()
@@ -58,6 +59,19 @@ describe "ArchiveManager", ->
 			it "should log out the error", ->
 			it "should log out the error", ->
 				@logger.error.called.should.equal true
 				@logger.error.called.should.equal true
 
 
+		describe "with a zip that is too large", ->
+			beforeEach (done) ->
+				@child.exec = sinon.stub().callsArgWith(1, null, "   10000000000009042                   2 files")
+				@ArchiveManager.extractZipArchive @source, @destination, (error) =>
+					@callback(error)
+					done()
+
+			it "should return the callback with an error", ->
+				@callback.calledWithExactly(new Error("zip_too_large")).should.equal true
+
+			it "should not call spawn", ->
+				@child.spawn.called.should.equal false
+
 		describe "with an error on the process", ->
 		describe "with an error on the process", ->
 			beforeEach (done) ->
 			beforeEach (done) ->
 				@ArchiveManager.extractZipArchive @source, @destination, (error) =>
 				@ArchiveManager.extractZipArchive @source, @destination, (error) =>