jekyll 4.0.1 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +350 -163
  3. data/LICENSE +21 -21
  4. data/README.markdown +86 -90
  5. data/exe/jekyll +57 -57
  6. data/lib/blank_template/_config.yml +3 -3
  7. data/lib/blank_template/_layouts/default.html +12 -12
  8. data/lib/blank_template/_sass/main.scss +9 -9
  9. data/lib/blank_template/assets/css/main.scss +4 -4
  10. data/lib/blank_template/index.md +8 -8
  11. data/lib/jekyll/cache.rb +190 -190
  12. data/lib/jekyll/cleaner.rb +111 -111
  13. data/lib/jekyll/collection.rb +309 -309
  14. data/lib/jekyll/command.rb +105 -103
  15. data/lib/jekyll/commands/build.rb +93 -93
  16. data/lib/jekyll/commands/clean.rb +45 -45
  17. data/lib/jekyll/commands/doctor.rb +177 -173
  18. data/lib/jekyll/commands/help.rb +34 -34
  19. data/lib/jekyll/commands/new.rb +169 -169
  20. data/lib/jekyll/commands/new_theme.rb +40 -42
  21. data/lib/jekyll/commands/serve/live_reload_reactor.rb +122 -122
  22. data/lib/jekyll/commands/serve/livereload_assets/livereload.js +1183 -1183
  23. data/lib/jekyll/commands/serve/servlet.rb +202 -202
  24. data/lib/jekyll/commands/serve/websockets.rb +81 -81
  25. data/lib/jekyll/commands/serve.rb +362 -354
  26. data/lib/jekyll/configuration.rb +313 -316
  27. data/lib/jekyll/converter.rb +54 -54
  28. data/lib/jekyll/converters/identity.rb +41 -41
  29. data/lib/jekyll/converters/markdown/kramdown_parser.rb +199 -130
  30. data/lib/jekyll/converters/markdown.rb +113 -113
  31. data/lib/jekyll/converters/smartypants.rb +70 -70
  32. data/lib/jekyll/convertible.rb +257 -254
  33. data/lib/jekyll/deprecator.rb +50 -50
  34. data/lib/jekyll/document.rb +544 -522
  35. data/lib/jekyll/drops/collection_drop.rb +20 -20
  36. data/lib/jekyll/drops/document_drop.rb +70 -69
  37. data/lib/jekyll/drops/drop.rb +293 -215
  38. data/lib/jekyll/drops/excerpt_drop.rb +19 -19
  39. data/lib/jekyll/drops/jekyll_drop.rb +32 -32
  40. data/lib/jekyll/drops/site_drop.rb +66 -66
  41. data/lib/jekyll/drops/static_file_drop.rb +14 -14
  42. data/lib/jekyll/drops/unified_payload_drop.rb +26 -26
  43. data/lib/jekyll/drops/url_drop.rb +140 -132
  44. data/lib/jekyll/entry_filter.rb +121 -110
  45. data/lib/jekyll/errors.rb +20 -20
  46. data/lib/jekyll/excerpt.rb +201 -201
  47. data/lib/jekyll/external.rb +79 -79
  48. data/lib/jekyll/filters/date_filters.rb +110 -110
  49. data/lib/jekyll/filters/grouping_filters.rb +64 -64
  50. data/lib/jekyll/filters/url_filters.rb +98 -68
  51. data/lib/jekyll/filters.rb +535 -454
  52. data/lib/jekyll/frontmatter_defaults.rb +240 -245
  53. data/lib/jekyll/generator.rb +5 -5
  54. data/lib/jekyll/hooks.rb +107 -106
  55. data/lib/jekyll/inclusion.rb +32 -0
  56. data/lib/jekyll/layout.rb +67 -62
  57. data/lib/jekyll/liquid_extensions.rb +22 -22
  58. data/lib/jekyll/liquid_renderer/file.rb +77 -77
  59. data/lib/jekyll/liquid_renderer/table.rb +55 -75
  60. data/lib/jekyll/liquid_renderer.rb +80 -77
  61. data/lib/jekyll/log_adapter.rb +151 -151
  62. data/lib/jekyll/mime.types +866 -866
  63. data/lib/jekyll/page.rb +217 -186
  64. data/lib/jekyll/page_excerpt.rb +25 -0
  65. data/lib/jekyll/page_without_a_file.rb +14 -14
  66. data/lib/jekyll/path_manager.rb +74 -31
  67. data/lib/jekyll/plugin.rb +92 -92
  68. data/lib/jekyll/plugin_manager.rb +115 -115
  69. data/lib/jekyll/profiler.rb +58 -0
  70. data/lib/jekyll/publisher.rb +23 -23
  71. data/lib/jekyll/reader.rb +192 -187
  72. data/lib/jekyll/readers/collection_reader.rb +23 -22
  73. data/lib/jekyll/readers/data_reader.rb +79 -75
  74. data/lib/jekyll/readers/layout_reader.rb +62 -61
  75. data/lib/jekyll/readers/page_reader.rb +25 -24
  76. data/lib/jekyll/readers/post_reader.rb +85 -84
  77. data/lib/jekyll/readers/static_file_reader.rb +25 -24
  78. data/lib/jekyll/readers/theme_assets_reader.rb +52 -51
  79. data/lib/jekyll/regenerator.rb +195 -195
  80. data/lib/jekyll/related_posts.rb +52 -52
  81. data/lib/jekyll/renderer.rb +265 -267
  82. data/lib/jekyll/site.rb +551 -527
  83. data/lib/jekyll/static_file.rb +208 -203
  84. data/lib/jekyll/stevenson.rb +60 -60
  85. data/lib/jekyll/tags/highlight.rb +110 -110
  86. data/lib/jekyll/tags/include.rb +275 -221
  87. data/lib/jekyll/tags/link.rb +42 -41
  88. data/lib/jekyll/tags/post_url.rb +106 -107
  89. data/lib/jekyll/theme.rb +86 -80
  90. data/lib/jekyll/theme_builder.rb +121 -121
  91. data/lib/jekyll/url.rb +167 -164
  92. data/lib/jekyll/utils/ansi.rb +57 -57
  93. data/lib/jekyll/utils/exec.rb +26 -26
  94. data/lib/jekyll/utils/internet.rb +37 -37
  95. data/lib/jekyll/utils/platforms.rb +67 -82
  96. data/lib/jekyll/utils/thread_event.rb +31 -31
  97. data/lib/jekyll/utils/win_tz.rb +75 -75
  98. data/lib/jekyll/utils.rb +367 -367
  99. data/lib/jekyll/version.rb +5 -5
  100. data/lib/jekyll.rb +195 -206
  101. data/lib/site_template/.gitignore +5 -5
  102. data/lib/site_template/404.html +25 -25
  103. data/lib/site_template/_config.yml +55 -55
  104. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -29
  105. data/lib/site_template/about.markdown +18 -18
  106. data/lib/site_template/index.markdown +6 -6
  107. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -74
  108. data/lib/theme_template/Gemfile +4 -4
  109. data/lib/theme_template/LICENSE.txt.erb +21 -21
  110. data/lib/theme_template/README.md.erb +52 -52
  111. data/lib/theme_template/_layouts/default.html +1 -1
  112. data/lib/theme_template/_layouts/page.html +5 -5
  113. data/lib/theme_template/_layouts/post.html +5 -5
  114. data/lib/theme_template/example/_config.yml.erb +1 -1
  115. data/lib/theme_template/example/_post.md +12 -12
  116. data/lib/theme_template/example/index.html +14 -14
  117. data/lib/theme_template/example/style.scss +7 -7
  118. data/lib/theme_template/gitignore.erb +6 -6
  119. data/lib/theme_template/theme.gemspec.erb +16 -19
  120. data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -149
  121. data/rubocop/jekyll/no_p_allowed.rb +23 -23
  122. data/rubocop/jekyll/no_puts_allowed.rb +23 -23
  123. data/rubocop/jekyll.rb +5 -5
  124. metadata +20 -38
@@ -1,202 +1,202 @@
1
- # frozen_string_literal: true
2
-
3
- require "webrick"
4
-
5
- module Jekyll
6
- module Commands
7
- class Serve
8
- # This class is used to determine if the Servlet should modify a served file
9
- # to insert the LiveReload script tags
10
- class SkipAnalyzer
11
- BAD_USER_AGENTS = [%r!MSIE!].freeze
12
-
13
- def self.skip_processing?(request, response, options)
14
- new(request, response, options).skip_processing?
15
- end
16
-
17
- def initialize(request, response, options)
18
- @options = options
19
- @request = request
20
- @response = response
21
- end
22
-
23
- def skip_processing?
24
- !html? || chunked? || inline? || bad_browser?
25
- end
26
-
27
- def chunked?
28
- @response["Transfer-Encoding"] == "chunked"
29
- end
30
-
31
- def inline?
32
- @response["Content-Disposition"].to_s.start_with?("inline")
33
- end
34
-
35
- def bad_browser?
36
- BAD_USER_AGENTS.any? { |pattern| pattern.match?(@request["User-Agent"]) }
37
- end
38
-
39
- def html?
40
- @response["Content-Type"].to_s.include?("text/html")
41
- end
42
- end
43
-
44
- # This class inserts the LiveReload script tags into HTML as it is served
45
- class BodyProcessor
46
- HEAD_TAG_REGEX = %r!<head>|<head[^(er)][^<]*>!.freeze
47
-
48
- attr_reader :content_length, :new_body, :livereload_added
49
-
50
- def initialize(body, options)
51
- @body = body
52
- @options = options
53
- @processed = false
54
- end
55
-
56
- def processed?
57
- @processed
58
- end
59
-
60
- # rubocop:disable Metrics/MethodLength
61
- def process!
62
- @new_body = []
63
- # @body will usually be a File object but Strings occur in rare cases
64
- if @body.respond_to?(:each)
65
- begin
66
- @body.each { |line| @new_body << line.to_s }
67
- ensure
68
- @body.close
69
- end
70
- else
71
- @new_body = @body.lines
72
- end
73
-
74
- @content_length = 0
75
- @livereload_added = false
76
-
77
- @new_body.each do |line|
78
- if !@livereload_added && line["<head"]
79
- line.gsub!(HEAD_TAG_REGEX) do |match|
80
- %(#{match}#{template.result(binding)})
81
- end
82
-
83
- @livereload_added = true
84
- end
85
-
86
- @content_length += line.bytesize
87
- @processed = true
88
- end
89
- @new_body = @new_body.join
90
- end
91
- # rubocop:enable Metrics/MethodLength
92
-
93
- def template
94
- # Unclear what "snipver" does. Doc at
95
- # https://github.com/livereload/livereload-js states that the recommended
96
- # setting is 1.
97
-
98
- # Complicated JavaScript to ensure that livereload.js is loaded from the
99
- # same origin as the page. Mostly useful for dealing with the browser's
100
- # distinction between 'localhost' and 127.0.0.1
101
- @template ||= ERB.new(<<~TEMPLATE)
102
- <script>
103
- document.write(
104
- '<script src="http://' +
105
- (location.host || 'localhost').split(':')[0] +
106
- ':<%=@options["livereload_port"] %>/livereload.js?snipver=1<%= livereload_args %>"' +
107
- '></' +
108
- 'script>');
109
- </script>
110
- TEMPLATE
111
- end
112
-
113
- def livereload_args
114
- # XHTML standard requires ampersands to be encoded as entities when in
115
- # attributes. See http://stackoverflow.com/a/2190292
116
- src = ""
117
- if @options["livereload_min_delay"]
118
- src += "&amp;mindelay=#{@options["livereload_min_delay"]}"
119
- end
120
- if @options["livereload_max_delay"]
121
- src += "&amp;maxdelay=#{@options["livereload_max_delay"]}"
122
- end
123
- src += "&amp;port=#{@options["livereload_port"]}" if @options["livereload_port"]
124
- src
125
- end
126
- end
127
-
128
- class Servlet < WEBrick::HTTPServlet::FileHandler
129
- DEFAULTS = {
130
- "Cache-Control" => "private, max-age=0, proxy-revalidate, " \
131
- "no-store, no-cache, must-revalidate",
132
- }.freeze
133
-
134
- def initialize(server, root, callbacks)
135
- # So we can access them easily.
136
- @jekyll_opts = server.config[:JekyllOptions]
137
- set_defaults
138
- super
139
- end
140
-
141
- def search_index_file(req, res)
142
- super ||
143
- search_file(req, res, ".html") ||
144
- search_file(req, res, ".xhtml")
145
- end
146
-
147
- # Add the ability to tap file.html the same way that Nginx does on our
148
- # Docker images (or on GitHub Pages.) The difference is that we might end
149
- # up with a different preference on which comes first.
150
-
151
- def search_file(req, res, basename)
152
- # /file.* > /file/index.html > /file.html
153
- super ||
154
- super(req, res, "#{basename}.html") ||
155
- super(req, res, "#{basename}.xhtml")
156
- end
157
-
158
- # rubocop:disable Naming/MethodName
159
- def do_GET(req, res)
160
- rtn = super
161
-
162
- if @jekyll_opts["livereload"]
163
- return rtn if SkipAnalyzer.skip_processing?(req, res, @jekyll_opts)
164
-
165
- processor = BodyProcessor.new(res.body, @jekyll_opts)
166
- processor.process!
167
- res.body = processor.new_body
168
- res.content_length = processor.content_length.to_s
169
-
170
- if processor.livereload_added
171
- # Add a header to indicate that the page content has been modified
172
- res["X-Rack-LiveReload"] = "1"
173
- end
174
- end
175
-
176
- validate_and_ensure_charset(req, res)
177
- res.header.merge!(@headers)
178
- rtn
179
- end
180
- # rubocop:enable Naming/MethodName
181
-
182
- private
183
-
184
- def validate_and_ensure_charset(_req, res)
185
- key = res.header.keys.grep(%r!content-type!i).first
186
- typ = res.header[key]
187
-
188
- unless %r!;\s*charset=!.match?(typ)
189
- res.header[key] = "#{typ}; charset=#{@jekyll_opts["encoding"]}"
190
- end
191
- end
192
-
193
- def set_defaults
194
- hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {})
195
- DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash|
196
- hash[key] = val unless hash.key?(key)
197
- end
198
- end
199
- end
200
- end
201
- end
202
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "webrick"
4
+
5
+ module Jekyll
6
+ module Commands
7
+ class Serve
8
+ # This class is used to determine if the Servlet should modify a served file
9
+ # to insert the LiveReload script tags
10
+ class SkipAnalyzer
11
+ BAD_USER_AGENTS = [%r!MSIE!].freeze
12
+
13
+ def self.skip_processing?(request, response, options)
14
+ new(request, response, options).skip_processing?
15
+ end
16
+
17
+ def initialize(request, response, options)
18
+ @options = options
19
+ @request = request
20
+ @response = response
21
+ end
22
+
23
+ def skip_processing?
24
+ !html? || chunked? || inline? || bad_browser?
25
+ end
26
+
27
+ def chunked?
28
+ @response["Transfer-Encoding"] == "chunked"
29
+ end
30
+
31
+ def inline?
32
+ @response["Content-Disposition"].to_s.start_with?("inline")
33
+ end
34
+
35
+ def bad_browser?
36
+ BAD_USER_AGENTS.any? { |pattern| pattern.match?(@request["User-Agent"]) }
37
+ end
38
+
39
+ def html?
40
+ @response["Content-Type"].to_s.include?("text/html")
41
+ end
42
+ end
43
+
44
+ # This class inserts the LiveReload script tags into HTML as it is served
45
+ class BodyProcessor
46
+ HEAD_TAG_REGEX = %r!<head>|<head[^(er)][^<]*>!.freeze
47
+
48
+ attr_reader :content_length, :new_body, :livereload_added
49
+
50
+ def initialize(body, options)
51
+ @body = body
52
+ @options = options
53
+ @processed = false
54
+ end
55
+
56
+ def processed?
57
+ @processed
58
+ end
59
+
60
+ # rubocop:disable Metrics/MethodLength
61
+ def process!
62
+ @new_body = []
63
+ # @body will usually be a File object but Strings occur in rare cases
64
+ if @body.respond_to?(:each)
65
+ begin
66
+ @body.each { |line| @new_body << line.to_s }
67
+ ensure
68
+ @body.close
69
+ end
70
+ else
71
+ @new_body = @body.lines
72
+ end
73
+
74
+ @content_length = 0
75
+ @livereload_added = false
76
+
77
+ @new_body.each do |line|
78
+ if !@livereload_added && line["<head"]
79
+ line.gsub!(HEAD_TAG_REGEX) do |match|
80
+ %(#{match}#{template.result(binding)})
81
+ end
82
+
83
+ @livereload_added = true
84
+ end
85
+
86
+ @content_length += line.bytesize
87
+ @processed = true
88
+ end
89
+ @new_body = @new_body.join
90
+ end
91
+ # rubocop:enable Metrics/MethodLength
92
+
93
+ def template
94
+ # Unclear what "snipver" does. Doc at
95
+ # https://github.com/livereload/livereload-js states that the recommended
96
+ # setting is 1.
97
+
98
+ # Complicated JavaScript to ensure that livereload.js is loaded from the
99
+ # same origin as the page. Mostly useful for dealing with the browser's
100
+ # distinction between 'localhost' and 127.0.0.1
101
+ @template ||= ERB.new(<<~TEMPLATE)
102
+ <script>
103
+ document.write(
104
+ '<script src="http://' +
105
+ (location.host || 'localhost').split(':')[0] +
106
+ ':<%=@options["livereload_port"] %>/livereload.js?snipver=1<%= livereload_args %>"' +
107
+ '></' +
108
+ 'script>');
109
+ </script>
110
+ TEMPLATE
111
+ end
112
+
113
+ def livereload_args
114
+ # XHTML standard requires ampersands to be encoded as entities when in
115
+ # attributes. See http://stackoverflow.com/a/2190292
116
+ src = ""
117
+ if @options["livereload_min_delay"]
118
+ src += "&amp;mindelay=#{@options["livereload_min_delay"]}"
119
+ end
120
+ if @options["livereload_max_delay"]
121
+ src += "&amp;maxdelay=#{@options["livereload_max_delay"]}"
122
+ end
123
+ src += "&amp;port=#{@options["livereload_port"]}" if @options["livereload_port"]
124
+ src
125
+ end
126
+ end
127
+
128
+ class Servlet < WEBrick::HTTPServlet::FileHandler
129
+ DEFAULTS = {
130
+ "Cache-Control" => "private, max-age=0, proxy-revalidate, " \
131
+ "no-store, no-cache, must-revalidate",
132
+ }.freeze
133
+
134
+ def initialize(server, root, callbacks)
135
+ # So we can access them easily.
136
+ @jekyll_opts = server.config[:JekyllOptions]
137
+ set_defaults
138
+ super
139
+ end
140
+
141
+ def search_index_file(req, res)
142
+ super ||
143
+ search_file(req, res, ".html") ||
144
+ search_file(req, res, ".xhtml")
145
+ end
146
+
147
+ # Add the ability to tap file.html the same way that Nginx does on our
148
+ # Docker images (or on GitHub Pages.) The difference is that we might end
149
+ # up with a different preference on which comes first.
150
+
151
+ def search_file(req, res, basename)
152
+ # /file.* > /file/index.html > /file.html
153
+ super ||
154
+ super(req, res, "#{basename}.html") ||
155
+ super(req, res, "#{basename}.xhtml")
156
+ end
157
+
158
+ # rubocop:disable Naming/MethodName
159
+ def do_GET(req, res)
160
+ rtn = super
161
+
162
+ if @jekyll_opts["livereload"]
163
+ return rtn if SkipAnalyzer.skip_processing?(req, res, @jekyll_opts)
164
+
165
+ processor = BodyProcessor.new(res.body, @jekyll_opts)
166
+ processor.process!
167
+ res.body = processor.new_body
168
+ res.content_length = processor.content_length.to_s
169
+
170
+ if processor.livereload_added
171
+ # Add a header to indicate that the page content has been modified
172
+ res["X-Rack-LiveReload"] = "1"
173
+ end
174
+ end
175
+
176
+ validate_and_ensure_charset(req, res)
177
+ res.header.merge!(@headers)
178
+ rtn
179
+ end
180
+ # rubocop:enable Naming/MethodName
181
+
182
+ private
183
+
184
+ def validate_and_ensure_charset(_req, res)
185
+ key = res.header.keys.grep(%r!content-type!i).first
186
+ typ = res.header[key]
187
+
188
+ unless %r!;\s*charset=!.match?(typ)
189
+ res.header[key] = "#{typ}; charset=#{@jekyll_opts["encoding"]}"
190
+ end
191
+ end
192
+
193
+ def set_defaults
194
+ hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {})
195
+ DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash|
196
+ hash[key] = val unless hash.key?(key)
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
@@ -1,81 +1,81 @@
1
- # frozen_string_literal: true
2
-
3
- require "http/parser"
4
-
5
- module Jekyll
6
- module Commands
7
- class Serve
8
- # The LiveReload protocol requires the server to serve livereload.js over HTTP
9
- # despite the fact that the protocol itself uses WebSockets. This custom connection
10
- # class addresses the dual protocols that the server needs to understand.
11
- class HttpAwareConnection < EventMachine::WebSocket::Connection
12
- attr_reader :reload_body, :reload_size
13
-
14
- def initialize(_opts)
15
- # If EventMachine SSL support on Windows ever gets better, the code below will
16
- # set up the reactor to handle SSL
17
- #
18
- # @ssl_enabled = opts["ssl_cert"] && opts["ssl_key"]
19
- # if @ssl_enabled
20
- # em_opts[:tls_options] = {
21
- # :private_key_file => Jekyll.sanitized_path(opts["source"], opts["ssl_key"]),
22
- # :cert_chain_file => Jekyll.sanitized_path(opts["source"], opts["ssl_cert"])
23
- # }
24
- # em_opts[:secure] = true
25
- # end
26
-
27
- # This is too noisy even for --verbose, but uncomment if you need it for
28
- # a specific WebSockets issue. Adding ?LR-verbose=true onto the URL will
29
- # enable logging on the client side.
30
- # em_opts[:debug] = true
31
-
32
- em_opts = {}
33
- super(em_opts)
34
-
35
- reload_file = File.join(Serve.singleton_class::LIVERELOAD_DIR, "livereload.js")
36
-
37
- @reload_body = File.read(reload_file)
38
- @reload_size = @reload_body.bytesize
39
- end
40
-
41
- # rubocop:disable Metrics/MethodLength
42
- def dispatch(data)
43
- parser = Http::Parser.new
44
- parser << data
45
-
46
- # WebSockets requests will have a Connection: Upgrade header
47
- if parser.http_method != "GET" || parser.upgrade?
48
- super
49
- elsif parser.request_url.start_with?("/livereload.js")
50
- headers = [
51
- "HTTP/1.1 200 OK",
52
- "Content-Type: application/javascript",
53
- "Content-Length: #{reload_size}",
54
- "",
55
- "",
56
- ].join("\r\n")
57
- send_data(headers)
58
-
59
- # stream_file_data would free us from keeping livereload.js in memory
60
- # but JRuby blocks on that call and never returns
61
- send_data(reload_body)
62
- close_connection_after_writing
63
- else
64
- body = "This port only serves livereload.js over HTTP.\n"
65
- headers = [
66
- "HTTP/1.1 400 Bad Request",
67
- "Content-Type: text/plain",
68
- "Content-Length: #{body.bytesize}",
69
- "",
70
- "",
71
- ].join("\r\n")
72
- send_data(headers)
73
- send_data(body)
74
- close_connection_after_writing
75
- end
76
- end
77
- # rubocop:enable Metrics/MethodLength
78
- end
79
- end
80
- end
81
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "http/parser"
4
+
5
+ module Jekyll
6
+ module Commands
7
+ class Serve
8
+ # The LiveReload protocol requires the server to serve livereload.js over HTTP
9
+ # despite the fact that the protocol itself uses WebSockets. This custom connection
10
+ # class addresses the dual protocols that the server needs to understand.
11
+ class HttpAwareConnection < EventMachine::WebSocket::Connection
12
+ attr_reader :reload_body, :reload_size
13
+
14
+ def initialize(_opts)
15
+ # If EventMachine SSL support on Windows ever gets better, the code below will
16
+ # set up the reactor to handle SSL
17
+ #
18
+ # @ssl_enabled = opts["ssl_cert"] && opts["ssl_key"]
19
+ # if @ssl_enabled
20
+ # em_opts[:tls_options] = {
21
+ # :private_key_file => Jekyll.sanitized_path(opts["source"], opts["ssl_key"]),
22
+ # :cert_chain_file => Jekyll.sanitized_path(opts["source"], opts["ssl_cert"])
23
+ # }
24
+ # em_opts[:secure] = true
25
+ # end
26
+
27
+ # This is too noisy even for --verbose, but uncomment if you need it for
28
+ # a specific WebSockets issue. Adding ?LR-verbose=true onto the URL will
29
+ # enable logging on the client side.
30
+ # em_opts[:debug] = true
31
+
32
+ em_opts = {}
33
+ super(em_opts)
34
+
35
+ reload_file = File.join(Serve.singleton_class::LIVERELOAD_DIR, "livereload.js")
36
+
37
+ @reload_body = File.read(reload_file)
38
+ @reload_size = @reload_body.bytesize
39
+ end
40
+
41
+ # rubocop:disable Metrics/MethodLength
42
+ def dispatch(data)
43
+ parser = Http::Parser.new
44
+ parser << data
45
+
46
+ # WebSockets requests will have a Connection: Upgrade header
47
+ if parser.http_method != "GET" || parser.upgrade?
48
+ super
49
+ elsif parser.request_url.start_with?("/livereload.js")
50
+ headers = [
51
+ "HTTP/1.1 200 OK",
52
+ "Content-Type: application/javascript",
53
+ "Content-Length: #{reload_size}",
54
+ "",
55
+ "",
56
+ ].join("\r\n")
57
+ send_data(headers)
58
+
59
+ # stream_file_data would free us from keeping livereload.js in memory
60
+ # but JRuby blocks on that call and never returns
61
+ send_data(reload_body)
62
+ close_connection_after_writing
63
+ else
64
+ body = "This port only serves livereload.js over HTTP.\n"
65
+ headers = [
66
+ "HTTP/1.1 400 Bad Request",
67
+ "Content-Type: text/plain",
68
+ "Content-Length: #{body.bytesize}",
69
+ "",
70
+ "",
71
+ ].join("\r\n")
72
+ send_data(headers)
73
+ send_data(body)
74
+ close_connection_after_writing
75
+ end
76
+ end
77
+ # rubocop:enable Metrics/MethodLength
78
+ end
79
+ end
80
+ end
81
+ end