Class: Dommy::Navigation::Fetcher
- Inherits:
-
Object
- Object
- Dommy::Navigation::Fetcher
- Defined in:
- lib/dommy/navigation.rb
Overview
URL resolution + redirect following over a Resources adapter. This is the
engine-agnostic core of "fetch the document at this navigation target": it
folds GET params into the query, serializes a POST body, follows 3xx
redirects (303→GET, 301/302 POST→GET, 307/308 keep method+body), and
returns [Resources::Response | nil, final_url]. The Rack session's own
redirect loop is the reference; this is its Resources-based generalization
so the core Browser can navigate without Rack.
Constant Summary collapse
- REDIRECT_STATUSES =
[301, 302, 303, 307, 308].freeze
- KEEP_METHOD_STATUSES =
[307, 308].freeze
- QUERY_METHODS =
%w[GET HEAD].freeze
Instance Method Summary collapse
-
#append_query(url, params) ⇒ Object
Merge ordered [name, value] params into
url's query, keeping any existing query and a trailing fragment (browser address-bar form). -
#initialize(resources, max_redirects: 20, same_origin: false) ⇒ Fetcher
constructor
same_origin: truescopes navigation to a single origin (the first one requested): a target or redirect to a different scheme/host/port is blocked (returns no response, so the browser stays put) — a test policy mirroring dommy-rack, so a page can't wander off to an external site the resources adapter happens to serve. -
#request(method:, url:, params: nil, body: nil, enctype: nil, headers: {}) ⇒ Object
Resolve + issue the request, following redirects.
Constructor Details
#initialize(resources, max_redirects: 20, same_origin: false) ⇒ Fetcher
same_origin: true scopes navigation to a single origin (the first one
requested): a target or redirect to a different scheme/host/port is
blocked (returns no response, so the browser stays put) — a test policy
mirroring dommy-rack, so a page can't wander off to an external site the
resources adapter happens to serve.
84 85 86 87 88 89 |
# File 'lib/dommy/navigation.rb', line 84 def initialize(resources, max_redirects: 20, same_origin: false) @resources = resources @max_redirects = max_redirects @same_origin = same_origin @origin = nil end |
Instance Method Details
#append_query(url, params) ⇒ Object
Merge ordered [name, value] params into url's query, keeping any
existing query and a trailing fragment (browser address-bar form).
117 118 119 120 121 122 123 124 |
# File 'lib/dommy/navigation.rb', line 117 def append_query(url, params) encoded = URI.encode_www_form(params) return url if encoded.empty? base, hash, fragment = url.to_s.partition("#") sep = base.include?("?") ? "&" : "?" "#{base}#{sep}#{encoded}#{hash}#{fragment}" end |
#request(method:, url:, params: nil, body: nil, enctype: nil, headers: {}) ⇒ Object
Resolve + issue the request, following redirects. params is an ordered
[name, value] array (form data set); it folds into the query for GET/HEAD
and becomes the request body otherwise. Returns [response|nil, final_url];
a nil response means "nothing served this URL" (stay on the current page).
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/dommy/navigation.rb', line 95 def request(method:, url:, params: nil, body: nil, enctype: nil, headers: {}) return [nil, url.to_s] unless @resources verb = method.to_s.upcase target = url.to_s # The first request establishes the origin the session is scoped to. @origin ||= origin_of(target) if @same_origin return [nil, target] if cross_origin?(target) hdrs = headers.dup if params && QUERY_METHODS.include?(verb) target = append_query(target, params) params = nil elsif params body, content_type = encode_body(params, enctype) hdrs["Content-Type"] ||= content_type if content_type end run(verb, target, body, hdrs, 0) end |