proof of concept

This commit is contained in:
Yessiest 2023-04-17 00:45:49 +04:00
parent f50ea11b17
commit 8593315b95
2 changed files with 86 additions and 12 deletions

72
hyde.rb
View File

@ -1,6 +1,23 @@
require 'mime-types' require 'mime-types'
require 'webrick'
module Hyde module Hyde
# 404 text
def default404(filepath)
return "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">
<HTML>
<HEAD><TITLE>File not found</TITLE></HEAD>
<BODY>
<H1>File not found</H1>
#{filepath}
<HR>
<ADDRESS>
Hyde on WEBrick/#{WEBrick::VERSION} (Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})
</ADDRESS>
</BODY>
</HTML>"
end
module_function :default404
# Interchangeable pattern matching # Interchangeable pattern matching
module PatternMatching module PatternMatching
def prep_path(path,safe_regex: true) def prep_path(path,safe_regex: true)
@ -47,50 +64,54 @@ module Hyde
end end
# Methods to control requests, accessible from within blocks # Methods to control requests, accessible from within blocks
module PublicRequestControlMethods module PublicContextControlMethods
def redirect(url) def redirect(url)
puts "Unimplemented method 'redirect' called" puts "Unimplemented method 'redirect' called"
return return
end end
end end
# Request control class # Request wrapper class
class Request class Context
def initialize(path,request,response) def initialize(path,request,response)
@path = path @path = path
@filepath = "" @filepath = ""
@request = request @request = request
@response = response @response = response
@handles = {}
end end
attr_reader :request attr_reader :request
attr_reader :response attr_reader :response
attr_accessor :filepath attr_accessor :filepath
attr_accessor :path attr_accessor :path
attr_accessor :handles
end end
# Request object with safe path encapsulation # Context object with safe path encapsulation
class ProtectedRequest < Request class ProtectedContext < Context
def initialize(request) def initialize(request)
@path = request.path @path = request.path
@filepath = request.filepath @filepath = request.filepath
@request = request.request @request = request.request
@response = request.response @response = request.response
@handles = request.handles
end end
undef :path= undef :path=
undef :filepath= undef :filepath=
undef :handles=
end end
# Handler classes # Handler classes
class Probe class Probe
include Hyde::PatternMatching include Hyde::PatternMatching
include Hyde::PublicRequestControlMethods include Hyde::PublicContextControlMethods
def initialize (path, safe_regex: true, &block_optional) def initialize (path, safe_regex: true, &block_optional)
prep_path path, safe_regex: safe_regex prep_path path, safe_regex: safe_regex
@block = block_optional @block = block_optional
end end
def match(request) def match(request)
if @block and (match? request.path) then if @block and (match? request.path) then
@current_request = Hyde::ProtectedRequest.new(request) @current_request = Hyde::ProtectedContext.new(request)
@lock_methods = true @lock_methods = true
return_later = self.instance_exec @current_request, &@block return_later = self.instance_exec @current_request, &@block
@lock_methods = false @lock_methods = false
@ -105,10 +126,21 @@ module Hyde
if match? request.path then if match? request.path then
match_path = normalize_input(request.path).match(@path)[0] match_path = normalize_input(request.path).match(@path)[0]
filepath = request.filepath+match_path filepath = request.filepath+match_path
mimetype = MIME::Types.type_for(filepath) begin
file = File.new filepath, "r" mimetype = MIME::Types.type_for(filepath)
data = file.read() file = File.new filepath, "r"
# TODO: Finish this data = file.read()
request.response.body = data
request.response["Content-Type"] = mimetype
rescue Errno::ENOENT
if request.handles.include? 404 then
request.response.body = request.handles[404].call filepath
request.response["Content-Type"] = "text/html"
else
request.response.body = Hyde::default404 filepath
end
end
end
end end
end end
@ -124,7 +156,8 @@ module Hyde
module Handlers module Handlers
{ {
probe: Hyde::Probe, probe: Hyde::Probe,
printProbe: Hyde::PrintProbe printProbe: Hyde::PrintProbe,
serve: Hyde::Serve
}.each_pair { |name, newclass| }.each_pair { |name, newclass|
define_method name do |path, *a, **b, &block| define_method name do |path, *a, **b, &block|
if path.kind_of? Array then if path.kind_of? Array then
@ -144,6 +177,7 @@ module Hyde
def initialize (path, root_path: nil, safe_regex: true, &block) def initialize (path, root_path: nil, safe_regex: true, &block)
prep_path path, safe_regex: safe_regex prep_path path, safe_regex: safe_regex
@chain = [] @chain = []
@handles = {}
@root_override = root_path @root_override = root_path
@remap = false @remap = false
@lock_methods = true @lock_methods = true
@ -170,6 +204,9 @@ module Hyde
@lock_methods = true @lock_methods = true
@remap = true @remap = true
end end
def handle(code, &block)
@handles[code] = block
end
def match(request) def match(request)
raise Exception, "Not permitted" if @lock_methods raise Exception, "Not permitted" if @lock_methods
if match? request.path then if match? request.path then
@ -183,8 +220,19 @@ module Hyde
else else
request.filepath = request.filepath+next_path+"/" request.filepath = request.filepath+next_path+"/"
end end
@handles.each_pair { |k,v| request.handles[k] = v }
next_pathspec = @chain.find { |x| x.match? cut_path } next_pathspec = @chain.find { |x| x.match? cut_path }
next_pathspec.match request if next_pathspec next_pathspec.match request if next_pathspec
unless next_pathspec then
if request.handles.include? 404
request.response.body = request.handles[404].call(
request.filepath+"/"+cut_path
)
else
request.response.body = Hyde::default404(request.filepath+cut_path)
end
request.response["Content-Type"] = 'text/html'
end
end end
end end
end end

26
test_combined.rb Normal file
View File

@ -0,0 +1,26 @@
require 'webrick'
require_relative 'hyde'
server = WEBrick::HTTPServer.new :Port => 8000
trap 'INT' do server.shutdown end
server.mount_proc '/' do |req,res|
Hyde::Pathspec.new '/' do
serve "index.html" do |ctx|
ctx.response.body = "This is a test of webrick+hyde combination
If you're seeing this, this means it's a success"
ctx.response["Content-Type"] = "text/plain"
end
path "about" do
serve "webrick" do |ctx|
ctx.response.body = "WEBrick is weird and pretty undocumented"
ctx.response["Content-Type"] = "text/plain"
end
serve "hyde" do |ctx|
ctx.response.body = "Hyde was born because i thought Sinatra is cool, but nested paths are even cooler"
ctx.response["Content-Type"] = "text/plain"
end
end
end.match(Hyde::Context.new(req.path, req, res))
end
server.start