lib/mechanize/http/agent.rb in mechanize-2.2.1 vs lib/mechanize/http/agent.rb in mechanize-2.3

- old
+ new

@@ -96,11 +96,11 @@ # The cookies for this agent attr_accessor :cookie_jar # Responses larger than this will be written to a Tempfile instead of stored - # in memory. + # in memory. Setting this to nil disables creation of Tempfiles. attr_accessor :max_file_buffer # :section: Utility # The context parses responses into pages @@ -124,11 +124,11 @@ @follow_meta_refresh = false @follow_meta_refresh_self = false @gzip_enabled = true @history = Mechanize::History.new @keep_alive = true - @max_file_buffer = 10240 + @max_file_buffer = 100_000 # 5MB for response bodies @open_timeout = nil @post_connect_hooks = [] @pre_connect_hooks = [] @read_timeout = nil @redirect_ok = true @@ -373,18 +373,11 @@ def content_encoding_gunzip body_io log.debug('gzip response') if log zio = Zlib::GzipReader.new body_io - out_io = Tempfile.new 'mechanize-decode' - out_io.unlink - out_io.binmode - - until zio.eof? do - out_io.write zio.read 16384 - end - + out_io = auto_io 'mechanize-gunzip', 16384, zio zio.finish return out_io rescue Zlib::Error log.error('unable to gunzip response, trying raw inflate') if log @@ -398,10 +391,11 @@ log.error("unable to gunzip response: #{e}") if log raise end ensure zio.close if zio and not zio.closed? + body_io.close unless body_io.closed? end ## # Decodes a deflate-encoded +body_io+. If it cannot be decoded, raw inflate # is tried followed by raising an error. @@ -419,10 +413,12 @@ return inflate body_io, -Zlib::MAX_WBITS rescue Zlib::Error => e log.error("unable to inflate response: #{e}") if log raise end + ensure + body_io.close end def disable_keep_alive request request['connection'] = 'close' unless @keep_alive end @@ -737,11 +733,14 @@ message = "error handling content-encoding #{response['Content-Encoding']}:" message << " #{e.message} (#{e.class})" raise Mechanize::Error, message ensure begin - body_io.close! if Tempfile === body_io and out_io.path != body_io.path + if Tempfile === body_io and + (StringIO === out_io or out_io.path != body_io.path) then + body_io.close! + end rescue IOError # HACK ruby 1.8 raises IOError when closing the stream end end @@ -781,11 +780,11 @@ redirects + 1 > @redirection_limit sleep delay @history.push(page, page.uri) fetch new_url, :get, {}, [], - Mechanize::Page.new(nil, {'content-type'=>'text/html'}), redirects + Mechanize::Page.new, redirects end def response_log response return unless log @@ -802,11 +801,11 @@ end def response_read response, request, uri content_length = response.content_length - if content_length and content_length > @max_file_buffer then + if use_tempfile? content_length then body_io = Tempfile.new 'mechanize-raw' body_io.unlink body_io.binmode if defined? body_io.binmode else body_io = StringIO.new @@ -817,11 +816,11 @@ begin response.read_body { |part| total += part.length - if StringIO === body_io and total > @max_file_buffer then + if StringIO === body_io and use_tempfile? total then new_io = Tempfile.new 'mechanize-raw' new_io.unlink new_io.binmode new_io.write body_io.string @@ -1032,21 +1031,56 @@ @http.idle_timeout = timeout end # :section: Utility + ## + # Creates a new output IO by reading +input_io+ in +read_size+ chunks. If + # the output is over the max_file_buffer size a Tempfile with +name+ is + # created. + # + # If a block is provided, each chunk of +input_io+ is yielded for further + # processing. + + def auto_io name, read_size, input_io + out_io = StringIO.new + + out_io.set_encoding Encoding::BINARY if out_io.respond_to? :set_encoding + + until input_io.eof? do + if StringIO === out_io and use_tempfile? out_io.size then + new_io = Tempfile.new name + new_io.unlink + new_io.binmode + + new_io.write out_io.string + out_io = new_io + end + + chunk = input_io.read read_size + chunk = yield chunk if block_given? + + out_io.write chunk + end + + out_io.rewind + + out_io + end + def inflate compressed, window_bits = nil inflate = Zlib::Inflate.new window_bits - out_io = Tempfile.new 'mechanize-decode' - until compressed.eof? do - out_io.write inflate.inflate compressed.read 1024 + out_io = auto_io 'mechanize-inflate', 1024, compressed do |chunk| + inflate.inflate chunk end out_io.write inflate.finish out_io + ensure + inflate.close end def log @context.log end @@ -1079,9 +1113,16 @@ proxy_uri.port = port proxy_uri.user = user if user proxy_uri.password = pass if pass @http.proxy = proxy_uri + end + + def use_tempfile? size + return false unless @max_file_buffer + return false unless size + + size >= @max_file_buffer end end