universal_renderer 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +200 -230
- data/lib/universal_renderer/client/base.rb +75 -0
- data/lib/universal_renderer/client/stream/error_logger.rb +31 -0
- data/lib/universal_renderer/client/stream/execution.rb +94 -0
- data/lib/universal_renderer/client/stream/setup.rb +39 -0
- data/lib/universal_renderer/client/stream.rb +86 -0
- data/lib/universal_renderer/engine.rb +3 -0
- data/{app/controllers/concerns → lib}/universal_renderer/rendering.rb +68 -32
- data/lib/universal_renderer/ssr/helpers.rb +45 -0
- data/lib/universal_renderer/ssr/scrubber.rb +62 -0
- data/lib/universal_renderer/version.rb +1 -1
- data/lib/universal_renderer.rb +5 -1
- metadata +10 -16
- data/app/helpers/universal_renderer/ssr_helpers.rb +0 -19
- data/app/services/universal_renderer/static_client.rb +0 -56
- data/app/services/universal_renderer/stream_client/error_logger.rb +0 -29
- data/app/services/universal_renderer/stream_client/execution.rb +0 -88
- data/app/services/universal_renderer/stream_client/setup.rb +0 -37
- data/app/services/universal_renderer/stream_client.rb +0 -84
- data/lib/universal_renderer/ssr_scrubber.rb +0 -61
@@ -1,37 +0,0 @@
|
|
1
|
-
module UniversalRenderer
|
2
|
-
class StreamClient
|
3
|
-
module Setup
|
4
|
-
class << self
|
5
|
-
def _ensure_ssr_server_url_configured?(config)
|
6
|
-
config.ssr_url.present?
|
7
|
-
end
|
8
|
-
|
9
|
-
def _build_stream_request_components(body, config)
|
10
|
-
# Ensure ssr_url is present, though _ensure_ssr_server_url_configured? should have caught this.
|
11
|
-
# However, direct calls to this method might occur, so a check or reliance on config.ssr_url is important.
|
12
|
-
if config.ssr_url.blank?
|
13
|
-
raise ArgumentError, "SSR URL is not configured."
|
14
|
-
end
|
15
|
-
|
16
|
-
parsed_ssr_url = URI.parse(config.ssr_url)
|
17
|
-
stream_uri = URI.join(parsed_ssr_url, config.ssr_stream_path)
|
18
|
-
|
19
|
-
http = Net::HTTP.new(stream_uri.host, stream_uri.port)
|
20
|
-
http.use_ssl = (stream_uri.scheme == "https")
|
21
|
-
http.open_timeout = config.timeout
|
22
|
-
http.read_timeout = config.timeout
|
23
|
-
|
24
|
-
http_request =
|
25
|
-
Net::HTTP::Post.new(
|
26
|
-
stream_uri.request_uri,
|
27
|
-
"Content-Type" => "application/json"
|
28
|
-
)
|
29
|
-
|
30
|
-
http_request.body = body.to_json
|
31
|
-
|
32
|
-
[stream_uri, http, http_request]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "stream_client/setup"
|
4
|
-
require_relative "stream_client/execution"
|
5
|
-
require_relative "stream_client/error_logger"
|
6
|
-
|
7
|
-
module UniversalRenderer
|
8
|
-
class StreamClient
|
9
|
-
extend Setup
|
10
|
-
extend Execution
|
11
|
-
extend ErrorLogger
|
12
|
-
|
13
|
-
# Orchestrates the streaming process for server-side rendering.
|
14
|
-
#
|
15
|
-
# @param url [String] The URL of the page to render.
|
16
|
-
# @param props [Hash] Data to be passed for rendering, including layout HTML.
|
17
|
-
# @param template [String] The HTML template to use for rendering.
|
18
|
-
# @param response [ActionDispatch::Response] The Rails response object to stream to.
|
19
|
-
# @return [Boolean] True if streaming was initiated, false otherwise.
|
20
|
-
def self.stream(url, props, template, response)
|
21
|
-
config = UniversalRenderer.config
|
22
|
-
|
23
|
-
unless Setup._ensure_ssr_server_url_configured?(config)
|
24
|
-
Rails.logger.warn(
|
25
|
-
"StreamClient: SSR URL (config.ssr_url) is not configured. Falling back."
|
26
|
-
)
|
27
|
-
return false
|
28
|
-
end
|
29
|
-
|
30
|
-
stream_uri_obj = nil
|
31
|
-
full_ssr_url_for_log = config.ssr_url.to_s # For logging in case of early error
|
32
|
-
|
33
|
-
begin
|
34
|
-
body = { url: url, props: props, template: template }
|
35
|
-
|
36
|
-
actual_stream_uri, http_client, http_post_request =
|
37
|
-
Setup._build_stream_request_components(body, config)
|
38
|
-
|
39
|
-
stream_uri_obj = actual_stream_uri
|
40
|
-
|
41
|
-
full_ssr_url_for_log = actual_stream_uri.to_s # Update for more specific logging
|
42
|
-
rescue URI::InvalidURIError => e
|
43
|
-
Rails.logger.error(
|
44
|
-
"StreamClient: SSR stream failed due to invalid URI ('#{config.ssr_url}'): #{e.message}"
|
45
|
-
)
|
46
|
-
|
47
|
-
return false
|
48
|
-
rescue StandardError => e
|
49
|
-
_log_setup_error(e, full_ssr_url_for_log)
|
50
|
-
|
51
|
-
return false
|
52
|
-
end
|
53
|
-
|
54
|
-
Execution._perform_streaming(
|
55
|
-
http_client,
|
56
|
-
http_post_request,
|
57
|
-
response,
|
58
|
-
stream_uri_obj
|
59
|
-
)
|
60
|
-
rescue Errno::ECONNREFUSED,
|
61
|
-
Errno::EHOSTUNREACH,
|
62
|
-
Net::OpenTimeout,
|
63
|
-
Net::ReadTimeout,
|
64
|
-
SocketError => e
|
65
|
-
uri_str_for_conn_error =
|
66
|
-
stream_uri_obj ? stream_uri_obj.to_s : full_ssr_url_for_log
|
67
|
-
|
68
|
-
ErrorLogger._log_connection_error(e, uri_str_for_conn_error)
|
69
|
-
|
70
|
-
false
|
71
|
-
rescue StandardError => e
|
72
|
-
uri_str_for_unexpected_error =
|
73
|
-
stream_uri_obj ? stream_uri_obj.to_s : full_ssr_url_for_log
|
74
|
-
|
75
|
-
ErrorLogger._log_unexpected_error(
|
76
|
-
e,
|
77
|
-
uri_str_for_unexpected_error,
|
78
|
-
"StreamClient: Unexpected error during SSR stream process"
|
79
|
-
)
|
80
|
-
|
81
|
-
false
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
require "loofah"
|
2
|
-
|
3
|
-
module UniversalRenderer
|
4
|
-
class SsrScrubber < ::Loofah::Scrubber
|
5
|
-
def initialize
|
6
|
-
super
|
7
|
-
@direction = :top_down
|
8
|
-
end
|
9
|
-
|
10
|
-
def scrub(node)
|
11
|
-
# Primary actions: stop if script, continue if a passthrough tag, otherwise clean attributes.
|
12
|
-
return Loofah::Scrubber::STOP if handle_script_node(node) # Checks for <script> and removes it
|
13
|
-
|
14
|
-
# Allows <link rel="stylesheet">, <style>, <meta> to pass through this scrubber.
|
15
|
-
return Loofah::Scrubber::CONTINUE if passthrough_node?(node)
|
16
|
-
|
17
|
-
# For all other nodes, clean potentially harmful attributes.
|
18
|
-
clean_attributes(node)
|
19
|
-
# Default Loofah behavior (CONTINUE for children) applies if not returned earlier.
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
# Handles <script> tags: removes them and returns true if a script node was processed.
|
25
|
-
def handle_script_node(node)
|
26
|
-
return false unless node.name == "script"
|
27
|
-
|
28
|
-
node.remove
|
29
|
-
true # Indicates the node was a script and has been handled.
|
30
|
-
end
|
31
|
-
|
32
|
-
# Checks if the node is a type that should bypass detailed attribute scrubbing.
|
33
|
-
def passthrough_node?(node)
|
34
|
-
(node.name == "link" && node["rel"]&.to_s&.downcase == "stylesheet") ||
|
35
|
-
%w[style meta].include?(node.name)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Orchestrates the cleaning of attributes for a given node.
|
39
|
-
def clean_attributes(node)
|
40
|
-
remove_javascript_href(node)
|
41
|
-
remove_event_handlers(node)
|
42
|
-
end
|
43
|
-
|
44
|
-
# Removes "javascript:" hrefs from <a> tags.
|
45
|
-
def remove_javascript_href(node)
|
46
|
-
if node.name == "a" &&
|
47
|
-
node["href"]&.to_s&.downcase&.start_with?("javascript:")
|
48
|
-
node.remove_attribute("href")
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Removes "on*" event handler attributes from any node.
|
53
|
-
def remove_event_handlers(node)
|
54
|
-
attrs_to_remove =
|
55
|
-
node.attributes.keys.select do |name|
|
56
|
-
name.to_s.downcase.start_with?("on")
|
57
|
-
end
|
58
|
-
attrs_to_remove.each { |attr_name| node.remove_attribute(attr_name) }
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|