Skip to content

Commit

Permalink
Merge pull request #100 from rage-rb/file-server
Browse files Browse the repository at this point in the history
Static file server
  • Loading branch information
rsamoilov authored Aug 21, 2024
2 parents 7858743 + 6dca714 commit 0f0f9d7
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 16 deletions.
13 changes: 8 additions & 5 deletions lib/rage/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ def server
app = ::Rack::Builder.parse_file(options[:config] || "config.ru")
app = app[0] if app.is_a?(Array)

port = options[:port] || Rage.config.server.port
address = options[:binding] || (Rage.env.production? ? "0.0.0.0" : "localhost")
timeout = Rage.config.server.timeout
max_clients = Rage.config.server.max_clients
server_options = { service: :http, handler: app }

::Iodine.listen service: :http, handler: app, port: port, address: address, timeout: timeout, max_clients: max_clients
server_options[:port] = options[:port] || Rage.config.server.port
server_options[:address] = options[:binding] || (Rage.env.production? ? "0.0.0.0" : "localhost")
server_options[:timeout] = Rage.config.server.timeout
server_options[:max_clients] = Rage.config.server.max_clients
server_options[:public] = Rage.config.public_file_server.enabled ? Rage.root.join("public").to_s : nil

::Iodine.listen(**server_options)
::Iodine.threads = Rage.config.server.threads_count
::Iodine.workers = Rage.config.server.workers_count

Expand Down
14 changes: 14 additions & 0 deletions lib/rage/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@
#
# > Specifies connection timeout.
#
# # Static file server
#
# • _config.public_file_server.enabled_
#
# > Configures whether Rage should serve static files from the public directory. Defaults to `false`.
#
# # Cable Configuration
#
# • _config.cable.protocol_
Expand Down Expand Up @@ -165,6 +171,10 @@ def cable
@cable ||= Cable.new
end

def public_file_server
@public_file_server ||= PublicFileServer.new
end

def internal
@internal ||= Internal.new
end
Expand Down Expand Up @@ -246,6 +256,10 @@ def middlewares
end
end

class PublicFileServer
attr_accessor :enabled
end

# @private
class Internal
attr_accessor :rails_mode
Expand Down
132 changes: 132 additions & 0 deletions spec/integration/file_server_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# frozen_string_literal: true

require "http"

RSpec.describe "File server" do
before :all do
skip("skipping file server tests") unless ENV["ENABLE_EXTERNAL_TESTS"] == "true"
end

subject { http.get(url) }
let(:http) { HTTP }
let(:url) { "http://localhost:3000/test.txt" }

context "with file server disabled" do
before :all do
launch_server
end

after :all do
stop_server
end

it "doesn't allow to access public assets" do
expect(subject.code).to eq(404)
end
end

context "with file server enabled" do
before :all do
launch_server(env: { "ENABLE_FILE_SERVER" => "1" })
end

after :all do
stop_server
end

it "allows to access public assets" do
expect(subject.code).to eq(200)
expect(subject.to_s).to eq("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n")
end

it "returns correct headers" do
expect(subject.headers["content-length"]).to eq("27")
expect(subject.headers["content-type"]).to eq("text/plain")
expect(subject.headers["etag"]).not_to be_empty
expect(subject.headers["last-modified"]).not_to be_empty
end

it "fallbacks to application routes" do
response = HTTP.get("http://localhost:3000/get")
expect(response.code).to eq(200)
expect(response.to_s).to eq("i am a get response")
end

context "with valid range" do
let(:http) { HTTP.headers(range: "bytes=5-9") }

it "returns correct response" do
expect(subject.code).to eq(206)
expect(subject.to_s).to eq("FGHIJ")
end

it "returns correct headers" do
expect(subject.headers["content-length"]).to eq("5")
expect(subject.headers["content-range"]).to eq("bytes 5-9/27")
end
end

context "with invalid range" do
let(:http) { HTTP.headers(range: "bytes=5-100") }

it "returns correct response" do
expect(subject.code).to eq(416)
end

it "returns correct headers" do
expect(subject.headers["content-range"]).to eq("bytes */27")
end
end

context "with If-None-Match" do
let(:http) { HTTP.headers(if_none_match: etag) }

context "with valid etag" do
let(:etag) { HTTP.get(url).headers["etag"] }

it "returns correct response" do
expect(subject.code).to eq(304)
end
end

context "with invalid etag" do
let(:etag) { "invalid-etag" }

it "returns correct response" do
expect(subject.code).to eq(200)
expect(subject.to_s).to eq("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n")
end
end
end

context "with If-Range" do
let(:http) { HTTP.headers(range: "bytes=5-9", if_range: etag) }

context "with valid etag" do
let(:etag) { HTTP.get(url).headers["etag"] }

it "returns correct response" do
expect(subject.code).to eq(206)
expect(subject.to_s).to eq("FGHIJ")
end
end

context "with invalid etag" do
let(:etag) { "invalid-etag" }

it "returns correct status code" do
expect(subject.code).to eq(200)
expect(subject.to_s).to eq("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n")
end
end
end

context "with URL outside public directory" do
let(:url) { "http://localhost:3000/../Gemfile" }

it "returns correct status code" do
expect(subject.code).to eq(404)
end
end
end
end
13 changes: 2 additions & 11 deletions spec/integration/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,11 @@
end

before :all do
Bundler.with_unbundled_env do
system("gem build -o rage-local.gem && gem install rage-local.gem --no-document && bundle install")
@pid = spawn("bundle exec rage s", chdir: "spec/integration/test_app")
sleep(1)
end
launch_server
end

after :all do
if @pid
Process.kill(:SIGTERM, @pid)
Process.wait
system("rm spec/integration/test_app/Gemfile.lock")
system("rm spec/integration/test_app/log/development.log")
end
stop_server
end

it "correctly processes lambda requests" do
Expand Down
1 change: 1 addition & 0 deletions spec/integration/test_app/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def call(env)

Rage.configure do
config.middleware.use TestMiddleware
config.public_file_server.enabled = !!ENV["ENABLE_FILE_SERVER"]
end

require "rage/setup"
Empty file.
1 change: 1 addition & 0 deletions spec/integration/test_app/public/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ABCDEFGHIJKLMNOPQRSTUVWXYZ
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require "rage/all"
require_relative "support/integration_helper"
require_relative "support/request_helper"
require_relative "support/controller_helper"
require_relative "support/reactor_helper"
Expand All @@ -21,6 +22,7 @@
Iodine.patch_rack
end

config.include IntegrationHelper
config.include RequestHelper
config.include ControllerHelper
config.include ReactorHelper
Expand Down
20 changes: 20 additions & 0 deletions spec/support/integration_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module IntegrationHelper
def launch_server(env: {})
Bundler.with_unbundled_env do
system("gem build -o rage-local.gem && gem install rage-local.gem --no-document && bundle install")
@pid = spawn(env, "bundle exec rage s", chdir: "spec/integration/test_app")
sleep(1)
end
end

def stop_server
if @pid
Process.kill(:SIGTERM, @pid)
Process.wait
system("rm spec/integration/test_app/Gemfile.lock")
system("rm spec/integration/test_app/log/development.log")
end
end
end

0 comments on commit 0f0f9d7

Please sign in to comment.