diff --git a/lib/httpx/plugins/compression.rb b/lib/httpx/plugins/compression.rb index e6769048..85a9fe54 100644 --- a/lib/httpx/plugins/compression.rb +++ b/lib/httpx/plugins/compression.rb @@ -15,17 +15,28 @@ module HTTPX end end + module RequestBodyMethods + def initialize(*) + super + return if @body.nil? + @headers.get("content-encoding").each do |encoding| + @body = Encoder.new(@body, Compression.registry(encoding).encoder) + end + @headers["content-length"] = @body.bytesize unless chunked? + end + end + module ResponseBodyMethods def initialize(*) super @_decoders = @headers.get("content-encoding").map do |encoding| - Transcoder.registry(encoding).decoder + Compression.registry(encoding).decoder end @_compressed_length = if @headers.key?("content-length") - @headers["content-length"].to_i - else - Float::INFINITY - end + @headers["content-length"].to_i + else + Float::INFINITY + end end def write(chunk) @@ -49,7 +60,48 @@ module HTTPX buffer end end - + + class Encoder + def initialize(body, deflater) + @body = body.respond_to?(:read) ? body : StringIO.new(body.to_s) + @buffer = StringIO.new("".b, File::RDWR) + @deflater = deflater + end + + def each(&blk) + return enum_for(__method__) unless block_given? + unless @buffer.size.zero? + @buffer.rewind + return @buffer.each(&blk) + end + deflate(&blk) + end + + def bytesize + deflate + @buffer.size + end + + def to_s + deflate + @buffer.rewind + @buffer.read + end + + def close + @buffer.close + @body.close + end + + private + + def deflate(&blk) + return unless @buffer.size.zero? + @body.rewind + @deflater.deflate(@body, @buffer, chunk_size: 16_384, &blk) + end + end + class Decoder extend Forwardable @@ -65,41 +117,6 @@ module HTTPX @inflater.inflate(chunk) end end - - class CompressEncoder - attr_reader :content_type - - def initialize(raw, encoder) - @content_type = raw.content_type - @raw = raw.respond_to?(:read) ? raw : StringIO.new(raw.to_s) - @buffer = StringIO.new("".b, File::RDWR) - @encoder = encoder - end - - def each(&blk) - return enum_for(__method__) unless block_given? - unless @buffer.size.zero? - @buffer.rewind - return @buffer.each(&blk) - end - @encoder.compress(@raw, @buffer, chunk_size: 16_384, &blk) - end - - def to_s - compress - @buffer.rewind - @buffer.read - end - - def bytesize - @encoder.compress(@raw, @buffer, chunk_size: 16_384) - @buffer.size - end - - def close - # @buffer.close - end - end end register_plugin :compression, Compression end diff --git a/lib/httpx/plugins/compression/brotli.rb b/lib/httpx/plugins/compression/brotli.rb index 99bb3d36..efea6f15 100644 --- a/lib/httpx/plugins/compression/brotli.rb +++ b/lib/httpx/plugins/compression/brotli.rb @@ -11,16 +11,13 @@ module HTTPX end def self.configure(*) - Transcoder.register "br", BrotliTranscoder Compression.register "br", self end module Encoder module_function - def compress(raw, buffer, chunk_size: ) - return unless buffer.size.zero? - raw.rewind + def deflate(raw, buffer, chunk_size: ) begin while chunk = raw.read(chunk_size) compressed = ::Brotli.deflate(chunk) @@ -43,16 +40,14 @@ module HTTPX end end - module BrotliTranscoder - module_function - - def encode(payload) - CompressEncoder.new(payload, Encoder) - end - - def decoder - Decoder.new(BrotliWrapper) - end + module_function + + def encoder + Encoder + end + + def decoder + Decoder.new(BrotliWrapper) end end end diff --git a/lib/httpx/plugins/compression/deflate.rb b/lib/httpx/plugins/compression/deflate.rb index 1d869996..ef869274 100644 --- a/lib/httpx/plugins/compression/deflate.rb +++ b/lib/httpx/plugins/compression/deflate.rb @@ -10,45 +10,40 @@ module HTTPX end def self.configure(*) - Transcoder.register "deflate", DeflateTranscoder Compression.register "deflate", self end - module DeflateTranscoder - module Encoder - module_function - - def compress(raw, buffer, chunk_size: ) - return unless buffer.size.zero? - raw.rewind - begin - deflater = Zlib::Deflate.new(Zlib::BEST_COMPRESSION, - Zlib::MAX_WBITS, - Zlib::MAX_MEM_LEVEL, - Zlib::HUFFMAN_ONLY) - while chunk = raw.read(chunk_size) - compressed = deflater.deflate(chunk) - buffer << compressed - yield compressed if block_given? - end - last = deflater.finish - buffer << last - yield last if block_given? - ensure - deflater.close - end - end - end - + module Encoder module_function - def encode(payload) - CompressEncoder.new(payload, Encoder) + def deflate(raw, buffer, chunk_size: ) + begin + deflater = Zlib::Deflate.new(Zlib::BEST_COMPRESSION, + Zlib::MAX_WBITS, + Zlib::MAX_MEM_LEVEL, + Zlib::HUFFMAN_ONLY) + while chunk = raw.read(chunk_size) + compressed = deflater.deflate(chunk) + buffer << compressed + yield compressed if block_given? + end + last = deflater.finish + buffer << last + yield last if block_given? + ensure + deflater.close + end end + end - def decoder - Decoder.new(Zlib::Inflate.new(32 + Zlib::MAX_WBITS)) - end + module_function + + def encoder + Encoder + end + + def decoder + Decoder.new(Zlib::Inflate.new(32 + Zlib::MAX_WBITS)) end end end diff --git a/lib/httpx/plugins/compression/gzip.rb b/lib/httpx/plugins/compression/gzip.rb index 7c4ebf72..49d5b308 100644 --- a/lib/httpx/plugins/compression/gzip.rb +++ b/lib/httpx/plugins/compression/gzip.rb @@ -11,54 +11,49 @@ module HTTPX end def self.configure(*) - Transcoder.register "gzip", GZIPTranscoder Compression.register "gzip", self end - module GZIPTranscoder - class Encoder - def compress(raw, buffer, chunk_size: ) - return unless buffer.size.zero? - raw.rewind - begin - gzip = Zlib::GzipWriter.new(self) + class Encoder + def deflate(raw, buffer, chunk_size: ) + begin + gzip = Zlib::GzipWriter.new(self) - while chunk = raw.read(chunk_size) - gzip.write(chunk) - gzip.flush - compressed = compressed_chunk - buffer << compressed - yield compressed if block_given? - end - ensure - gzip.close + while chunk = raw.read(chunk_size) + gzip.write(chunk) + gzip.flush + compressed = compressed_chunk + buffer << compressed + yield compressed if block_given? end - end - - private - - def write(chunk) - @compressed_chunk = chunk - end - - def compressed_chunk - compressed = @compressed_chunk - compressed ensure - @compressed_chunk = nil + gzip.close end end - - - module_function - - def encode(payload) - CompressEncoder.new(payload, Encoder.new) - end - def decoder - Decoder.new(Zlib::Inflate.new(32 + Zlib::MAX_WBITS)) + private + + def write(chunk) + @compressed_chunk = chunk end + + def compressed_chunk + compressed = @compressed_chunk + compressed + ensure + @compressed_chunk = nil + end + end + + + module_function + + def encoder + Encoder.new + end + + def decoder + Decoder.new(Zlib::Inflate.new(32 + Zlib::MAX_WBITS)) end end end