1# HTTP response class.
2#
3# This class wraps together the response header and the response body (the
4# entity requested).
5#
6# It mixes in the HTTPHeader module, which provides access to response
7# header values both via hash-like methods and via individual readers.
8#
9# Note that each possible HTTP response code defines its own
10# HTTPResponse subclass.  These are listed below.
11#
12# All classes are defined under the Net module. Indentation indicates
13# inheritance.  For a list of the classes see Net::HTTP.
14#
15#
16class Net::HTTPResponse
17  class << self
18    # true if the response has a body.
19    def body_permitted?
20      self::HAS_BODY
21    end
22
23    def exception_type   # :nodoc: internal use only
24      self::EXCEPTION_TYPE
25    end
26
27    def read_new(sock)   #:nodoc: internal use only
28      httpv, code, msg = read_status_line(sock)
29      res = response_class(code).new(httpv, code, msg)
30      each_response_header(sock) do |k,v|
31        res.add_field k, v
32      end
33      res
34    end
35
36    private
37
38    def read_status_line(sock)
39      str = sock.readline
40      m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/in.match(str) or
41        raise Net::HTTPBadResponse, "wrong status line: #{str.dump}"
42      m.captures
43    end
44
45    def response_class(code)
46      CODE_TO_OBJ[code] or
47      CODE_CLASS_TO_OBJ[code[0,1]] or
48      Net::HTTPUnknownResponse
49    end
50
51    def each_response_header(sock)
52      key = value = nil
53      while true
54        line = sock.readuntil("\n", true).sub(/\s+\z/, '')
55        break if line.empty?
56        if line[0] == ?\s or line[0] == ?\t and value
57          value << ' ' unless value.empty?
58          value << line.strip
59        else
60          yield key, value if key
61          key, value = line.strip.split(/\s*:\s*/, 2)
62          raise Net::HTTPBadResponse, 'wrong header line format' if value.nil?
63        end
64      end
65      yield key, value if key
66    end
67  end
68
69  # next is to fix bug in RDoc, where the private inside class << self
70  # spills out.
71  public
72
73  include Net::HTTPHeader
74
75  def initialize(httpv, code, msg)   #:nodoc: internal use only
76    @http_version = httpv
77    @code         = code
78    @message      = msg
79    initialize_http_header nil
80    @body = nil
81    @read = false
82    @uri  = nil
83    @decode_content = false
84  end
85
86  # The HTTP version supported by the server.
87  attr_reader :http_version
88
89  # The HTTP result code string. For example, '302'.  You can also
90  # determine the response type by examining which response subclass
91  # the response object is an instance of.
92  attr_reader :code
93
94  # The HTTP result message sent by the server. For example, 'Not Found'.
95  attr_reader :message
96  alias msg message   # :nodoc: obsolete
97
98  # The URI used to fetch this response.  The response URI is only available
99  # if a URI was used to create the request.
100  attr_reader :uri
101
102  # Set to true automatically when the request did not contain an
103  # Accept-Encoding header from the user.
104  attr_accessor :decode_content
105
106  def inspect
107    "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
108  end
109
110  #
111  # response <-> exception relationship
112  #
113
114  def code_type   #:nodoc:
115    self.class
116  end
117
118  def error!   #:nodoc:
119    raise error_type().new(@code + ' ' + @message.dump, self)
120  end
121
122  def error_type   #:nodoc:
123    self.class::EXCEPTION_TYPE
124  end
125
126  # Raises an HTTP error if the response is not 2xx (success).
127  def value
128    error! unless self.kind_of?(Net::HTTPSuccess)
129  end
130
131  def uri= uri # :nodoc:
132    @uri = uri.dup if uri
133  end
134
135  #
136  # header (for backward compatibility only; DO NOT USE)
137  #
138
139  def response   #:nodoc:
140    warn "#{caller(1)[0]}: warning: Net::HTTPResponse#response is obsolete" if $VERBOSE
141    self
142  end
143
144  def header   #:nodoc:
145    warn "#{caller(1)[0]}: warning: Net::HTTPResponse#header is obsolete" if $VERBOSE
146    self
147  end
148
149  def read_header   #:nodoc:
150    warn "#{caller(1)[0]}: warning: Net::HTTPResponse#read_header is obsolete" if $VERBOSE
151    self
152  end
153
154  #
155  # body
156  #
157
158  def reading_body(sock, reqmethodallowbody)  #:nodoc: internal use only
159    @socket = sock
160    @body_exist = reqmethodallowbody && self.class.body_permitted?
161    begin
162      yield
163      self.body   # ensure to read body
164    ensure
165      @socket = nil
166    end
167  end
168
169  # Gets the entity body returned by the remote HTTP server.
170  #
171  # If a block is given, the body is passed to the block, and
172  # the body is provided in fragments, as it is read in from the socket.
173  #
174  # Calling this method a second or subsequent time for the same
175  # HTTPResponse object will return the value already read.
176  #
177  #   http.request_get('/index.html') {|res|
178  #     puts res.read_body
179  #   }
180  #
181  #   http.request_get('/index.html') {|res|
182  #     p res.read_body.object_id   # 538149362
183  #     p res.read_body.object_id   # 538149362
184  #   }
185  #
186  #   # using iterator
187  #   http.request_get('/index.html') {|res|
188  #     res.read_body do |segment|
189  #       print segment
190  #     end
191  #   }
192  #
193  def read_body(dest = nil, &block)
194    if @read
195      raise IOError, "#{self.class}\#read_body called twice" if dest or block
196      return @body
197    end
198    to = procdest(dest, block)
199    stream_check
200    if @body_exist
201      read_body_0 to
202      @body = to
203    else
204      @body = nil
205    end
206    @read = true
207
208    @body
209  end
210
211  # Returns the full entity body.
212  #
213  # Calling this method a second or subsequent time will return the
214  # string already read.
215  #
216  #   http.request_get('/index.html') {|res|
217  #     puts res.body
218  #   }
219  #
220  #   http.request_get('/index.html') {|res|
221  #     p res.body.object_id   # 538149362
222  #     p res.body.object_id   # 538149362
223  #   }
224  #
225  def body
226    read_body()
227  end
228
229  # Because it may be necessary to modify the body, Eg, decompression
230  # this method facilitates that.
231  def body=(value)
232    @body = value
233  end
234
235  alias entity body   #:nodoc: obsolete
236
237  private
238
239  ##
240  # Checks for a supported Content-Encoding header and yields an Inflate
241  # wrapper for this response's socket when zlib is present.  If the
242  # Content-Encoding is unsupported or zlib is missing the plain socket is
243  # yielded.
244  #
245  # If a Content-Range header is present a plain socket is yielded as the
246  # bytes in the range may not be a complete deflate block.
247
248  def inflater # :nodoc:
249    return yield @socket unless Net::HTTP::HAVE_ZLIB
250    return yield @socket unless @decode_content
251    return yield @socket if self['content-range']
252
253    case self['content-encoding']
254    when 'deflate', 'gzip', 'x-gzip' then
255      self.delete 'content-encoding'
256
257      inflate_body_io = Inflater.new(@socket)
258
259      begin
260        yield inflate_body_io
261      ensure
262        inflate_body_io.finish
263      end
264    when 'none', 'identity' then
265      self.delete 'content-encoding'
266
267      yield @socket
268    else
269      yield @socket
270    end
271  end
272
273  def read_body_0(dest)
274    inflater do |inflate_body_io|
275      if chunked?
276        read_chunked dest, inflate_body_io
277        return
278      end
279
280      @socket = inflate_body_io
281
282      clen = content_length()
283      if clen
284        @socket.read clen, dest, true   # ignore EOF
285        return
286      end
287      clen = range_length()
288      if clen
289        @socket.read clen, dest
290        return
291      end
292      @socket.read_all dest
293    end
294  end
295
296  ##
297  # read_chunked reads from +@socket+ for chunk-size, chunk-extension, CRLF,
298  # etc. and +chunk_data_io+ for chunk-data which may be deflate or gzip
299  # encoded.
300  #
301  # See RFC 2616 section 3.6.1 for definitions
302
303  def read_chunked(dest, chunk_data_io) # :nodoc:
304    len = nil
305    total = 0
306    while true
307      line = @socket.readline
308      hexlen = line.slice(/[0-9a-fA-F]+/) or
309          raise Net::HTTPBadResponse, "wrong chunk size line: #{line}"
310      len = hexlen.hex
311      break if len == 0
312      begin
313        chunk_data_io.read len, dest
314      ensure
315        total += len
316        @socket.read 2   # \r\n
317      end
318    end
319    until @socket.readline.empty?
320      # none
321    end
322  end
323
324  def stream_check
325    raise IOError, 'attempt to read body out of block' if @socket.closed?
326  end
327
328  def procdest(dest, block)
329    raise ArgumentError, 'both arg and block given for HTTP method' if
330      dest and block
331    if block
332      Net::ReadAdapter.new(block)
333    else
334      dest || ''
335    end
336  end
337
338  ##
339  # Inflater is a wrapper around Net::BufferedIO that transparently inflates
340  # zlib and gzip streams.
341
342  class Inflater # :nodoc:
343
344    ##
345    # Creates a new Inflater wrapping +socket+
346
347    def initialize socket
348      @socket = socket
349      # zlib with automatic gzip detection
350      @inflate = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
351    end
352
353    ##
354    # Finishes the inflate stream.
355
356    def finish
357      @inflate.finish
358    end
359
360    ##
361    # Returns a Net::ReadAdapter that inflates each read chunk into +dest+.
362    #
363    # This allows a large response body to be inflated without storing the
364    # entire body in memory.
365
366    def inflate_adapter(dest)
367      block = proc do |compressed_chunk|
368        @inflate.inflate(compressed_chunk) do |chunk|
369          dest << chunk
370        end
371      end
372
373      Net::ReadAdapter.new(block)
374    end
375
376    ##
377    # Reads +clen+ bytes from the socket, inflates them, then writes them to
378    # +dest+.  +ignore_eof+ is passed down to Net::BufferedIO#read
379    #
380    # Unlike Net::BufferedIO#read, this method returns more than +clen+ bytes.
381    # At this time there is no way for a user of Net::HTTPResponse to read a
382    # specific number of bytes from the HTTP response body, so this internal
383    # API does not return the same number of bytes as were requested.
384    #
385    # See https://bugs.ruby-lang.org/issues/6492 for further discussion.
386
387    def read clen, dest, ignore_eof = false
388      temp_dest = inflate_adapter(dest)
389
390      @socket.read clen, temp_dest, ignore_eof
391    end
392
393    ##
394    # Reads the rest of the socket, inflates it, then writes it to +dest+.
395
396    def read_all dest
397      temp_dest = inflate_adapter(dest)
398
399      @socket.read_all temp_dest
400    end
401
402  end
403
404end
405
406