server: add gzip support

This commit is contained in:
0x1eef 2023-06-29 12:07:24 -03:00
parent 786700e6ea
commit d89f3fd8b9
6 changed files with 103 additions and 14 deletions

View file

@ -0,0 +1,40 @@
##
# Plugins
require:
- standard
##
# Defaults: standard-rb
inherit_gem:
standard: config/base.yml
##
# All cops
AllCops:
TargetRubyVersion: 3.2
Include:
- lib/*.rb
- lib/**/*.rb
- test/*_test.rb
##
# Enabled
Style/FrozenStringLiteralComment:
Enabled: true
##
# Disabled
Layout/ArgumentAlignment:
Enabled: false
Layout/MultilineMethodCallIndentation:
Enabled: false
Layout/EmptyLineBetweenDefs:
Enabled: false
Style/TrivialAccessors:
Enabled: false
Lint/NestedMethodDefinition:
Exclude:
- test/server_dir_test.rb
Style/SingleLineMethods:
Exclude:
- test/server_dir_test.rb

View file

@ -3,6 +3,7 @@
class Server
require "rack"
require_relative "server/puma"
require_relative "server/gzip"
require_relative "server/dir"
def self.app(path)

View file

@ -1,19 +1,17 @@
# frozen_string_literal: true
##
# A rack application that serves the contents
# of a directory over HTTP.
class Server::Dir
MIME_TYPES = {
".ttf" => "font/ttf"
}.freeze
prepend Server::Gzip
def initialize(root)
@root = File.realpath(root)
end
def call(env)
req = Rack::Request.new(env)
headers = Rack::Headers.new(env)
h, body = read(local_path(req.path))
[200, headers.merge!(h), body]
finish Rack::Request.new(env)
rescue Errno::EPERM, Errno::EACCES
body = "Permission denied"
[403, {"content-length" => body.bytesize, "content-type" => "text/plain"}, [body]]
@ -29,18 +27,24 @@ class Server::Dir
attr_reader :root
def read(path)
def finish(request)
path = find_path(request)
body = File.binread(path)
extn = File.extname(path)
[
{"content-type" => MIME_TYPES[extn] || Rack::Mime.mime_type(extn),
200,
{"content-type" => mime_types[extn] || Rack::Mime.mime_type(extn),
"content-length" => body.bytesize},
body.each_line
]
end
def local_path(req_path)
lpath = File.join root, File.expand_path(req_path)
File.directory?(lpath) ? File.join(lpath, "index.html") : lpath
def find_path(request)
path = File.join root, File.expand_path(request.path)
File.directory?(path) ? File.join(path, "index.html") : path
end
def mime_types
{".ttf" => "font/ttf"}.freeze
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
##
# A mixin module that serves a compressed version of
# a file when the file is found to exist on disk,
# and has a ".gz" file extension.
module Server::Gzip
def finish(request)
path = gzip_path(request)
if path
body = File.binread(path)
extn = File.extname(path[0..-4])
[
200,
{"content-type" => mime_types[extn] || Rack::Mime.mime_type(extn),
"content-encoding" => "gzip",
"content-length" => body.bytesize},
body.each_line
]
else
super
end
end
private
def gzip_path(request)
return unless request.get_header("accept-encoding")
&.include?("gzip")
path = "#{find_path(request)}.gz"
File.exist?(path) ? path : nil
end
end

View file

@ -10,6 +10,15 @@ Gem::Specification.new do |gem|
gem.require_paths = ["lib"]
gem.summary = "A static file web server"
gem.description = gem.summary
##
# Default gems
# Pinned to specific versions for OpenBSD support
gem.add_runtime_dependency "json", "= 2.6.1"
gem.add_runtime_dependency "racc", "= 1.6.0"
gem.add_runtime_dependency "stringio", "= 3.0.1"
gem.add_runtime_dependency "set", "= 1.0.2"
gem.add_runtime_dependency "puma", "~> 6.3"
gem.add_runtime_dependency "rack", "~> 3.0"
gem.add_development_dependency "standard", "~> 1.24"

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
require_relative "setup"
require "rack/test"
@ -44,7 +46,7 @@ class ServerDirTest < Test::Unit::TestCase
end
def test_internal_server_error
def app.read(path) raise RuntimeError, "test" end
def app.finish(request) raise "test" end
get "/"
assert_equal 500, last_response.status
assert_equal "text/plain", last_response.content_type
@ -62,7 +64,7 @@ class ServerDirTest < Test::Unit::TestCase
assert_equal "Permission denied".bytesize, last_response.content_length
assert_equal "Permission denied", last_response.body
ensure
File.chmod 0440, "./test/webroot/permission_denied.html"
File.chmod 0o440, "./test/webroot/permission_denied.html"
end
def test_page_not_found