lib/httpx/plugins/compression.rb in httpx-0.9.0 vs lib/httpx/plugins/compression.rb in httpx-0.10.0

- old
+ new

@@ -44,20 +44,17 @@ module RequestBodyMethods def initialize(*, options) super return if @body.nil? - if (threshold = options.compression_threshold_size) - unless unbounded_body? - return if @body.bytesize < threshold - end - end + threshold = options.compression_threshold_size + return if threshold && !unbounded_body? && @body.bytesize < threshold @headers.get("content-encoding").each do |encoding| next if encoding == "identity" - @body = Encoder.new(@body, Compression.registry(encoding).encoder) + @body = Encoder.new(@body, Compression.registry(encoding).deflater) end @headers["content-length"] = @body.bytesize unless chunked? end end @@ -69,114 +66,82 @@ super return unless @headers.key?("content-encoding") - @_decoders = @headers.get("content-encoding").map do |encoding| + # remove encodings that we are able to decode + @headers["content-encoding"] = @headers.get("content-encoding") - @encodings + + compressed_length = if @headers.key?("content-length") + @headers["content-length"].to_i + else + Float::INFINITY + end + + @_inflaters = @headers.get("content-encoding").map do |encoding| next if encoding == "identity" - decoder = Compression.registry(encoding).decoder + inflater = Compression.registry(encoding).inflater(compressed_length) # do not uncompress if there is no decoder available. In fact, we can't reliably # continue decompressing beyond that, so ignore. - break unless decoder + break unless inflater @encodings << encoding - decoder + inflater end.compact - # remove encodings that we are able to decode - @headers["content-encoding"] = @headers.get("content-encoding") - @encodings - - @_compressed_length = if @headers.key?("content-length") - @headers["content-length"].to_i - else - Float::INFINITY - end + # this can happen if the only declared encoding is "identity" + remove_instance_variable(:@_inflaters) if @_inflaters.empty? end def write(chunk) - return super unless defined?(@_compressed_length) + return super unless defined?(@_inflaters) - @_compressed_length -= chunk.bytesize chunk = decompress(chunk) super(chunk) end - def close - super - - return unless defined?(@_decoders) - - @_decoders.each(&:close) - end - private def decompress(buffer) - @_decoders.reverse_each do |decoder| - buffer = decoder.decode(buffer) - buffer << decoder.finish if @_compressed_length <= 0 + @_inflaters.reverse_each do |inflater| + buffer = inflater.inflate(buffer) end buffer end end class Encoder + attr_reader :content_type + def initialize(body, deflater) + @content_type = body.content_type @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) + return deflate(&blk) if @buffer.size.zero? + + @buffer.rewind + @buffer.each(&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 - - def_delegator :@inflater, :finish - - def_delegator :@inflater, :close - - def initialize(inflater) - @inflater = inflater - end - - def decode(chunk) - @inflater.inflate(chunk) end end end register_plugin :compression, Compression end