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