Răsfoiți Sursa

check if file is optimised before running qpdf

Brian Gough 9 ani în urmă
părinte
comite
7e58bfd752

+ 16 - 1
services/clsi/app/coffee/OutputFileOptimiser.coffee

@@ -11,10 +11,25 @@ module.exports = OutputFileOptimiser =
 		# check output file (src) and see if we can optimise it, storing
 		# the result in the build directory (dst)
 		if src.match(/\/output\.pdf$/)
-			OutputFileOptimiser.optimisePDF src, dst, callback
+			OutputFileOptimiser.checkIfPDFIsOptimised src, (err, isOptimised) ->
+				return callback(null) if err? or isOptimised
+				OutputFileOptimiser.optimisePDF src, dst, callback
 		else
 			callback (null)
 
+	checkIfPDFIsOptimised: (file, callback) ->
+		SIZE = 16*1024 # check the header of the pdf
+		result = new Buffer(SIZE)
+		result.fill(0) # prevent leakage of uninitialised buffer
+		fs.open file, "r", (err, fd) ->
+			return callback(err) if err?
+			fs.read fd, result, 0, SIZE, 0, (errRead, bytesRead, buffer) ->
+				fs.close fd, (errClose) ->
+					return callback(errRead) if errRead?
+					return callback(errClose) if errReadClose?
+					isOptimised = buffer.toString('ascii').indexOf("/Linearized 1") >= 0
+					callback(null, isOptimised)
+
 	optimisePDF: (src, dst, callback = (error) ->) ->
 		tmpOutput = dst + '.opt'
 		args = ["--linearize", src, tmpOutput]

+ 103 - 0
services/clsi/test/unit/coffee/OutputFileOptimiserTests.coffee

@@ -0,0 +1,103 @@
+SandboxedModule = require('sandboxed-module')
+sinon = require('sinon')
+require('chai').should()
+modulePath = require('path').join __dirname, '../../../app/js/OutputFileOptimiser'
+path = require "path"
+expect = require("chai").expect
+EventEmitter = require("events").EventEmitter
+
+describe "OutputFileOptimiser", ->
+	beforeEach ->
+		@OutputFileOptimiser = SandboxedModule.require modulePath, requires:
+			"fs": @fs = {}
+			"path": @Path = {}
+			"child_process": spawn: @spawn = sinon.stub()
+			"logger-sharelatex": { log: sinon.stub(), warn: sinon.stub() }
+			"./Metrics" : {}
+		@directory = "/test/dir"
+		@callback = sinon.stub()
+
+	describe "optimiseFile", ->
+		beforeEach ->
+			@src = "./output.pdf"
+			@dst = "./output.pdf"
+
+		describe "when the file is not a pdf file", ->
+			beforeEach (done)->
+				@src = "./output.log"
+				@OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, false)
+				@OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null)
+				@OutputFileOptimiser.optimiseFile @src, @dst, done
+
+			it "should not check if the file is optimised", ->
+				@OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(@src).should.equal false
+
+			it "should not optimise the file", ->
+				@OutputFileOptimiser.optimisePDF.calledWith(@src, @dst).should.equal false
+
+		describe "when the pdf file is not optimised", ->
+			beforeEach (done) ->
+				@OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, false)
+				@OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null)
+				@OutputFileOptimiser.optimiseFile @src, @dst, done
+
+			it "should check if the pdf is optimised", ->
+				@OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(@src).should.equal true
+
+			it "should optimise the pdf", ->
+				@OutputFileOptimiser.optimisePDF.calledWith(@src, @dst).should.equal true
+
+		describe "when the pdf file is optimised", ->
+			beforeEach (done) ->
+				@OutputFileOptimiser.checkIfPDFIsOptimised = sinon.stub().callsArgWith(1, null, true)
+				@OutputFileOptimiser.optimisePDF = sinon.stub().callsArgWith(2, null)
+				@OutputFileOptimiser.optimiseFile @src, @dst, done
+
+			it "should check if the pdf is optimised", ->
+				@OutputFileOptimiser.checkIfPDFIsOptimised.calledWith(@src).should.equal true
+
+			it "should not optimise the pdf", ->
+				@OutputFileOptimiser.optimisePDF.calledWith(@src, @dst).should.equal false
+
+	describe "checkIfPDFISOptimised", ->
+		beforeEach () ->
+			@callback = sinon.stub()
+			@fd = 1234
+			@fs.open = sinon.stub().yields(null, @fd)
+			@fs.read = sinon.stub().withArgs(@fd).yields(null, 100, new Buffer("hello /Linearized 1"))
+			@fs.close = sinon.stub().withArgs(@fd).yields(null)
+			@OutputFileOptimiser.checkIfPDFIsOptimised @src, @callback
+
+		describe "for a linearised file", ->
+			beforeEach () ->
+				@fs.read = sinon.stub().withArgs(@fd).yields(null, 100, new Buffer("hello /Linearized 1"))
+				@OutputFileOptimiser.checkIfPDFIsOptimised @src, @callback
+
+			it "should open the file", ->
+				@fs.open.calledWith(@src, "r").should.equal true
+
+			it "should read the header", ->
+				@fs.read.calledWith(@fd).should.equal true
+
+			it "should close the file", ->
+				@fs.close.calledWith(@fd).should.equal true
+
+			it "should call the callback with a true result", ->
+				@callback.calledWith(null, true).should.equal true
+
+		describe "for an unlinearised file", ->
+			beforeEach () ->
+				@fs.read = sinon.stub().withArgs(@fd).yields(null, 100, new Buffer("hello not linearized 1"))
+				@OutputFileOptimiser.checkIfPDFIsOptimised @src, @callback
+
+			it "should open the file", ->
+				@fs.open.calledWith(@src, "r").should.equal true
+
+			it "should read the header", ->
+				@fs.read.calledWith(@fd).should.equal true
+
+			it "should close the file", ->
+				@fs.close.calledWith(@fd).should.equal true
+
+			it "should call the callback with a false result", ->
+				@callback.calledWith(null, false).should.equal true