Compress to single data buffer instead of chunked stream
This commit is contained in:
		@@ -11,7 +11,7 @@ let package = Package(
 | 
				
			|||||||
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
 | 
					        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 🤐 Unzip archives
 | 
					        // 🤐 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: [
 | 
					    targets: [
 | 
				
			||||||
        .target(name: "GzipMiddleware", dependencies: ["Vapor", "ZIPFoundation"]),
 | 
					        .target(name: "GzipMiddleware", dependencies: ["Vapor", "ZIPFoundation"]),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,15 @@ import Vapor
 | 
				
			|||||||
import Foundation
 | 
					import Foundation
 | 
				
			||||||
import ZIPFoundation
 | 
					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:
 | 
					/// Server Gzip middlere:
 | 
				
			||||||
/// 1. checks if the "Accept-Encoding" header contains "gzip"
 | 
					/// 1. checks if the "Accept-Encoding" header contains "gzip"
 | 
				
			||||||
/// 2. if so, compresses the body and sets the response header "Content-Encoding" to "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
 | 
					            var headers = response.http.headers
 | 
				
			||||||
            headers.replaceOrAdd(name: .contentEncoding, value: "gzip")
 | 
					            headers.replaceOrAdd(name: .contentEncoding, value: "gzip")
 | 
				
			||||||
            return response.http.body.consumeData(on: request).map { data in
 | 
					            return response.http.body.consumeData(on: request).map { data in
 | 
				
			||||||
                let stream  = HTTPChunkedStream(on: request)
 | 
					                var buffer  = Data()
 | 
				
			||||||
                let bufSize = 4096
 | 
					 | 
				
			||||||
                var buffer  = ByteBufferAllocator().buffer(capacity: bufSize)
 | 
					 | 
				
			||||||
                let header  : [UInt8] = [0x1f, 0x8b, 0x08, 0x00]
 | 
					                let header  : [UInt8] = [0x1f, 0x8b, 0x08, 0x00]
 | 
				
			||||||
                let header2 : [UInt8] = [0x00, 0x03]
 | 
					                let header2 : [UInt8] = [0x00, 0x03]
 | 
				
			||||||
                buffer.write(bytes: header)
 | 
					                buffer.append(contentsOf: header)
 | 
				
			||||||
                buffer.write(integer: UInt32(Date().timeIntervalSince1970), endianness: .little)
 | 
					                buffer.appendLittleEndian(UInt32(Date().timeIntervalSince1970))
 | 
				
			||||||
                buffer.write(bytes: header2)
 | 
					                buffer.append(contentsOf: header2)
 | 
				
			||||||
                var write   = stream.write(.chunk(buffer))
 | 
					                let crc32   = try Data.compress(size: data.count, bufferSize: 4096,
 | 
				
			||||||
                let crc32   = try Data.compress(size: data.count, bufferSize: bufSize,
 | 
					 | 
				
			||||||
                    provider: {(offset, readSize) -> Data in
 | 
					                    provider: {(offset, readSize) -> Data in
 | 
				
			||||||
                        return data.subdata(in: offset..<offset+readSize)
 | 
					                        return data.subdata(in: offset..<offset+readSize)
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    consumer: { data -> Void in
 | 
					                    consumer: { data -> Void in
 | 
				
			||||||
                        write = write.flatMap {
 | 
					                        buffer.append(data)
 | 
				
			||||||
                            buffer.clear()
 | 
					 | 
				
			||||||
                            buffer.write(bytes: data)
 | 
					 | 
				
			||||||
                            return stream.write(.chunk(buffer))
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                write.always {
 | 
					                buffer.appendLittleEndian(crc32)
 | 
				
			||||||
                    buffer.clear()
 | 
					                buffer.appendLittleEndian(UInt32(data.count))
 | 
				
			||||||
                    buffer.write(integer: crc32, endianness: .little)
 | 
					                let httpResponse = HTTPResponse(status: response.http.status, headers: headers, body: buffer)
 | 
				
			||||||
                    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)
 | 
					 | 
				
			||||||
                return request.response(http: httpResponse)
 | 
					                return request.response(http: httpResponse)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user