Class: Falcon::Adapters::Response

Inherits:
Protocol::HTTP::Response
  • Object
show all
Defined in:
lib/falcon/adapters/response.rb

Overview

A wrapper for a `Rack` response.

A Rack response consisting of `[status, headers, body]` includes various rack-specific elements, including:

  • A `headers` callback which bypasses normal response handling.

  • Potentially invalid content length.

  • Potentially invalid body when processing a `HEAD` request.

  • Newline-separated header values.

  • Other `rack.` specific header key/value pairs.

This wrapper takes those issues into account and adapts the rack response tuple into a Protocol::HTTP::Response.

Constant Summary collapse

IGNORE_HEADERS =
Middleware::Proxy::HOP_HEADERS

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(status, headers, body, protocol = nil) ⇒ Response

Initialize the response wrapper.



108
109
110
# File 'lib/falcon/adapters/response.rb', line 108

def initialize(status, headers, body, protocol = nil)
	super(nil, status, headers, body, protocol)
end

Class Method Details

.wrap(status, headers, body, request = nil) ⇒ Object

Wrap a rack response.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/falcon/adapters/response.rb', line 72

def self.wrap(status, headers, body, request = nil)
	headers, meta = wrap_headers(headers)
	
	if block = meta['rack.hijack']
		body = Async::HTTP::Body::Hijack.wrap(request, &block)
	else
		ignored = headers.extract(IGNORE_HEADERS)
		
		unless ignored.empty?
			Console.logger.warn("Ignoring protocol-level headers: #{ignored.inspect}")
		end
		
		body = Output.wrap(status, headers, body, request)
	end
	
	if request&.head?
		# I thought about doing this in Output.wrap, but decided the semantics are too tricky. Specifically, the various ways a rack response body can be wrapped, and the need to invoke #close at the right point.
		body = ::Protocol::HTTP::Body::Head.for(body)
	end
	
	protocol = meta['rack.protocol']
	
	# https://tools.ietf.org/html/rfc7231#section-7.4.2
	# headers.add('server', "falcon/#{Falcon::VERSION}")
	
	# https://tools.ietf.org/html/rfc7231#section-7.1.1.2
	# headers.add('date', Time.now.httpdate)
	
	return self.new(status, headers, body, protocol)
end

.wrap_headers(fields) ⇒ Object

Process the rack response headers into into a Protocol::HTTP::Headers instance, along with any extra `rack.` metadata.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/falcon/adapters/response.rb', line 48

def self.wrap_headers(fields)
	headers = ::Protocol::HTTP::Headers.new
	meta = {}
	
	fields.each do |key, value|
		key = key.downcase
		
		if key.start_with?('rack.')
			meta[key] = value
		else
			value.to_s.split("\n").each do |part|
				headers.add(key, part)
			end
		end
	end
	
	return headers, meta
end