Class: HTTPX::Response::Body

Inherits:
Object
  • Object
show all
Defined in:
lib/httpx/response/body.rb

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

Class Method Summary collapse

Instance Method Summary collapse

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, options)
  @response = response
  @headers = response.headers
  @options = options
  @window_size = options.window_size
  @encodings = []
  @length = 0
  @buffer = nil
  @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

#encodingObject (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

#encodingsObject (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

:nodoc:



232
233
234
235
236
237
238
239
# File 'lib/httpx/response/body.rb', line 232

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



153
154
155
156
157
158
159
160
# File 'lib/httpx/response/body.rb', line 153

def ==(other)
  super || case other
           when Response::Body
             @buffer == other.buffer
           else
             @buffer = other
           end
end

#bytesizeObject

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

#closeObject

closes/cleans the buffer, resets everything



144
145
146
147
148
149
150
151
# File 'lib/httpx/response/body.rb', line 144

def close
  if @buffer
    @buffer.close
    @buffer = nil
  end
  @length = 0
  transition(:closed)
end

#closed?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/httpx/response/body.rb', line 49

def closed?
  @state == :closed
end

#copy_to(dest) ⇒ Object

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
# 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
end

#eachObject

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.

Returns:

  • (Boolean)


122
123
124
# File 'lib/httpx/response/body.rb', line 122

def empty?
  @length.zero?
end

#filenameObject

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

#inspectObject

:nocov:



163
164
165
166
167
# File 'lib/httpx/response/body.rb', line 163

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

#rewindObject

rewinds the response payload buffer.



171
172
173
174
175
176
177
178
# File 'lib/httpx/response/body.rb', line 171

def rewind
  return unless @buffer

  # in case there's some reading going on
  @reader = nil

  @buffer.rewind
end

#to_sObject 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

#write(chunk) ⇒ Object

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)

  size = chunk.bytesize
  @length += size
  transition(:open)
  @buffer.write(chunk)

  @response.emit(:chunk_received, chunk)
  size
end