mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-08-10 00:01:27 -04:00
added transcoders for content-encoding; added logic in request body to iteratively apply them; there's still a problem: how to close all buffers in the most logical way
This commit is contained in:
parent
2f67f0ad15
commit
ca96f6dfe1
@ -1,57 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module HTTPX
|
||||
module Transcoder
|
||||
module GZIP
|
||||
module_function
|
||||
def encode(payload)
|
||||
|
||||
end
|
||||
|
||||
def decode(io)
|
||||
Zlib::GzipReader.new(io, window_size: 32 + Zlib::MAX_WBITS)
|
||||
end
|
||||
end
|
||||
|
||||
module Deflate
|
||||
module_function
|
||||
|
||||
class Decoder
|
||||
def initialize(io)
|
||||
@io = io
|
||||
@inflater = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
|
||||
@buffer = StringIO.new
|
||||
end
|
||||
|
||||
def rewind
|
||||
@buffer.rewind
|
||||
end
|
||||
|
||||
def read(*args)
|
||||
return @buffer.read(*args) if @io.eof?
|
||||
chunk = @io.read(*args)
|
||||
inflated_chunk = @inflater.inflate(chunk)
|
||||
inflated_chunk << @inflater.finish if @io.eof?
|
||||
@buffer << chunk
|
||||
inflated_chunk
|
||||
end
|
||||
|
||||
def close
|
||||
@io.close
|
||||
@io.unlink if @io.respond_to?(:unlink)
|
||||
@inflater.close
|
||||
end
|
||||
end
|
||||
|
||||
def decode(io)
|
||||
Decoder.new(io)
|
||||
end
|
||||
end
|
||||
|
||||
register "gzip", GZIP
|
||||
register "deflate", Deflate
|
||||
end
|
||||
|
||||
module Plugins
|
||||
module Compression
|
||||
ACCEPT_ENCODING = %w[gzip deflate].freeze
|
||||
@ -94,7 +43,154 @@ module HTTPX
|
||||
buffer
|
||||
end
|
||||
end
|
||||
|
||||
class CompressEncoder
|
||||
attr_reader :content_type
|
||||
|
||||
def initialize(raw)
|
||||
@content_type = raw.content_type
|
||||
@raw = raw.respond_to?(:read) ? raw : StringIO.new(raw.to_s)
|
||||
@buffer = StringIO.new("".b, File::RDWR)
|
||||
end
|
||||
|
||||
def each(&blk)
|
||||
return enum_for(__method__) unless block_given?
|
||||
unless @buffer.size.zero?
|
||||
@buffer.rewind
|
||||
return @buffer.each(&blk)
|
||||
end
|
||||
compress(&blk)
|
||||
end
|
||||
|
||||
def to_s
|
||||
compress
|
||||
@buffer.rewind
|
||||
@buffer.read
|
||||
end
|
||||
|
||||
def bytesize
|
||||
compress
|
||||
@buffer.size
|
||||
end
|
||||
|
||||
def close
|
||||
# @buffer.close
|
||||
end
|
||||
end
|
||||
|
||||
module GZIPTranscoder
|
||||
class Encoder < CompressEncoder
|
||||
def write(chunk)
|
||||
@compressed_chunk = chunk
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compressed_chunk
|
||||
compressed = @compressed_chunk
|
||||
compressed
|
||||
ensure
|
||||
@compressed_chunk = nil
|
||||
end
|
||||
|
||||
def compress
|
||||
return unless @buffer.size.zero?
|
||||
@raw.rewind
|
||||
begin
|
||||
gzip = Zlib::GzipWriter.new(self)
|
||||
|
||||
while chunk = @raw.read(16_384)
|
||||
gzip.write(chunk)
|
||||
gzip.flush
|
||||
compressed = compressed_chunk
|
||||
@buffer << compressed
|
||||
yield compressed if block_given?
|
||||
end
|
||||
ensure
|
||||
gzip.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
def encode(payload)
|
||||
Encoder.new(payload)
|
||||
end
|
||||
|
||||
def decode(io)
|
||||
Zlib::GzipReader.new(io, window_size: 32 + Zlib::MAX_WBITS)
|
||||
end
|
||||
end
|
||||
|
||||
module DeflateTranscoder
|
||||
class Encoder < CompressEncoder
|
||||
private
|
||||
|
||||
def compress
|
||||
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(16_384)
|
||||
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_function
|
||||
|
||||
class Decoder
|
||||
def initialize(io)
|
||||
@io = io
|
||||
@inflater = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
|
||||
@buffer = StringIO.new
|
||||
end
|
||||
|
||||
def rewind
|
||||
@buffer.rewind
|
||||
end
|
||||
|
||||
def read(*args)
|
||||
return @buffer.read(*args) if @io.eof?
|
||||
chunk = @io.read(*args)
|
||||
inflated_chunk = @inflater.inflate(chunk)
|
||||
inflated_chunk << @inflater.finish if @io.eof?
|
||||
@buffer << chunk
|
||||
inflated_chunk
|
||||
end
|
||||
|
||||
def close
|
||||
@io.close
|
||||
@io.unlink if @io.respond_to?(:unlink)
|
||||
@inflater.close
|
||||
end
|
||||
end
|
||||
|
||||
def encode(payload)
|
||||
Encoder.new(payload)
|
||||
end
|
||||
|
||||
def decode(io)
|
||||
Decoder.new(io)
|
||||
end
|
||||
end
|
||||
Transcoder.register "gzip", GZIPTranscoder
|
||||
Transcoder.register "deflate", DeflateTranscoder
|
||||
end
|
||||
register_plugin :compression, Compression
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
@ -102,6 +102,9 @@ module HTTPX
|
||||
Transcoder.registry("json").encode(options.json)
|
||||
end
|
||||
return if @body.nil?
|
||||
@headers.get("content-encoding").each do |encoding|
|
||||
@body = Transcoder.registry(encoding).encode(@body)
|
||||
end
|
||||
@headers["content-type"] ||= @body.content_type
|
||||
@headers["content-length"] ||= @body.bytesize unless chunked?
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user