Class: HTTPX::Response::Body
- Inherits:
-
Object
- Object
- HTTPX::Response::Body
- Includes:
- _Reader, _ToS, _ToStr
- Defined in:
- lib/httpx/response/body.rb,
sig/response/body.rbs
Overview
Implementation of the HTTP Response body as a buffer which implements the IO writer protocol (for buffering the response payload), the IO reader protocol (for consuming the response payload), and can be iterated over (via #each, which yields the payload in chunks).
Instance Attribute Summary collapse
-
#buffer ⇒ Response::Buffer?
readonly
Returns the value of attribute buffer.
-
#encoding ⇒ Encoding
readonly
the payload encoding (i.e. "utf-8", "ASCII-8BIT").
-
#encodings ⇒ Array[String]
readonly
Array of encodings contained in the response "content-encoding" header.
Class Method Summary collapse
-
.initialize_inflater_by_encoding(encoding, response, **kwargs) ⇒ Object & Transcoder::_Inflater
:nodoc:.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#bytesize ⇒ Integer
size of the decoded response payload.
-
#close ⇒ void
closes/cleans the buffer, resets everything.
- #closed? ⇒ Boolean
-
#copy_to(dest) ⇒ void
copies the payload to
dest. -
#decode_chunk(chunk) ⇒ String
passes the
chunkthrough all inflaters to decode it. -
#each {|arg0| ... } ⇒ Object
yields the payload in chunks.
-
#empty? ⇒ Boolean
whether the payload is empty.
-
#filename ⇒ String?
returns the declared filename in the "contennt-disposition" header, when present.
-
#initialize(response, options) ⇒ Body
constructor
initialized with the corresponding HTTPX::Response
responseand HTTPX::Optionsoptions. - #initialize_dup(other) ⇒ Object
-
#initialize_inflaters ⇒ void
prepares inflaters for the advertised encodings in "content-encoding" header.
-
#inspect ⇒ Object
simplecov:disable.
-
#read(*args) ⇒ Object
reads a chunk from the payload (implementation of the IO reader protocol).
-
#rewind ⇒ void
rewinds the response payload buffer.
-
#to_s ⇒ Object
(also: #to_str)
returns the full response payload as a string.
-
#transition(nextstate) ⇒ void
tries transitioning the body STM to the
nextstate. -
#write(chunk) ⇒ Integer?
write the response payload
chunkinto the buffer.
Constructor Details
#initialize(response, options) ⇒ Body
initialized with the corresponding HTTPX::Response response and HTTPX::Options options.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/httpx/response/body.rb', line 18 def initialize(response, ) @response = response @headers = response.headers @options = @window_size = .window_size @max_response_body_size = .max_response_body_size @encodings = [] @length = 0 @buffer = @reader = nil @state = :idle # initialize response encoding @encoding = if (enc = response.content_type.charset) begin Encoding.find(enc) rescue ArgumentError Encoding::BINARY end else Encoding::BINARY end initialize_inflaters end |
Instance Attribute Details
#buffer ⇒ Response::Buffer? (readonly)
Returns the value of attribute buffer.
14 15 16 |
# File 'lib/httpx/response/body.rb', line 14 def buffer @buffer end |
#encoding ⇒ Encoding (readonly)
the payload encoding (i.e. "utf-8", "ASCII-8BIT")
9 10 11 |
# File 'lib/httpx/response/body.rb', line 9 def encoding @encoding end |
#encodings ⇒ Array[String] (readonly)
Array of encodings contained in the response "content-encoding" header.
12 13 14 |
# File 'lib/httpx/response/body.rb', line 12 def encodings @encodings end |
Class Method Details
.initialize_inflater_by_encoding(encoding, response, **kwargs) ⇒ Object & Transcoder::_Inflater
:nodoc:
236 237 238 239 240 241 242 243 |
# File 'lib/httpx/response/body.rb', line 236 def initialize_inflater_by_encoding(encoding, response, **kwargs) # :nodoc: case encoding when "gzip" Transcoder::GZIP.decode(response, **kwargs) when "deflate" Transcoder::Deflate.decode(response, **kwargs) end end |
Instance Method Details
#==(other) ⇒ Object
155 156 157 158 159 160 161 162 |
# File 'lib/httpx/response/body.rb', line 155 def ==(other) super || case other when Response::Body @buffer == other.buffer else @buffer = other end end |
#bytesize ⇒ Integer
size of the decoded response payload. May differ from "content-length" header if response was encoded over-the-wire.
85 86 87 |
# File 'lib/httpx/response/body.rb', line 85 def bytesize @length end |
#close ⇒ void
This method returns an undefined value.
closes/cleans the buffer, resets everything
146 147 148 149 150 151 152 153 |
# File 'lib/httpx/response/body.rb', line 146 def close if @buffer @buffer.close @buffer = nil end @length = 0 transition(:closed) end |
#closed? ⇒ Boolean
49 50 51 |
# File 'lib/httpx/response/body.rb', line 49 def closed? @state == :closed end |
#copy_to(dest) ⇒ void
This method returns an undefined value.
copies the payload to dest.
body.copy_to("path/to/file")
body.copy_to(Pathname.new("path/to/file"))
body.copy_to(File.new("path/to/file"))
131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/httpx/response/body.rb', line 131 def copy_to(dest) return unless @buffer rewind if dest.respond_to?(:path) && @buffer.respond_to?(:path) FileUtils.mv(@buffer.path, dest.path) else IO.copy_stream(@buffer, dest) end ensure close end |
#decode_chunk(chunk) ⇒ String
passes the chunk through all inflaters to decode it.
207 208 209 210 211 212 213 214 215 |
# File 'lib/httpx/response/body.rb', line 207 def decode_chunk(chunk) @inflaters.reverse_each do |inflater| chunk = inflater.call(chunk) end if @inflaters @length += chunk.bytesize chunk end |
#each ⇒ void #each ⇒ Enumerable[String]
yields the payload in chunks.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/httpx/response/body.rb', line 90 def each return enum_for(__method__) unless block_given? begin if @buffer rewind while (chunk = @buffer.read(@window_size)) yield(chunk.force_encoding(@encoding)) end end ensure close end end |
#empty? ⇒ Boolean
whether the payload is empty.
122 123 124 |
# File 'lib/httpx/response/body.rb', line 122 def empty? @length.zero? end |
#filename ⇒ String?
returns the declared filename in the "contennt-disposition" header, when present.
106 107 108 109 110 |
# File 'lib/httpx/response/body.rb', line 106 def filename return unless @headers.key?("content-disposition") Utils.get_filename(@headers["content-disposition"]) end |
#initialize_dup(other) ⇒ Object
43 44 45 46 47 |
# File 'lib/httpx/response/body.rb', line 43 def initialize_dup(other) super @buffer = other.instance_variable_get(:@buffer).dup end |
#initialize_inflaters ⇒ void
This method returns an undefined value.
prepares inflaters for the advertised encodings in "content-encoding" header.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/httpx/response/body.rb', line 185 def initialize_inflaters @inflaters = nil return unless @headers.key?("content-encoding") return unless @options.decompress_response_body @inflaters = @headers.get("content-encoding").filter_map do |encoding| next if encoding == "identity" inflater = self.class.initialize_inflater_by_encoding(encoding, @response) # do not uncompress if there is no decoder available. In fact, we can't reliably # continue decompressing beyond that, so ignore. break unless inflater @encodings << encoding inflater end end |
#inspect ⇒ Object
simplecov:disable
165 166 167 168 169 |
# File 'lib/httpx/response/body.rb', line 165 def inspect "#<#{self.class}:#{object_id} " \ "@state=#{@state} " \ "@length=#{@length}>" end |
#read(*args) ⇒ Object
reads a chunk from the payload (implementation of the IO reader protocol).
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/httpx/response/body.rb', line 72 def read(*args) return unless @buffer unless @reader rewind @reader = @buffer end @reader.read(*args) end |
#rewind ⇒ void
This method returns an undefined value.
rewinds the response payload buffer.
173 174 175 176 177 178 179 180 |
# File 'lib/httpx/response/body.rb', line 173 def rewind return unless @buffer # in case there's some reading going on @reader = nil @buffer.rewind end |
#to_s ⇒ Object Also known as: to_str
returns the full response payload as a string.
113 114 115 116 117 |
# File 'lib/httpx/response/body.rb', line 113 def to_s return "".b unless @buffer @buffer.to_s end |
#transition(nextstate) ⇒ void
This method returns an undefined value.
tries transitioning the body STM to the nextstate.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/httpx/response/body.rb', line 218 def transition(nextstate) case nextstate when :open return unless @state == :idle @buffer = Response::Buffer.new( threshold_size: @options.body_threshold_size, bytesize: @length, encoding: @encoding ) when :closed return if @state == :closed end @state = nextstate end |
#write(chunk) ⇒ Integer?
write the response payload chunk into the buffer. Inflates the chunk when required
and supported.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/httpx/response/body.rb', line 55 def write(chunk) return if @state == :closed return 0 if chunk.empty? chunk = decode_chunk(chunk) raise Error, "maximum response body size exceeded" if @max_response_body_size < @length transition(:open) @buffer.write(chunk) @response.emit(:chunk_received, chunk) chunk.bytesize end |