Class: ShopifyCLI::Theme::DevServer::WebServer

Inherits:
WEBrick::HTTPServlet::AbstractServlet
  • Object
show all
Defined in:
lib/shopify_cli/theme/dev_server/web_server.rb

Overview

Base on Rack::Handler::WEBrick

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server, app) ⇒ WebServer

Returns a new instance of WebServer.



65
66
67
68
# File 'lib/shopify_cli/theme/dev_server/web_server.rb', line 65

def initialize(server, app)
  super(server)
  @app = app
end

Class Method Details

.run(app, **options) {|@server| ... } ⇒ Object

Yields:

  • (@server)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/shopify_cli/theme/dev_server/web_server.rb', line 29

def self.run(app, **options)
  environment  = ENV["RACK_ENV"] || "development"
  default_host = environment == "development" ? "localhost" : nil

  if !options[:BindAddress] || options[:Host]
    options[:BindAddress] = options.delete(:Host) || default_host
  end
  options[:Port] ||= 8080
  if options[:SSLEnable]
    require "webrick/https"
  end

  @server = ::WEBrick::HTTPServer.new(options)
  @server.extend(WEBrickGenericServerThreadJoinWithTimeout)
  @server.mount("/", WebServer, app)
  yield @server if block_given?
  @server.start
end

.shutdownObject



58
59
60
61
62
63
# File 'lib/shopify_cli/theme/dev_server/web_server.rb', line 58

def self.shutdown
  if @server
    @server.shutdown
    @server = nil
  end
end

.valid_optionsObject



48
49
50
51
52
53
54
55
56
# File 'lib/shopify_cli/theme/dev_server/web_server.rb', line 48

def self.valid_options
  environment  = ENV["RACK_ENV"] || "development"
  default_host = environment == "development" ? "localhost" : "0.0.0.0"

  {
    "Host=HOST" => "Hostname to listen on (default: #{default_host})",
    "Port=PORT" => "Port to listen on (default: 8080)",
  }
end

Instance Method Details

#service(req, res) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/shopify_cli/theme/dev_server/web_server.rb', line 70

def service(req, res)
  # res.rack = true
  env = req.meta_vars
  env.delete_if { |_k, v| v.nil? }

  rack_input = StringIO.new(req.body.to_s)
  rack_input.set_encoding(Encoding::BINARY)

  env.update(
    "rack.version"      => [1, 3],
    "rack.input"        => rack_input,
    "rack.errors"       => $stderr,
    "rack.multithread"  => true,
    "rack.multiprocess" => false,
    "rack.run_once"     => false,
    "rack.url_scheme"   => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http",
    "rack.hijack?"      => true,
    "rack.hijack"       => lambda { raise NotImplementedError, "only partial hijack is supported." },
    "rack.hijack_io"    => nil
  )

  env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
  env["QUERY_STRING"] ||= ""
  unless env["PATH_INFO"] == ""
    path = req.request_uri.path
    n = env["SCRIPT_NAME"].length
    env["PATH_INFO"] = path[n, path.length - n]
  end
  env["REQUEST_PATH"] ||= [env["SCRIPT_NAME"], env["PATH_INFO"]].join

  status, headers, body = @app.call(env)

  res.status = status.to_i
  io_lambda = nil
  headers.each do |k, vs|
    if k == "rack.hijack"
      io_lambda = vs
    elsif k == "webrick.chunked"
      res.chunked = true
    elsif k.downcase == "set-cookie"
      res.cookies.concat(vs.split("\n"))
    else
      # Since WEBrick won't accept repeated headers,
      # merge the values per RFC 1945 section 4.2.
      res[k] = vs.split("\n").join(", ")
    end
  end

  if io_lambda
    rd, wr = IO.pipe
    res.body = rd
    res.chunked = true
    io_lambda.call(wr)
    body.close if body.respond_to?(:close)
  elsif body.respond_to?(:to_path)
    res.body = ::File.open(body.to_path, "rb")
    body.close if body.respond_to?(:close)
  else
    res.body = lambda do |out|
      out.set_encoding(Encoding::BINARY) if out.respond_to?(:set_encoding)
      body.each do |part|
        out.write(part)
      end
      body.close if body.respond_to?(:close)
    end
  end
end