proof of concept
This commit is contained in:
parent
f50ea11b17
commit
8593315b95
72
hyde.rb
72
hyde.rb
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue