From 3a6a02deb51dfe415391185ad6f0a9e6a1c43695 Mon Sep 17 00:00:00 2001 From: Matthias Neeracher Date: Sun, 7 Oct 2018 01:32:19 +0200 Subject: [PATCH] Compress to single data buffer instead of chunked stream --- Package.swift | 2 +- Sources/GzipMiddleware/GzipMiddleware.swift | 40 ++++++++++----------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/Package.swift b/Package.swift index 3592bc0..9974960 100644 --- a/Package.swift +++ b/Package.swift @@ -11,7 +11,7 @@ let package = Package( .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"), // ๐Ÿค Unzip archives - .package(url: "https://github.com/microtherion/ZIPFoundation.git", .upToNextMajor(from: "0.9.7-ยต")) + .package(url: "https://github.com/microtherion/ZIPFoundation.git", .upToNextMajor(from: "0.9.8-ยต")) ], targets: [ .target(name: "GzipMiddleware", dependencies: ["Vapor", "ZIPFoundation"]), diff --git a/Sources/GzipMiddleware/GzipMiddleware.swift b/Sources/GzipMiddleware/GzipMiddleware.swift index e7d5550..f0c9f96 100644 --- a/Sources/GzipMiddleware/GzipMiddleware.swift +++ b/Sources/GzipMiddleware/GzipMiddleware.swift @@ -3,6 +3,15 @@ import Vapor import Foundation import ZIPFoundation +private extension Data { + mutating func appendLittleEndian(_ word: UInt32) { + self.append(UInt8(word & 0xFF)) + self.append(UInt8((word >> 8) & 0xFF)) + self.append(UInt8((word >> 16) & 0xFF)) + self.append(UInt8((word >> 24) & 0xFF)) + } +} + /// Server Gzip middlere: /// 1. checks if the "Accept-Encoding" header contains "gzip" /// 2. if so, compresses the body and sets the response header "Content-Encoding" to "gzip", @@ -30,35 +39,22 @@ public struct GzipServerMiddleware: Middleware, ServiceType { var headers = response.http.headers headers.replaceOrAdd(name: .contentEncoding, value: "gzip") return response.http.body.consumeData(on: request).map { data in - let stream = HTTPChunkedStream(on: request) - let bufSize = 4096 - var buffer = ByteBufferAllocator().buffer(capacity: bufSize) + var buffer = Data() let header : [UInt8] = [0x1f, 0x8b, 0x08, 0x00] let header2 : [UInt8] = [0x00, 0x03] - buffer.write(bytes: header) - buffer.write(integer: UInt32(Date().timeIntervalSince1970), endianness: .little) - buffer.write(bytes: header2) - var write = stream.write(.chunk(buffer)) - let crc32 = try Data.compress(size: data.count, bufferSize: bufSize, + buffer.append(contentsOf: header) + buffer.appendLittleEndian(UInt32(Date().timeIntervalSince1970)) + buffer.append(contentsOf: header2) + let crc32 = try Data.compress(size: data.count, bufferSize: 4096, provider: {(offset, readSize) -> Data in return data.subdata(in: offset.. Void in - write = write.flatMap { - buffer.clear() - buffer.write(bytes: data) - return stream.write(.chunk(buffer)) - } + buffer.append(data) }) - write.always { - buffer.clear() - buffer.write(integer: crc32, endianness: .little) - buffer.write(integer: UInt32(data.count), endianness: .little) - stream.write(.chunk(buffer)).always { - _ = stream.write(.end) - } - } - let httpResponse = HTTPResponse(status: response.http.status, headers: headers, body: stream) + buffer.appendLittleEndian(crc32) + buffer.appendLittleEndian(UInt32(data.count)) + let httpResponse = HTTPResponse(status: response.http.status, headers: headers, body: buffer) return request.response(http: httpResponse) } }