Class: Dommy::Rack::Response
- Inherits:
-
Object
- Object
- Dommy::Rack::Response
- Defined in:
- lib/dommy/rack/response.rb
Overview
Wraps a single completed Rack response triple plus the absolute URL it was fetched at. The body is drained eagerly (Rack bodies are one-shot) and the Dommy document is parsed lazily on first access.
Constant Summary collapse
- HTML_CONTENT_TYPES =
["text/html", "application/xhtml+xml"].freeze
- REDIRECT_STATUSES =
[301, 302, 303, 307, 308].freeze
Instance Attribute Summary collapse
-
#headers ⇒ Object
readonly
Returns the value of attribute headers.
-
#redirects ⇒ Object
The redirects followed to reach this response, oldest first.
-
#status ⇒ Object
readonly
Returns the value of attribute status.
-
#url ⇒ Object
readonly
Returns the value of attribute url.
Instance Method Summary collapse
- #body ⇒ Object
- #client_error? ⇒ Boolean
-
#content_type ⇒ Object
Content-Type with any parameters (charset, boundary) stripped.
- #document ⇒ Object
- #error? ⇒ Boolean
- #html? ⇒ Boolean
-
#initialize(status, headers, body, url:) ⇒ Response
constructor
A new instance of Response.
-
#json(symbolize_names: false) ⇒ Object
The parsed JSON body.
-
#json? ⇒ Boolean
True when the response advertises a JSON content type, including structured-suffix types such as application/vnd.api+json.
- #location_header ⇒ Object
-
#meta_refresh_url ⇒ Object
The redirect target of an immediate (delay 0) <meta http-equiv= “refresh”>, or nil.
- #not_found? ⇒ Boolean
- #redirect? ⇒ Boolean
- #server_error? ⇒ Boolean
-
#set_cookie_strings ⇒ Object
All Set-Cookie values, handling both single-string (newline-joined) and array header shapes across Rack 2 and Rack 3.
-
#success? ⇒ Boolean
— Status-class predicates —.
-
#window ⇒ Object
The parsed Dommy window, or nil for non-HTML responses.
Constructor Details
#initialize(status, headers, body, url:) ⇒ Response
Returns a new instance of Response.
21 22 23 24 25 26 27 28 29 |
# File 'lib/dommy/rack/response.rb', line 21 def initialize(status, headers, body, url:) @status = status.to_i @headers = headers || {} @url = url @body = drain_body(body) @document_parsed = false @window = nil @redirects = [] end |
Instance Attribute Details
#headers ⇒ Object (readonly)
Returns the value of attribute headers.
14 15 16 |
# File 'lib/dommy/rack/response.rb', line 14 def headers @headers end |
#redirects ⇒ Object
The redirects followed to reach this response, oldest first. Each entry is url:, location:. Empty unless this was the final response of a followed redirect chain. Set by Navigation.
19 20 21 |
# File 'lib/dommy/rack/response.rb', line 19 def redirects @redirects end |
#status ⇒ Object (readonly)
Returns the value of attribute status.
14 15 16 |
# File 'lib/dommy/rack/response.rb', line 14 def status @status end |
#url ⇒ Object (readonly)
Returns the value of attribute url.
14 15 16 |
# File 'lib/dommy/rack/response.rb', line 14 def url @url end |
Instance Method Details
#body ⇒ Object
31 32 33 |
# File 'lib/dommy/rack/response.rb', line 31 def body @body end |
#client_error? ⇒ Boolean
70 |
# File 'lib/dommy/rack/response.rb', line 70 def client_error? = (400..499).cover?(@status) |
#content_type ⇒ Object
Content-Type with any parameters (charset, boundary) stripped.
36 37 38 39 40 41 |
# File 'lib/dommy/rack/response.rb', line 36 def content_type raw = header("content-type") return nil unless raw raw.split(";", 2).first.to_s.strip.downcase end |
#document ⇒ Object
110 111 112 |
# File 'lib/dommy/rack/response.rb', line 110 def document window&.document end |
#error? ⇒ Boolean
72 |
# File 'lib/dommy/rack/response.rb', line 72 def error? = @status >= 400 |
#html? ⇒ Boolean
43 44 45 |
# File 'lib/dommy/rack/response.rb', line 43 def html? HTML_CONTENT_TYPES.include?(content_type) end |
#json(symbolize_names: false) ⇒ Object
The parsed JSON body. Parses regardless of Content-Type so that servers mislabeling JSON still work; raises JSON::ParserError on invalid JSON. Pass symbolize_names: true for symbol keys.
59 60 61 |
# File 'lib/dommy/rack/response.rb', line 59 def json(symbolize_names: false) JSON.parse(@body, symbolize_names: symbolize_names) end |
#json? ⇒ Boolean
True when the response advertises a JSON content type, including structured-suffix types such as application/vnd.api+json.
49 50 51 52 53 54 |
# File 'lib/dommy/rack/response.rb', line 49 def json? ct = content_type return false unless ct ct == "application/json" || ct == "text/json" || ct.end_with?("+json") end |
#location_header ⇒ Object
75 76 77 |
# File 'lib/dommy/rack/response.rb', line 75 def location_header header("location") end |
#meta_refresh_url ⇒ Object
The redirect target of an immediate (delay 0) <meta http-equiv= “refresh”>, or nil. The HTML analog of location_header. A self-refresh with no URL is ignored to avoid reload loops; non-HTML responses and non-zero delays return nil.
83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/dommy/rack/response.rb', line 83 def return nil unless html? = document&.query_selector_all("meta") &.find { |m| m.get_attribute("http-equiv")&.downcase == "refresh" } return nil unless delay, _, rest = .get_attribute("content").to_s.partition(";") return nil unless delay.strip.match?(/\A0+\z/) url = rest.strip.sub(/\Aurl\s*=\s*/i, "").delete("\"'").strip url.empty? ? nil : url end |
#not_found? ⇒ Boolean
73 |
# File 'lib/dommy/rack/response.rb', line 73 def not_found? = @status == 404 |
#redirect? ⇒ Boolean
63 64 65 |
# File 'lib/dommy/rack/response.rb', line 63 def redirect? REDIRECT_STATUSES.include?(@status) end |
#server_error? ⇒ Boolean
71 |
# File 'lib/dommy/rack/response.rb', line 71 def server_error? = (500..599).cover?(@status) |
#set_cookie_strings ⇒ Object
All Set-Cookie values, handling both single-string (newline-joined) and array header shapes across Rack 2 and Rack 3.
99 100 101 102 |
# File 'lib/dommy/rack/response.rb', line 99 def values = lookup_header("set-cookie") Array(values).flat_map { |v| v.to_s.split("\n") }.reject(&:empty?) end |
#success? ⇒ Boolean
— Status-class predicates —
69 |
# File 'lib/dommy/rack/response.rb', line 69 def success? = (200..299).cover?(@status) |
#window ⇒ Object
The parsed Dommy window, or nil for non-HTML responses.
105 106 107 108 |
# File 'lib/dommy/rack/response.rb', line 105 def window parse_document! unless @document_parsed @window end |