wovnrb 3.11.0 → 3.11.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/wovnrb.rb CHANGED
@@ -1,145 +1,146 @@
1
- require 'rack'
2
- require 'wovnrb/api_translator'
3
- require 'wovnrb/headers'
4
- require 'wovnrb/store'
5
- require 'wovnrb/lang'
6
- require 'wovnrb/services/html_converter'
7
- require 'wovnrb/services/html_replace_marker'
8
- require 'wovnrb/url_language_switcher'
9
- require 'nokogiri'
10
- require 'active_support'
11
- require 'json'
12
- require 'wovnrb/helpers/nokogumbo_helper'
13
- require 'wovnrb/railtie' if defined?(Rails)
14
- require 'wovnrb/version'
15
-
16
- module Wovnrb
17
- class Interceptor
18
- def initialize(app, opts = {})
19
- @app = app
20
- @store = Store.instance
21
- opts = opts.transform_keys(&:to_s)
22
- @store.update_settings(opts)
23
- @url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(@store)
24
- end
25
-
26
- def call(env)
27
- # disabled by previous Rack middleware
28
- return @app.call(env) if Rack::Request.new(env).params['wovn_disable'] == true
29
-
30
- @store.settings.clear_dynamic_settings!
31
- return @app.call(env) unless Store.instance.valid_settings?
32
-
33
- @env = env
34
- headers = Headers.new(env, @store.settings, @url_lang_switcher)
35
- default_lang = @store.settings['default_lang']
36
- return @app.call(env) if @store.settings['test_mode'] && @store.settings['test_url'] != headers.url
37
-
38
- cookie_lang = Rack::Request.new(env).cookies['wovn_selected_lang']
39
- request_lang = headers.lang_code
40
- if @store.settings['use_cookie_lang'] && cookie_lang.present? && request_lang != cookie_lang && request_lang == @store.default_lang
41
- redirect_headers = headers.redirect(cookie_lang)
42
- return [302, redirect_headers, ['']]
43
- end
44
-
45
- # redirect if the path is set to the default language (for SEO purposes)
46
- if explicit_default_lang?(headers)
47
- redirect_headers = headers.redirect(default_lang)
48
- return [307, redirect_headers, ['']]
49
- end
50
-
51
- # if path containing language code is ignored, do nothing
52
- if headers.lang_code != default_lang && ignore_path?(headers.unmasked_pathname_without_trailing_slash)
53
- status, res_headers, body = @app.call(env)
54
-
55
- return output(headers, status, res_headers, body)
56
- end
57
- # pass to application
58
- status, res_headers, body = @app.call(headers.request_out)
59
-
60
- # disabled by next Rack middleware
61
- return output(headers, status, res_headers, body) unless res_headers['Content-Type']&.include?('html')
62
-
63
- request = Rack::Request.new(env)
64
-
65
- return output(headers, status, res_headers, body) if request.params['wovn_disable'] == true
66
-
67
- @store.settings.update_dynamic_settings!(request.params)
68
- return output(headers, status, res_headers, body) if ignore_path?(headers.pathname)
69
-
70
- body = switch_lang(headers, body) unless /^1|302/.match?(status.to_s)
71
-
72
- content_length = 0
73
- body.each { |b| content_length += b.respond_to?(:bytesize) ? b.bytesize : 0 }
74
- res_headers['Content-Length'] = content_length.to_s
75
-
76
- output(headers, status, res_headers, body)
77
- end
78
-
79
- def switch_lang(headers, body)
80
- translated_body = []
81
-
82
- # Must use `.each` for to support multiple-chunks in Sinatra
83
- string_body = ''
84
- body.each { |chunk| string_body += chunk }
85
- html_body = Helpers::NokogumboHelper.parse_html(string_body)
86
-
87
- if !wovn_ignored?(html_body) && !amp_page?(html_body)
88
-
89
- html_converter = HtmlConverter.new(html_body, @store, headers, @url_lang_switcher)
90
-
91
- if needs_api?(html_body, headers)
92
- converted_html, marker = html_converter.build_api_compatible_html
93
- translated_content = ApiTranslator.new(@store, headers, WovnLogger.uuid).translate(converted_html)
94
- translated_body.push(marker.revert(translated_content))
95
- else
96
- string_body = html_converter.build if html_body.html?
97
- translated_body.push(string_body)
98
- end
99
- else
100
- translated_body.push(string_body)
101
- end
102
-
103
- body.close if body.respond_to?(:close)
104
- translated_body
105
- end
106
-
107
- private
108
-
109
- def output(headers, status, res_headers, body)
110
- headers.out(res_headers)
111
- [status, res_headers, body]
112
- end
113
-
114
- def needs_api?(html_body, headers)
115
- headers.lang_code != @store.settings['default_lang'] &&
116
- (html_body.html? || @store.settings['translate_fragment'])
117
- end
118
-
119
- def wovn_ignored?(html_body)
120
- !html_body.xpath('//html[@wovn-ignore or @data-wovn-ignore]').empty?
121
- end
122
-
123
- def ignore_path?(path)
124
- @store.settings['ignore_globs'].ignore?(path)
125
- end
126
-
127
- # Checks if a given HTML body is an Accelerated Mobile Page (AMP).
128
- # To do so, it looks at the required attributes for the HTML tag:
129
- # https://www.ampproject.org/docs/tutorials/create/basic_markup.
130
- #
131
- # @param {Nokogiri::HTML5::Document} body The HTML body to check.
132
- #
133
- # @returns {Boolean} True is the HTML body is an AMP, false otherwise.
134
- def amp_page?(html_body)
135
- html_attributes = html_body.xpath('//html')[0].try(:attributes) || {}
136
-
137
- !!(html_attributes['amp'] || html_attributes["\u26A1"])
138
- end
139
-
140
- def explicit_default_lang?(headers)
141
- default_lang, url_pattern = @store.settings.values_at('default_lang', 'url_pattern')
142
- default_lang == headers.url_language && url_pattern != 'custom_domain'
143
- end
144
- end
145
- end
1
+ require 'rack'
2
+ require 'wovnrb/api_translator'
3
+ require 'wovnrb/headers'
4
+ require 'wovnrb/store'
5
+ require 'wovnrb/lang'
6
+ require 'wovnrb/services/html_converter'
7
+ require 'wovnrb/services/html_replace_marker'
8
+ require 'wovnrb/url_language_switcher'
9
+ require 'nokogiri'
10
+ require 'active_support'
11
+ require 'json'
12
+ require 'wovnrb/helpers/nokogumbo_helper'
13
+ require 'wovnrb/railtie' if defined?(Rails)
14
+ require 'wovnrb/version'
15
+
16
+ module Wovnrb
17
+ class Interceptor
18
+ def initialize(app, opts = {})
19
+ @app = app
20
+ @store = Store.instance
21
+ opts = opts.transform_keys(&:to_s)
22
+ @store.update_settings(opts)
23
+ @url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(@store)
24
+ end
25
+
26
+ def call(env)
27
+ # disabled by previous Rack middleware
28
+ request = Rack::Request.new(env)
29
+ return @app.call(env) if request.params['wovn_disable'] == true
30
+
31
+ @store.settings.clear_dynamic_settings!
32
+ return @app.call(env) unless Store.instance.valid_settings?
33
+
34
+ @env = env
35
+ headers = Headers.new(env, @store.settings, @url_lang_switcher)
36
+ default_lang = @store.settings['default_lang']
37
+ return @app.call(env) if @store.settings['test_mode'] && @store.settings['test_url'] != headers.url
38
+
39
+ cookie_lang = request.cookies['wovn_selected_lang']
40
+ request_lang = headers.lang_code
41
+ is_get_request = request.get?
42
+
43
+ if @store.settings['use_cookie_lang'] && cookie_lang.present? && request_lang != cookie_lang && request_lang == @store.default_lang && is_get_request
44
+ redirect_headers = headers.redirect(cookie_lang)
45
+ return [302, redirect_headers, ['']]
46
+ end
47
+
48
+ # redirect if the path is set to the default language (for SEO purposes)
49
+ if explicit_default_lang?(headers) && is_get_request
50
+ redirect_headers = headers.redirect(default_lang)
51
+ return [307, redirect_headers, ['']]
52
+ end
53
+
54
+ # if path containing language code is ignored, do nothing
55
+ if headers.lang_code != default_lang && ignore_path?(headers.unmasked_pathname_without_trailing_slash)
56
+ status, res_headers, body = @app.call(env)
57
+
58
+ return output(headers, status, res_headers, body)
59
+ end
60
+ # pass to application
61
+ status, res_headers, body = @app.call(headers.request_out)
62
+
63
+ # disabled by next Rack middleware
64
+ return output(headers, status, res_headers, body) unless res_headers['Content-Type']&.include?('html')
65
+
66
+ return output(headers, status, res_headers, body) if request.params['wovn_disable'] == true
67
+
68
+ @store.settings.update_dynamic_settings!(request.params)
69
+ return output(headers, status, res_headers, body) if ignore_path?(headers.pathname)
70
+
71
+ body = switch_lang(headers, body) unless /^1|302/.match?(status.to_s)
72
+
73
+ content_length = 0
74
+ body.each { |b| content_length += b.respond_to?(:bytesize) ? b.bytesize : 0 }
75
+ res_headers['Content-Length'] = content_length.to_s
76
+
77
+ output(headers, status, res_headers, body)
78
+ end
79
+
80
+ def switch_lang(headers, body)
81
+ translated_body = []
82
+
83
+ # Must use `.each` for to support multiple-chunks in Sinatra
84
+ string_body = ''
85
+ body.each { |chunk| string_body += chunk }
86
+ html_body = Helpers::NokogumboHelper.parse_html(string_body)
87
+
88
+ if !wovn_ignored?(html_body) && !amp_page?(html_body)
89
+
90
+ html_converter = HtmlConverter.new(html_body, @store, headers, @url_lang_switcher)
91
+
92
+ if needs_api?(html_body, headers)
93
+ converted_html, marker = html_converter.build_api_compatible_html
94
+ translated_content = ApiTranslator.new(@store, headers, WovnLogger.uuid).translate(converted_html)
95
+ translated_body.push(marker.revert(translated_content))
96
+ else
97
+ string_body = html_converter.build if html_body.html?
98
+ translated_body.push(string_body)
99
+ end
100
+ else
101
+ translated_body.push(string_body)
102
+ end
103
+
104
+ body.close if body.respond_to?(:close)
105
+ translated_body
106
+ end
107
+
108
+ private
109
+
110
+ def output(headers, status, res_headers, body)
111
+ headers.out(res_headers)
112
+ [status, res_headers, body]
113
+ end
114
+
115
+ def needs_api?(html_body, headers)
116
+ headers.lang_code != @store.settings['default_lang'] &&
117
+ (html_body.html? || @store.settings['translate_fragment'])
118
+ end
119
+
120
+ def wovn_ignored?(html_body)
121
+ !html_body.xpath('//html[@wovn-ignore or @data-wovn-ignore]').empty?
122
+ end
123
+
124
+ def ignore_path?(path)
125
+ @store.settings['ignore_globs'].ignore?(path)
126
+ end
127
+
128
+ # Checks if a given HTML body is an Accelerated Mobile Page (AMP).
129
+ # To do so, it looks at the required attributes for the HTML tag:
130
+ # https://www.ampproject.org/docs/tutorials/create/basic_markup.
131
+ #
132
+ # @param {Nokogiri::HTML5::Document} body The HTML body to check.
133
+ #
134
+ # @returns {Boolean} True is the HTML body is an AMP, false otherwise.
135
+ def amp_page?(html_body)
136
+ html_attributes = html_body.xpath('//html')[0].try(:attributes) || {}
137
+
138
+ !!(html_attributes['amp'] || html_attributes["\u26A1"])
139
+ end
140
+
141
+ def explicit_default_lang?(headers)
142
+ default_lang, url_pattern = @store.settings.values_at('default_lang', 'url_pattern')
143
+ default_lang == headers.url_language && url_pattern != 'custom_domain'
144
+ end
145
+ end
146
+ end