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.



15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/httpx/response/body.rb', line 15

def initialize(response, options)
  @response = response
  @headers = response.headers
  @options = options
  @window_size = options.window_size
  @encoding = response.content_type.charset || Encoding::BINARY
  @encodings = []
  @length = 0
  @buffer = nil
  @reader = nil
  @state = :idle
  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



139
140
141
142
143
144
145
146
147
# File 'lib/httpx/response/body.rb', line 139

def ==(other)
  object_id == other.object_id || begin
    if other.respond_to?(:read)
      _with_same_buffer_pos { FileUtils.compare_stream(@buffer, other) }
    else
      to_s == other.to_s
    end
  end
end

#bytesizeObject

size of the decoded response payload. May differ from “content-length” header if response was encoded over-the-wire.



71
72
73
# File 'lib/httpx/response/body.rb', line 71

def bytesize
  @length
end

#closeObject

closes/cleans the buffer, resets everything



130
131
132
133
134
135
136
137
# File 'lib/httpx/response/body.rb', line 130

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

#closed?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/httpx/response/body.rb', line 35

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"))


117
118
119
120
121
122
123
124
125
126
127
# File 'lib/httpx/response/body.rb', line 117

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.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/httpx/response/body.rb', line 76

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)


108
109
110
# File 'lib/httpx/response/body.rb', line 108

def empty?
  @length.zero?
end

#filenameObject

returns the declared filename in the “contennt-disposition” header, when present.



92
93
94
95
96
# File 'lib/httpx/response/body.rb', line 92

def filename
  return unless @headers.key?("content-disposition")

  Utils.get_filename(@headers["content-disposition"])
end

#initialize_dup(other) ⇒ Object



29
30
31
32
33
# File 'lib/httpx/response/body.rb', line 29

def initialize_dup(other)
  super

  @buffer = other.instance_variable_get(:@buffer).dup
end

#inspectObject

:nocov:



150
151
152
153
154
# File 'lib/httpx/response/body.rb', line 150

def inspect
  "#<HTTPX::Response::Body:#{object_id} " \
    "@state=#{@state} " \
    "@length=#{@length}>"
end

#read(*args) ⇒ Object

reads a chunk from the payload (implementation of the IO reader protocol).



58
59
60
61
62
63
64
65
66
67
# File 'lib/httpx/response/body.rb', line 58

def read(*args)
  return unless @buffer

  unless @reader
    rewind
    @reader = @buffer
  end

  @reader.read(*args)
end

#rewindObject

rewinds the response payload buffer.



158
159
160
161
162
163
164
165
# File 'lib/httpx/response/body.rb', line 158

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.



99
100
101
102
103
# File 'lib/httpx/response/body.rb', line 99

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.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/httpx/response/body.rb', line 41

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