diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/http/response.rb')
-rw-r--r-- | actionpack/lib/action_dispatch/http/response.rb | 78 |
1 files changed, 50 insertions, 28 deletions
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index fa4c54701a..e8173e2a99 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'action_dispatch/http/filter_redirect' -require 'action_dispatch/http/cache' -require 'monitor' +require "active_support/core_ext/module/attribute_accessors" +require "action_dispatch/http/filter_redirect" +require "action_dispatch/http/cache" +require "monitor" module ActionDispatch # :nodoc: # Represents an HTTP response generated by a controller action. Use it to @@ -41,7 +41,7 @@ module ActionDispatch # :nodoc: def []=(k,v) if @response.sending? || @response.sent? - raise ActionDispatch::IllegalStateError, 'header already sent' + raise ActionDispatch::IllegalStateError, "header already sent" end super @@ -67,8 +67,14 @@ module ActionDispatch # :nodoc: alias_method :headers, :header - delegate :[], :[]=, :to => :@header - delegate :each, :to => :@stream + delegate :[], :[]=, to: :@header + + def each(&block) + sending! + x = @stream.each(&block) + sent! + x + end CONTENT_TYPE = "Content-Type".freeze SET_COOKIE = "Set-Cookie".freeze @@ -97,10 +103,10 @@ module ActionDispatch # :nodoc: def body @str_body ||= begin - buf = '' - each { |chunk| buf << chunk } - buf - end + buf = "" + each { |chunk| buf << chunk } + buf + end end def write(string) @@ -112,10 +118,13 @@ module ActionDispatch # :nodoc: end def each(&block) - @response.sending! - x = @buf.each(&block) - @response.sent! - x + if @str_body + return enum_for(:each) unless block_given? + + yield @str_body + else + each_chunk(&block) + end end def abort @@ -129,6 +138,12 @@ module ActionDispatch # :nodoc: def closed? @closed end + + private + + def each_chunk(&block) + @buf.each(&block) # extract into own method + end end def self.create(status = 200, header = {}, body = [], default_headers: self.default_headers) @@ -209,8 +224,10 @@ module ActionDispatch # :nodoc: # Sets the HTTP content type. def content_type=(content_type) - header_info = parse_content_type - set_content_type content_type.to_s, header_info.charset || self.class.default_charset + return unless content_type + new_header_info = parse_content_type(content_type.to_s) + prev_header_info = parsed_content_type_header + set_content_type new_header_info.mime_type, new_header_info.charset || prev_header_info.charset || self.class.default_charset end # Sets the HTTP response's content MIME type. For example, in the controller @@ -223,7 +240,7 @@ module ActionDispatch # :nodoc: # information. def content_type - parse_content_type.mime_type + parsed_content_type_header.mime_type end def sending_file=(v) @@ -238,7 +255,7 @@ module ActionDispatch # :nodoc: # response.charset = 'utf-16' # => 'utf-16' # response.charset = nil # => 'utf-8' def charset=(charset) - header_info = parse_content_type + header_info = parsed_content_type_header if false == charset set_header CONTENT_TYPE, header_info.mime_type else @@ -250,7 +267,7 @@ module ActionDispatch # :nodoc: # The charset of the response. HTML wants to know the encoding of the # content you're giving them, so we need to send that along. def charset - header_info = parse_content_type + header_info = parsed_content_type_header header_info.charset || self.class.default_charset end @@ -314,7 +331,7 @@ module ActionDispatch # :nodoc: # Stream the file's contents if Rack::Sendfile isn't present. def each - File.open(to_path, 'rb') do |file| + File.open(to_path, "rb") do |file| while chunk = file.read(16384) yield chunk end @@ -374,7 +391,7 @@ module ActionDispatch # :nodoc: if header = get_header(SET_COOKIE) header = header.split("\n") if header.respond_to?(:to_str) header.each do |cookie| - if pair = cookie.split(';').first + if pair = cookie.split(";").first key, value = pair.split("=").map { |v| Rack::Utils.unescape(v) } cookies[key] = value end @@ -388,8 +405,7 @@ module ActionDispatch # :nodoc: ContentTypeHeader = Struct.new :mime_type, :charset NullContentTypeHeader = ContentTypeHeader.new nil, nil - def parse_content_type - content_type = get_header CONTENT_TYPE + def parse_content_type(content_type) if content_type type, charset = content_type.split(/;\s*charset=/) type = nil if type.empty? @@ -399,8 +415,14 @@ module ActionDispatch # :nodoc: end end + # Small internal convenience method to get the parsed version of the current + # content type header. + def parsed_content_type_header + parse_content_type(get_header(CONTENT_TYPE)) + end + def set_content_type(content_type, charset) - type = (content_type || '').dup + type = (content_type || "").dup type << "; charset=#{charset}" if charset set_header CONTENT_TYPE, type end @@ -435,7 +457,7 @@ module ActionDispatch # :nodoc: def assign_default_content_type_and_charset! return if content_type - ct = parse_content_type + ct = parsed_content_type_header set_content_type(ct.mime_type || Mime[:html].to_s, ct.charset || self.class.default_charset) end @@ -460,7 +482,7 @@ module ActionDispatch # :nodoc: end def respond_to?(method, include_private = false) - if method.to_s == 'to_path' + if method.to_s == "to_path" @response.stream.respond_to?(method) else super @@ -479,7 +501,7 @@ module ActionDispatch # :nodoc: def handle_no_content! if NO_CONTENT_CODES.include?(@status) @header.delete CONTENT_TYPE - @header.delete 'Content-Length' + @header.delete "Content-Length" end end |