82 lines
2.8 KiB
Ruby
82 lines
2.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "http/parser"
|
|
|
|
module Jekyll
|
|
module Commands
|
|
class Serve
|
|
# The LiveReload protocol requires the server to serve livereload.js over HTTP
|
|
# despite the fact that the protocol itself uses WebSockets. This custom connection
|
|
# class addresses the dual protocols that the server needs to understand.
|
|
class HttpAwareConnection < EventMachine::WebSocket::Connection
|
|
attr_reader :reload_body, :reload_size
|
|
|
|
def initialize(_opts)
|
|
# If EventMachine SSL support on Windows ever gets better, the code below will
|
|
# set up the reactor to handle SSL
|
|
#
|
|
# @ssl_enabled = opts["ssl_cert"] && opts["ssl_key"]
|
|
# if @ssl_enabled
|
|
# em_opts[:tls_options] = {
|
|
# :private_key_file => Jekyll.sanitized_path(opts["source"], opts["ssl_key"]),
|
|
# :cert_chain_file => Jekyll.sanitized_path(opts["source"], opts["ssl_cert"])
|
|
# }
|
|
# em_opts[:secure] = true
|
|
# end
|
|
|
|
# This is too noisy even for --verbose, but uncomment if you need it for
|
|
# a specific WebSockets issue. Adding ?LR-verbose=true onto the URL will
|
|
# enable logging on the client side.
|
|
# em_opts[:debug] = true
|
|
|
|
em_opts = {}
|
|
super(em_opts)
|
|
|
|
reload_file = File.join(Serve.singleton_class::LIVERELOAD_DIR, "livereload.js")
|
|
|
|
@reload_body = File.read(reload_file)
|
|
@reload_size = @reload_body.bytesize
|
|
end
|
|
|
|
# rubocop:disable Metrics/MethodLength
|
|
def dispatch(data)
|
|
parser = Http::Parser.new
|
|
parser << data
|
|
|
|
# WebSockets requests will have a Connection: Upgrade header
|
|
if parser.http_method != "GET" || parser.upgrade?
|
|
super
|
|
elsif parser.request_url.start_with?("/livereload.js")
|
|
headers = [
|
|
"HTTP/1.1 200 OK",
|
|
"Content-Type: application/javascript",
|
|
"Content-Length: #{reload_size}",
|
|
"",
|
|
"",
|
|
].join("\r\n")
|
|
send_data(headers)
|
|
|
|
# stream_file_data would free us from keeping livereload.js in memory
|
|
# but JRuby blocks on that call and never returns
|
|
send_data(reload_body)
|
|
close_connection_after_writing
|
|
else
|
|
body = "This port only serves livereload.js over HTTP.\n"
|
|
headers = [
|
|
"HTTP/1.1 400 Bad Request",
|
|
"Content-Type: text/plain",
|
|
"Content-Length: #{body.bytesize}",
|
|
"",
|
|
"",
|
|
].join("\r\n")
|
|
send_data(headers)
|
|
send_data(body)
|
|
close_connection_after_writing
|
|
end
|
|
end
|
|
# rubocop:enable Metrics/MethodLength
|
|
end
|
|
end
|
|
end
|
|
end
|