- Object
+ Node
Object
+ Node
+
Hyde::Path
@@ -94,24 +96,808 @@
Defined in:
- lib/hyde.rb
+ lib/hyde/path.rb
+Overview
+
+
+
Primary building block of request navigation.
+
+
+
+
+
+
+
+
+
Direct Known Subclasses
+
Server
+
+
+
+
+ Constant Summary
+ collapse
+
+
+
+
+ Binding =
+
+
+ Hyde :: PathBinding
+
+
+
+ Instance Attribute Summary collapse
+
+
+
+
+
+ #children ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute children.
+
+
+
+
+
+
+
+
+ #properties ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute properties.
+
+
+
+
+
+
+
+
+ Attributes inherited from Node
+ #remap , #root
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Methods inherited from Node
+ #go , #reject
+
+
Constructor Details
+
+
+
+
+ #initialize (path, parent:, &setup) ⇒ Path
+
+
+
+
+
+
+
+
+
Returns a new instance of Path.
+
+
+
+
+
+
+
+
+
+
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+
+
+ # File 'lib/hyde/path.rb', line 27
+
+def initialize ( path , parent: , & setup )
+ super ( path , parent: parent )
+ @children = [ ]
+ @preprocessors = [ ]
+ @postprocessors = [ ]
+ @filters = [ ]
+
+ binding = Binding . new ( self )
+ binding . instance_exec ( & setup )
+end
+
+
+
+
+
+
+
+
+
Instance Attribute Details
+
+
+
+
+
+
+ #children ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute children.
+
+
+
+
+
+
+
+
+
+
+
+
+
+86
+87
+88
+
+
+ # File 'lib/hyde/path.rb', line 86
+
+def children
+ @children
+end
+
+
+
+
+
+
+
+
+
+
+ #properties ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute properties.
+
+
+
+
+
+
+
+
+
+
+
+
+
+86
+87
+88
+
+
+ # File 'lib/hyde/path.rb', line 86
+
+def properties
+ @properties
+end
+
+
+
+
+
+
+
+
+
+
Instance Method Details
+
+
+
+
+
+ #filter (&block) {|request| ... } ⇒ Object
+
+
+
+
+
+
+
+
+
Add a filter to the path. Blocks path access if a filter returns false.
+
+
+
+
+
+
+
+
+
+
+82
+83
+84
+
+
+ # File 'lib/hyde/path.rb', line 82
+
+def filter ( & block )
+ @filters . append ( block )
+end
+
+
+
+
+
+
+
+
+ #postprocess (&block) {|request, response| ... } ⇒ Object
+
+
+
+
+
+
+
+
+
Add a postprocessor to the path.
+
+
+
+
+
+
+
+
+
+
+74
+75
+76
+
+
+ # File 'lib/hyde/path.rb', line 74
+
+def postprocess ( & block )
+ @postprocessors . append ( block )
+end
+
+
+
+
+
+
+
+
+ #preprocess (&block) {|request| ... } ⇒ Object
+
+
+
+
+
+
+
+
+
Add a preprocessor to the path. Does not modify path execution.
+
+
+
+
+
+
+
+
+
+
+66
+67
+68
+
+
+ # File 'lib/hyde/path.rb', line 66
+
+def preprocess ( & block )
+ @preprocessors . append ( block )
+end
+
+
+
+
+
+
+
+
+ #process (request) ⇒ Boolean
+
+
+
+
+
+
+
+
+
Method callback on successful request navigation. Finds the next appropriate path to go to.
+
+
+
+
+
+
+
+
+
+
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+
+
+ # File 'lib/hyde/path.rb', line 44
+
+def process ( request )
+ return false unless run_filters ( request )
+
+ run_preprocessors ( request )
+ enqueue_postprocessors ( request )
+ @children . each do | x |
+ if ( value = x . go ( request ) )
+ return value
+ end
+ end
+ value = index ( request )
+ return value if value
+
+ _die ( 404 )
+rescue StandardError => e
+ _die ( 500 , backtrace: [ e . to_s ] + e . backtrace )
+end
+
+
+
+
+
+
+
diff --git a/doc/Hyde/PathBinding.html b/doc/Hyde/PathBinding.html
index 79b7d40..3bb71a0 100644
--- a/doc/Hyde/PathBinding.html
+++ b/doc/Hyde/PathBinding.html
@@ -87,6 +87,11 @@
+
+ Includes:
+ DSL::PathConstructors , DSL::PathMethods
+
+
@@ -94,24 +99,143 @@
Defined in:
- lib/hyde.rb
+ lib/hyde/path.rb
+Overview
+
+
+
Protected interface that provides DSL context for setup block.
+
+
+
+
+
+
+
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #filter , #index , #postprocess , #preprocess , #remap , #root
+
+
+
+
+
+
+
+
+
+
+ #connect , #delete , #get , #head , #options , #patch , #path , #post , #probe , #put , #register , #serve , #trace
+
+
Constructor Details
+
+
+
+
+ #initialize (path) ⇒ PathBinding
+
+
+
+
+
+
+
+
+
Returns a new instance of PathBinding.
+
+
+
+
+
+
+
+
+
+
+
+
+
+15
+16
+17
+
+
+ # File 'lib/hyde/path.rb', line 15
+
+def initialize ( path )
+ @origin = path
+end
+
+
+
+
+
+
diff --git a/doc/Hyde/Pattern.html b/doc/Hyde/Pattern.html
index b3afed9..af2693e 100644
--- a/doc/Hyde/Pattern.html
+++ b/doc/Hyde/Pattern.html
@@ -275,13 +275,13 @@
+16
17
18
-19
-20
+19
- # File 'lib/hyde/pattern_matching.rb', line 17
+ # File 'lib/hyde/pattern_matching.rb', line 16
def initialize ( pattern )
@pattern = patternify ( pattern )
@@ -379,6 +379,7 @@
+35
36
37
38
@@ -389,11 +390,10 @@
43
44
45
-46
-47
+46
- # File 'lib/hyde/pattern_matching.rb', line 36
+ # File 'lib/hyde/pattern_matching.rb', line 35
def match ( input )
if @pattern . is_a? String
@@ -471,20 +471,20 @@
+52
53
54
55
56
57
-58
-59
+58
- # File 'lib/hyde/pattern_matching.rb', line 53
+ # File 'lib/hyde/pattern_matching.rb', line 52
def match? ( input )
if @pattern . is_a? String
- Hyde :: PatternMatching . canonicalize ( input ) . start_with? pattern
+ Hyde :: PatternMatching . canonicalize ( input ) . start_with? @pattern
else
@pattern . match? ( input )
end
@@ -533,12 +533,12 @@
+22
23
-24
-25
+24
- # File 'lib/hyde/pattern_matching.rb', line 23
+ # File 'lib/hyde/pattern_matching.rb', line 22
def static?
@static
@@ -553,7 +553,7 @@
diff --git a/doc/Hyde/PatternMatching.html b/doc/Hyde/PatternMatching.html
index 68cef9f..b994167 100644
--- a/doc/Hyde/PatternMatching.html
+++ b/doc/Hyde/PatternMatching.html
@@ -232,7 +232,7 @@
diff --git a/doc/Hyde/PatternMatching/Glob.html b/doc/Hyde/PatternMatching/Glob.html
index 3136500..6b028a6 100644
--- a/doc/Hyde/PatternMatching/Glob.html
+++ b/doc/Hyde/PatternMatching/Glob.html
@@ -641,7 +641,7 @@
diff --git a/doc/Hyde/PatternMatching/ReMatch.html b/doc/Hyde/PatternMatching/ReMatch.html
index 541d4cd..843c1ce 100644
--- a/doc/Hyde/PatternMatching/ReMatch.html
+++ b/doc/Hyde/PatternMatching/ReMatch.html
@@ -559,7 +559,7 @@
diff --git a/doc/Hyde/Probe.html b/doc/Hyde/Probe.html
new file mode 100644
index 0000000..2282d75
--- /dev/null
+++ b/doc/Hyde/Probe.html
@@ -0,0 +1,471 @@
+
+
+
+
+
+
+ Class: Hyde::Probe
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::Probe
+
+
+
+
+
+
+
+ Inherits:
+
+ Node
+
+
+ Object
+
+ Node
+
+ Hyde::Probe
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/probe.rb
+
+
+
+
+
Overview
+
+
+
Test probe. Also base for all “reactive” nodes.
+
+
+
+
+
+
+
+
+
+
+
+
+
Instance Attribute Summary collapse
+
+
+
+
+
+ #properties ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute properties.
+
+
+
+
+
+
+
+
+
+
+
+
Attributes inherited from Node
+
#remap , #root
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Methods inherited from Node
+
#go , #reject
+
+
Constructor Details
+
+
+
+
+ #initialize (path, parent:) ⇒ Probe
+
+
+
+
+
+
+
+
+
Returns a new instance of Probe.
+
+
+
+
+
+
+
+
+
+
+23
+24
+25
+
+
+ # File 'lib/hyde/probe.rb', line 23
+
+def initialize ( path , parent: )
+ super ( path , parent: parent )
+end
+
+
+
+
+
+
+
+
+
Instance Attribute Details
+
+
+
+
+
+
+ #properties ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute properties.
+
+
+
+
+
+
+
+
+
+
+
+
+
+27
+28
+29
+
+
+ # File 'lib/hyde/probe.rb', line 27
+
+def properties
+ @properties
+end
+
+
+
+
+
+
+
+
+
+
Instance Method Details
+
+
+
+
+
+ #process (request) ⇒ Boolean
+
+
+
+
+
+
+
+
+
Method callback on successful request navigation. Throws an error upon reaching the path. This behaviour should only be used internally.
+
+
+
+
+
+
+
+
+
+
+35
+36
+37
+38
+39
+40
+41
+42
+
+
+ # File 'lib/hyde/probe.rb', line 35
+
+def process ( request )
+ return reject ( request ) unless request . path . match? ( / ^\/?$ / )
+
+ raise StandardError , <<~STREND
+ probe reached #{ request . splat . inspect } , #{ request . param . inspect }
+ #{ request . pretty_inspect }
+ STREND
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/ProbeBinding.html b/doc/Hyde/ProbeBinding.html
new file mode 100644
index 0000000..84d9a19
--- /dev/null
+++ b/doc/Hyde/ProbeBinding.html
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+ Class: Hyde::ProbeBinding
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::ProbeBinding
+
+
+
+
+
+
+
+ Inherits:
+
+ Object
+
+
+ Object
+
+ Hyde::ProbeBinding
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+ Includes:
+ DSL::ProbeMethods
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/probe/binding.rb
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#bounce , #die , #header , #remove_header , #request , #status
+
+
Constructor Details
+
+
+
+
+ #initialize (origin) ⇒ ProbeBinding
+
+
+
+
+
+
+
+
+
Returns a new instance of ProbeBinding.
+
+
+
+
+
+
+
+
+
+
+
+
+
+7
+8
+9
+
+
+ # File 'lib/hyde/probe/binding.rb', line 7
+
+def initialize ( origin )
+ @origin = origin
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/Request.html b/doc/Hyde/Request.html
new file mode 100644
index 0000000..9efd6fe
--- /dev/null
+++ b/doc/Hyde/Request.html
@@ -0,0 +1,1505 @@
+
+
+
+
+
+
+ Class: Hyde::Request
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::Request
+
+
+
+
+
+
+
+ Inherits:
+
+ Object
+
+
+ Object
+
+ Hyde::Request
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/request.rb
+
+
+
+
+
Overview
+
+
+
Request wrapper for Rack protocol
+
+
+
+
+
+
+
+
+
+
+
+
Instance Attribute Summary collapse
+
+
+
+
+
+ #filepath ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute filepath.
+
+
+
+
+
+
+
+
+ #headers ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute headers.
+
+
+
+
+
+
+
+
+ #param ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute param.
+
+
+
+
+
+
+
+
+ #path ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute path.
+
+
+
+
+
+
+
+
+ #path_info ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute path_info.
+
+
+
+
+
+
+
+
+ #postprocessors ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute postprocessors.
+
+
+
+
+
+
+
+
+ #query ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute query.
+
+
+
+
+
+
+
+
+ #request_method ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute request_method.
+
+
+
+
+
+
+
+
+ #script_name ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute script_name.
+
+
+
+
+
+
+
+
+ #server_name ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute server_name.
+
+
+
+
+
+
+
+
+ #server_port ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute server_port.
+
+
+
+
+
+
+
+
+ #server_protocol ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute server_protocol.
+
+
+
+
+
+
+
+
+ #splat ⇒ Object
+
+
+
+
+
+
+
+
+ readonly
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute splat.
+
+
+
+
+
+
+
+
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
Constructor Details
+
+
+
+
+ #initialize (env) ⇒ Request
+
+
+
+
+
+
+
+
+
Returns a new instance of Request.
+
+
+
+
+
+
+
+
+
+
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+
+
+ # File 'lib/hyde/request.rb', line 10
+
+def initialize ( env )
+ @_original_env = env
+ init_request_params ( env )
+ @query = Query . new ( @query_string )
+ @param = { }
+ @splat = [ ]
+ @path = URI . decode_www_form_component ( env [ " PATH_INFO " ] . dup )
+ @filepath = " / "
+ @rack = init_rack_vars ( env )
+ @states = [ ]
+ @postprocessors = [ ]
+end
+
+
+
+
+
+
+
+
+
Instance Attribute Details
+
+
+
+
+
+
+ #filepath ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute filepath.
+
+
+
+
+
+
+
+
+
+
+
+
+
+59
+60
+61
+
+
+ # File 'lib/hyde/request.rb', line 59
+
+def filepath
+ @filepath
+end
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute headers.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def
+ @headers
+end
+
+
+
+
+
+
+
+
+
+
+ #param ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute param.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def param
+ @param
+end
+
+
+
+
+
+
+
+
+
+
+ #path ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute path.
+
+
+
+
+
+
+
+
+
+
+
+
+
+59
+60
+61
+
+
+ # File 'lib/hyde/request.rb', line 59
+
+def path
+ @path
+end
+
+
+
+
+
+
+
+
+
+
+ #path_info ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute path_info.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def path_info
+ @path_info
+end
+
+
+
+
+
+
+
+
+
+
+ #postprocessors ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute postprocessors.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def postprocessors
+ @postprocessors
+end
+
+
+
+
+
+
+
+
+
+
+ #query ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute query.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def query
+ @query
+end
+
+
+
+
+
+
+
+
+
+
+ #request_method ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute request_method.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def request_method
+ @request_method
+end
+
+
+
+
+
+
+
+
+
+
+ #script_name ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute script_name.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def script_name
+ @script_name
+end
+
+
+
+
+
+
+
+
+
+
+ #server_name ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute server_name.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def server_name
+ @server_name
+end
+
+
+
+
+
+
+
+
+
+
+ #server_port ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute server_port.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def server_port
+ @server_port
+end
+
+
+
+
+
+
+
+
+
+
+ #server_protocol ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute server_protocol.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def server_protocol
+ @server_protocol
+end
+
+
+
+
+
+
+
+
+
+
+ #splat ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute splat.
+
+
+
+
+
+
+
+
+
+
+
+
+
+56
+57
+58
+
+
+ # File 'lib/hyde/request.rb', line 56
+
+def splat
+ @splat
+end
+
+
+
+
+
+
+
+
+
+
Instance Method Details
+
+
+
+
+
+ #body ⇒ nil , String
+
+
+
+
+
+
+
+
+
Returns request body (if POST data exists)
+
+
+
+
+
+
+
+
+
+
+42
+43
+44
+
+
+ # File 'lib/hyde/request.rb', line 42
+
+def body
+ @body ||= @rack . input &. gets
+end
+
+
+
+
+
+
+
+
+ #pop_state ⇒ Object
+
+
+
+
+
+
+
+
+
Load last navigation state (path, splat, param) from state stack
+
+
+
+
+
+
+
+
+
+
+
+
+
+52
+53
+54
+
+
+ # File 'lib/hyde/request.rb', line 52
+
+def pop_state
+ @path , @param , @splat , @filepath = @states . pop
+end
+
+
+
+
+
+
+
+
+ #push_state ⇒ Object
+
+
+
+
+
+
+
+
+
Push current navigation state (path, splat, param) onto state stack
+
+
+
+
+
+
+
+
+
+
+
+
+
+47
+48
+49
+
+
+ # File 'lib/hyde/request.rb', line 47
+
+def push_state
+ @states . push ( [ @path , @param . dup , @splat . dup , @filepath . dup ] )
+end
+
+
+
+
+
+
+
+
+ #run_postprocessors (response) ⇒ Object
+
+
+
+
+
+
+
+
+
Run postprocessors
+
+
+
+
+
+
+
+
+
+
+34
+35
+36
+37
+38
+
+
+ # File 'lib/hyde/request.rb', line 34
+
+def run_postprocessors ( response )
+ @postprocessors . each do | postproc |
+ postproc . call ( self , response )
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/Response.html b/doc/Hyde/Response.html
new file mode 100644
index 0000000..e5fa4ba
--- /dev/null
+++ b/doc/Hyde/Response.html
@@ -0,0 +1,1177 @@
+
+
+
+
+
+
+ Class: Hyde::Response
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::Response
+
+
+
+
+
+
+
+ Inherits:
+
+ Object
+
+
+ Object
+
+ Hyde::Response
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/response.rb
+
+
+
+
+
Overview
+
+
+
Rack protocol response wrapper.
+
+
+
+
+
+
+
+
+
+
+
+
Instance Attribute Summary collapse
+
+
+
+
+
+ #body ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute body.
+
+
+
+
+
+
+
+
+ #chunk_size ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute chunk_size.
+
+
+
+
+
+
+
+
+ #headers ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute headers.
+
+
+
+
+
+
+
+
+ #status ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute status.
+
+
+
+
+
+
+
+
+
+
+
+
+ Class Method Summary
+ collapse
+
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
Constructor Details
+
+
+
+
+ #initialize (response = nil) ⇒ Response
+
+
+
+
+
+
+
+
+
Returns a new instance of Response.
+
+
+
+
+
+
+
+
+
+
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+
+
+ # File 'lib/hyde/response.rb', line 11
+
+def initialize ( response = nil )
+ if response
+ @status = response [ 0 ]
+ @headers = response [ 1 ]
+ @body = response [ 2 ]
+ else
+ @status = 404
+ @headers = { }
+ @body = [ ]
+ end
+end
+
+
+
+
+
+
+
+
+
Instance Attribute Details
+
+
+
+
+
+
+ #body ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute body.
+
+
+
+
+
+
+
+
+
+
+
+
+
+71
+72
+73
+
+
+ # File 'lib/hyde/response.rb', line 71
+
+def body
+ @body
+end
+
+
+
+
+
+
+
+
+
+
+ #chunk_size ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute chunk_size.
+
+
+
+
+
+
+
+
+
+
+
+
+
+8
+9
+10
+
+
+ # File 'lib/hyde/response.rb', line 8
+
+def chunk_size
+ @chunk_size
+end
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute headers.
+
+
+
+
+
+
+
+
+
+
+
+
+
+71
+72
+73
+
+
+ # File 'lib/hyde/response.rb', line 71
+
+def
+ @headers
+end
+
+
+
+
+
+
+
+
+
+
+ #status ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute status.
+
+
+
+
+
+
+
+
+
+
+
+
+
+71
+72
+73
+
+
+ # File 'lib/hyde/response.rb', line 71
+
+def status
+ @status
+end
+
+
+
+
+
+
+
+
+
+
Class Method Details
+
+
+
+
+
+ .chunk_body (text) ⇒ Array(String)
+
+
+
+
+
+
+
+
+
Turn body into array of chunks
+
+
+
+
+
+
+
+
+
+
+96
+97
+98
+
+
+ # File 'lib/hyde/response.rb', line 96
+
+def self . chunk_body ( text )
+ text . chars . each_slice ( @chunk_size ) . map ( & :join )
+end
+
+
+
+
+
+
+
+
+ .convert (obj) ⇒ Object
+
+
+
+
+
+
+
+
+
Ensure response correctness
+
+
+
+
+
+
+
+
+
+
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+
+
+ # File 'lib/hyde/response.rb', line 76
+
+def self . convert ( obj )
+ case obj
+ when Response
+ obj . validate
+ when Array
+ Response . new ( obj ) . validate
+ when String , File , IO
+ Response . new ( [ 200 ,
+ {
+ " content-type " => " text/html "
+ } ,
+ obj ] ) . validate
+ else
+ Response . new ( [ 404 , { } , [ ] ] )
+ end
+end
+
+
+
+
+
+
+
+
+
Instance Method Details
+
+
+
+
+
+
+
Add a header to the headers hash
+
+
+
+
+
+
+
+
+
+
+49
+50
+51
+52
+53
+54
+55
+56
+57
+
+
+ # File 'lib/hyde/response.rb', line 49
+
+def ( key , value )
+ if @headers [ key ] . is_a? String
+ @headers [ key ] = [ @headers [ key ] , value ]
+ elsif @headers [ key ] . is_a? Array
+ @headers [ key ] . append ( value )
+ else
+ @headers [ key ] = value
+ end
+end
+
+
+
+
+
+
+
+
+
+
Delete a header value from the headers hash If no value is provided, deletes all key entries
+
+
+
+
+
+
+
+
+
+
+63
+64
+65
+66
+67
+68
+69
+
+
+ # File 'lib/hyde/response.rb', line 63
+
+def ( key , value = nil )
+ if value and @response [ key ]
+ @response [ key ] . delete ( value )
+ else
+ @response . delete ( key )
+ end
+end
+
+
+
+
+
+
+
+
+ #finalize ⇒ Array(Integer,Hash,Array)
+
+
+
+
+
+
+
+
+
Return internal representation of Rack response
+
+
+
+
+
+
+
+
+
+
+25
+26
+27
+
+
+ # File 'lib/hyde/response.rb', line 25
+
+def finalize
+ [ @status , @headers , @body ]
+end
+
+
+
+
+
+
+
+
+
+
Make internal representation conformant
+
+
+
+
+
+
+
+
+
+
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+
+
+ # File 'lib/hyde/response.rb', line 31
+
+def validate
+ if [ 204 , 304 ] . include? ( @status ) or ( 100 .. 199 ) . include? ( @status )
+ @headers . delete " content-length "
+ @headers . delete " content-type "
+ @body = [ ]
+ elsif @headers . empty?
+ @headers = {
+ " content-length " => content_size ,
+ " content-type " => " text/html "
+ }
+ end
+ @body = self . class . chunk_body ( @body ) if @body . is_a? String
+ self
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/ServeHandler.html b/doc/Hyde/ServeHandler.html
new file mode 100644
index 0000000..eb34b2e
--- /dev/null
+++ b/doc/Hyde/ServeHandler.html
@@ -0,0 +1,476 @@
+
+
+
+
+
+
+ Class: Hyde::ServeHandler
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::ServeHandler
+
+
+
+
+
+
+
+ Inherits:
+
+ Probe
+
+
+ Object
+
+ Node
+
+ Probe
+
+ Hyde::ServeHandler
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/probe/serve_handler.rb
+
+
+
+
+
Overview
+
+
+
Probe that sends files from a location
+
+
+
+
+
+
+
+
+
+
+
+
Instance Attribute Summary collapse
+
+
+
+
+
+ #response ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute response.
+
+
+
+
+
+
+
+
+
+
+
+
Attributes inherited from Probe
+
#properties
+
+
+
+
Attributes inherited from Node
+
#remap , #root
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Methods inherited from Node
+
#go , #reject
+
+
Constructor Details
+
+
+
+
+ #initialize (path, parent:) ⇒ ServeHandler
+
+
+
+
+
+
+
+
+
Returns a new instance of ServeHandler.
+
+
+
+
+
+
+
+
+
+
+12
+13
+14
+
+
+ # File 'lib/hyde/probe/serve_handler.rb', line 12
+
+def initialize ( path , parent: )
+ super ( path , parent: parent )
+end
+
+
+
+
+
+
+
+
+
Instance Attribute Details
+
+
+
+
+
+
+ #response ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute response.
+
+
+
+
+
+
+
+
+
+
+
+
+
+16
+17
+18
+
+
+ # File 'lib/hyde/probe/serve_handler.rb', line 16
+
+def response
+ @response
+end
+
+
+
+
+
+
+
+
+
+
Instance Method Details
+
+
+
+
+
+ #process (request) ⇒ Boolean
+
+
+
+
+
+
+
+
+
Method callback on successful request navigation. Tries to serve files matched by handler
+
+
+
+
+
+
+
+
+
+
+22
+23
+24
+25
+26
+27
+28
+29
+
+
+ # File 'lib/hyde/probe/serve_handler.rb', line 22
+
+def process ( request )
+ path = File . expand_path ( request . filepath )
+ return unless path . start_with? @properties [ " path " ]
+
+ File . open ( path . delete_suffix ( " / " ) )
+rescue StandardError
+ false
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/Server.html b/doc/Hyde/Server.html
new file mode 100644
index 0000000..0166536
--- /dev/null
+++ b/doc/Hyde/Server.html
@@ -0,0 +1,441 @@
+
+
+
+
+
+
+ Class: Hyde::Server
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::Server
+
+
+
+
+
+
+
+ Inherits:
+
+ Path
+
+
+ Object
+
+ Node
+
+ Path
+
+ Hyde::Server
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/server.rb
+
+
+
+
+
Overview
+
+
+
A specialized path that can be used directly as a Rack application.
+
+
+
+
+
+
+
+
+
+
+ Constant Summary
+ collapse
+
+
+
+
+ Binding =
+
+
+ ServerBinding
+
+
+
+
+
+
+
+
+
+
Instance Attribute Summary
+
+
Attributes inherited from Path
+
#children , #properties
+
+
+
+
Attributes inherited from Node
+
#remap , #root
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Methods inherited from Path
+
#filter , #postprocess , #preprocess , #process
+
+
+
+
+
+
+
+
+
+
Methods inherited from Node
+
#go , #process , #reject
+
+
Constructor Details
+
+
+
+
+ #initialize (parent: nil, &setup) ⇒ Server
+
+
+
+
+
+
+
+
+
Returns a new instance of Server.
+
+
+
+
+
+
+
+
+
+
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+
+
+ # File 'lib/hyde/server.rb', line 18
+
+def initialize ( parent: nil , & setup )
+ super ( " " , parent: parent , & setup )
+ return if parent
+
+ {
+ " index " => [ ] ,
+ " handle.default " => proc do | code , backtrace: nil |
+ page = Hyde :: Util . default_error_page ( code , backtrace )
+ = {
+ " content-length ": page . length ,
+ " content-type ": " text/html "
+ }
+ [ , page ]
+ end ,
+ " path " => " / "
+ } . each { | k , v | @properties [ k ] = v unless @properties [ k ] }
+end
+
+
+
+
+
+
+
+
+
+
Instance Method Details
+
+
+
+
+
+ #call (env) ⇒ Array(Integer,Hash,Array)
+
+
+
+
+
+
+
+
+
Rack ingress point. This should not be called under any circumstances twice in the same application, although server nesting for the purpose of creating virtual hosts is allowed.
+
+
+
+
+
+
+
+
+
+
+41
+42
+43
+44
+45
+46
+47
+48
+
+
+ # File 'lib/hyde/server.rb', line 41
+
+def call ( env )
+ request = Hyde :: Request . new ( env )
+ response = catch ( :finish ) do
+ go ( request )
+ end
+ request . run_postprocessors ( response )
+ Response . convert ( response ) . finalize
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/ServerBinding.html b/doc/Hyde/ServerBinding.html
new file mode 100644
index 0000000..ce91faf
--- /dev/null
+++ b/doc/Hyde/ServerBinding.html
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+ Class: Hyde::ServerBinding
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::ServerBinding
+
+
+
+
+
+
+
+ Inherits:
+
+ PathBinding
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/server.rb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Method Summary
+
+
Methods inherited from PathBinding
+
#initialize
+
+
+
+
+
+
+
+
+
+
+
#filter , #index , #postprocess , #preprocess , #remap , #root
+
+
+
+
+
+
+
+
+
+
+
#connect , #delete , #get , #head , #options , #patch , #path , #post , #probe , #put , #register , #serve , #trace
+
+
Constructor Details
+
+
This class inherits a constructor from Hyde::PathBinding
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/TRACEHandler.html b/doc/Hyde/TRACEHandler.html
new file mode 100644
index 0000000..30a8e7e
--- /dev/null
+++ b/doc/Hyde/TRACEHandler.html
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+ Class: Hyde::TRACEHandler
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::TRACEHandler
+
+
+
+
+
+
+
+ Inherits:
+
+ GETHandler
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/probe/http_method.rb
+
+
+
+
+
Overview
+
+
+
Probe that executes callback on a TRACE
+
+
+
+
+
+
+
+
+
+
+ Constant Summary
+ collapse
+
+
+
+
+ METHOD =
+
+
+ " TRACE "
+
+
+
+
+
+
+
+
+
+
Instance Attribute Summary
+
+
Attributes inherited from Handler
+
#request , #response
+
+
+
+
Attributes inherited from Probe
+
#properties
+
+
+
+
Attributes inherited from Node
+
#remap , #root
+
+
+
+
+
+
+
+
+
+
Method Summary
+
+
Methods inherited from GETHandler
+
#process
+
+
+
+
+
+
+
+
+
+
Methods inherited from Handler
+
#initialize , #process
+
+
+
+
+
+
+
+
+
+
Methods inherited from Probe
+
#initialize , #process
+
+
+
+
+
+
+
+
+
+
Methods inherited from Node
+
#go , #initialize , #process , #reject
+
+
Constructor Details
+
+
This class inherits a constructor from Hyde::Handler
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/Util.html b/doc/Hyde/Util.html
new file mode 100644
index 0000000..c44f07c
--- /dev/null
+++ b/doc/Hyde/Util.html
@@ -0,0 +1,487 @@
+
+
+
+
+
+
+ Module: Hyde::Util
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Module: Hyde::Util
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/util/lookup.rb,
+ lib/hyde/util/html.rb, lib/hyde/util/query.rb
+
+
+
+
+
+
Overview
+
+
+
Various things that exists for purely logical reasons
+
+
+
+
+
+
+
+
Defined Under Namespace
+
+
+
+
+
+ Classes: Lookup , Query
+
+
+
+
+
+
+ Constant Summary
+ collapse
+
+
+
+
+ HTTP_STATUS =
+
+
+
+
+
+
+ {
+ 100 => ' Continue ' ,
+ 101 => ' Switching Protocols ' ,
+ 200 => ' OK ' ,
+ 201 => ' Created ' ,
+ 202 => ' Accepted ' ,
+ 203 => ' Non-Authoritative Information ' ,
+ 204 => ' No Content ' ,
+ 205 => ' Reset Content ' ,
+ 206 => ' Partial Content ' ,
+ 207 => ' Multi-Status ' ,
+ 300 => ' Multiple Choices ' ,
+ 301 => ' Moved Permanently ' ,
+ 302 => ' Found ' ,
+ 303 => ' See Other ' ,
+ 304 => ' Not Modified ' ,
+ 305 => ' Use Proxy ' ,
+ 307 => ' Temporary Redirect ' ,
+ 400 => ' Bad Request ' ,
+ 401 => ' Unauthorized ' ,
+ 402 => ' Payment Required ' ,
+ 403 => ' Forbidden ' ,
+ 404 => ' Not Found ' ,
+ 405 => ' Method Not Allowed ' ,
+ 406 => ' Not Acceptable ' ,
+ 407 => ' Proxy Authentication Required ' ,
+ 408 => ' Request Timeout ' ,
+ 409 => ' Conflict ' ,
+ 410 => ' Gone ' ,
+ 411 => ' Length Required ' ,
+ 412 => ' Precondition Failed ' ,
+ 413 => ' Request Entity Too Large ' ,
+ 414 => ' Request-URI Too Large ' ,
+ 415 => ' Unsupported Media Type ' ,
+ 416 => ' Request Range Not Satisfiable ' ,
+ 417 => ' Expectation Failed ' ,
+ 422 => ' Unprocessable Entity ' ,
+ 423 => ' Locked ' ,
+ 424 => ' Failed Dependency ' ,
+ 426 => ' Upgrade Required ' ,
+ 428 => ' Precondition Required ' ,
+ 429 => ' Too Many Requests ' ,
+ 431 => ' Request Header Fields Too Large ' ,
+ 451 => ' Unavailable For Legal Reasons ' ,
+ 500 => ' Internal Server Error ' ,
+ 501 => ' Not Implemented ' ,
+ 502 => ' Bad Gateway ' ,
+ 503 => ' Service Unavailable ' ,
+ 504 => ' Gateway Timeout ' ,
+ 505 => ' HTTP Version Not Supported ' ,
+ 507 => ' Insufficient Storage ' ,
+ 511 => ' Network Authentication Required '
+} . freeze
+
+
+
+
+
+
+
+
+
+
+
+
+ Class Method Summary
+ collapse
+
+
+
+
+
+
+
+
+
Class Method Details
+
+
+
+
+
+ .default_error_page (code, backtrace) ⇒ String
+
+
+
+
+
+
+
+
+
Default error page for Hyde
+
+
+
+
+
+
+
+
+
+
+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
+
+
+ # File 'lib/hyde/util/html.rb', line 78
+
+def self . default_error_page ( code , backtrace )
+ backtrace ||= [ ]
+ errortext = HTTP_STATUS [ code ]
+ <<~HTMLEOF
+ <!DOCTYPE HTML>
+ <html>
+ <head>
+ <title> #{ Util . escape_html ( errortext ) } </title>
+ <style> .header {padding: 0.5rem; overflow: auto;} .title { font-weight: bolder; font-size: 48px; margin: 10px 10px; text-shadow: 1px 1px 1px #202222, 2px 2px 2px #404444; float: left } body { margin: 0; } .text { font-size 1rem; } .small { color: #7D7D7D; font-size: 12px;} .code { font-family: monospace; font-size: 0.7rem; } </style>
+ </head>
+ <body>
+ <div class="header">
+ <p class="title">HYDE</p>
+ <p style="float: right"><a href="https://adastra7.net/git/yessiest/hyde">Source code</a></p>
+ </div>
+ <div style="padding: 0.5rem">
+ <p class="text"> #{ Util . escape_html ( errortext ) } </p>
+ <pre><code class="text code">
+ #{ backtrace . map ( & Util . method ( : escape_html ) ) . join ( ' <br/> ' ) }
+ </code></pre>
+ <hr/>
+ <p class="small"> #{ Util . escape_html ( Hyde :: VLINE ) } </p>
+ </div>
+ </body>
+ </html>
+ HTMLEOF
+ end
+
+
+
+
+
+
+
+
+ .escape_html (str) ⇒ String
+
+
+
+
+
+
+
+
+
Return string with escaped HTML entities
+
+
+
+
+
+
+
+
+
+
+64
+65
+66
+67
+68
+69
+70
+
+
+ # File 'lib/hyde/util/html.rb', line 64
+
+def self . escape_html ( str )
+ str . gsub ( " & " , " & " )
+ . gsub ( " < " , " < " )
+ . gsub ( " > " , " > " )
+ . gsub ( " \" " , " " " )
+ . gsub ( " ' " , " ' " )
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/Util/Lookup.html b/doc/Hyde/Util/Lookup.html
new file mode 100644
index 0000000..6af3b6f
--- /dev/null
+++ b/doc/Hyde/Util/Lookup.html
@@ -0,0 +1,613 @@
+
+
+
+
+
+
+ Class: Hyde::Util::Lookup
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::Util::Lookup
+
+
+
+
+
+
+
+ Inherits:
+
+ Object
+
+
+ Object
+
+ Hyde::Util::Lookup
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/util/lookup.rb
+
+
+
+
+
Overview
+
+
+
Value container with recursive lookup
+
+
+
+
+
+
+
+
+
+
+
+
Instance Attribute Summary collapse
+
+
+
+
+
+ #parent ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Returns the value of attribute parent.
+
+
+
+
+
+
+
+
+
+
+
+
+ Class Method Summary
+ collapse
+
+
+
+
+
+
+
+ .[] (hash) ⇒ Object
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Initialize a Lookup from Hash.
+
+
+
+
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
Constructor Details
+
+
+
+
+ #initialize (parent = nil, hash = {}) ⇒ Lookup
+
+
+
+
+
+
+
+
+
Returns a new instance of Lookup.
+
+
+
+
+
+
+
+
+
+
+9
+10
+11
+12
+
+
+ # File 'lib/hyde/util/lookup.rb', line 9
+
+def initialize ( parent = nil , hash = { } )
+ @parent = ( parent or Hash . new ( nil ) )
+ @storage = hash
+end
+
+
+
+
+
+
+
+
+
Instance Attribute Details
+
+
+
+
+
+
+ #parent ⇒ Object
+
+
+
+
+
+
+
+
+
Returns the value of attribute parent.
+
+
+
+
+
+
+
+
+
+
+
+
+
+34
+35
+36
+
+
+ # File 'lib/hyde/util/lookup.rb', line 34
+
+def parent
+ @parent
+end
+
+
+
+
+
+
+
+
+
+
Class Method Details
+
+
+
+
+
+ .[] (hash) ⇒ Object
+
+
+
+
+
+
+
+
+
Initialize a Lookup from Hash
+
+
+
+
+
+
+
+
+
+
+16
+17
+18
+
+
+ # File 'lib/hyde/util/lookup.rb', line 16
+
+def self . [] ( hash )
+ Lookup . new ( nil , Hash [ hash ] )
+end
+
+
+
+
+
+
+
+
+
Instance Method Details
+
+
+
+
+
+ #[] (key) ⇒ Object ?
+
+
+
+
+
+
+
+
+
Get a value by key
+
+
+
+
+
+
+
+
+
+
+23
+24
+25
+
+
+ # File 'lib/hyde/util/lookup.rb', line 23
+
+def [] ( key )
+ @storage [ key ] or @parent [ key ]
+end
+
+
+
+
+
+
+
+
+ #[]= (key, value) ⇒ Object
+
+
+
+
+
+
+
+
+
Set a value by key
+
+
+
+
+
+
+
+
+
+
+30
+31
+32
+
+
+ # File 'lib/hyde/util/lookup.rb', line 30
+
+def []= ( key , value )
+ @storage [ key ] = value
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/Hyde/Util/Query.html b/doc/Hyde/Util/Query.html
new file mode 100644
index 0000000..120361b
--- /dev/null
+++ b/doc/Hyde/Util/Query.html
@@ -0,0 +1,402 @@
+
+
+
+
+
+
+ Class: Hyde::Util::Query
+
+ — Documentation by YARD 0.9.34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Class: Hyde::Util::Query
+
+
+
+
+
+
+
+ Inherits:
+
+ Object
+
+
+ Object
+
+ Hyde::Util::Query
+
+
+ show all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defined in:
+ lib/hyde/util/query.rb
+
+
+
+
+
Overview
+
+
+
Query string parser
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Instance Method Summary
+ collapse
+
+
+
+
+
+
+
+ #initialize (query) ⇒ Query
+
+
+
+
+
+
+ constructor
+
+
+
+
+
+
+
+
+
+
A new instance of Query.
+
+
+
+
+
+
+
+
+ #parse ⇒ Hash
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Better(tm) query parser with Returns a hash with arrays Key semantics:.
+
+
+
+
+
+
+
+
+ #parse_shallow ⇒ Hash
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Shallow query parser (does not do PHP-like array keys).
+
+
+
+
+
+
+
+
+
+
Constructor Details
+
+
+
+
+ #initialize (query) ⇒ Query
+
+
+
+
+
+
+
+
+
Returns a new instance of Query.
+
+
+
+
+
+
+
+
+
+
+10
+11
+12
+
+
+ # File 'lib/hyde/util/query.rb', line 10
+
+def initialize ( query )
+ @query = query
+end
+
+
+
+
+
+
+
+
+
+
Instance Method Details
+
+
+
+
+
+ #parse ⇒ Hash
+
+
+
+
+
+
+
+
+
Better(tm) query parser with Returns a hash with arrays Key semantics:
+
+‘key=value` creates a key value pair
+
+‘key[]=value` appends `value` to an array named `key`
+
+‘key =value` sets `value` at `index` of array named `key`
+
+
+
+
+
+
+
+
+
+
+
+30
+31
+32
+
+
+ # File 'lib/hyde/util/query.rb', line 30
+
+def parse
+ construct_deep_hash ( URI . decode_www_form ( @query , Encoding :: UTF_8 ) )
+end
+
+
+
+
+
+
+
+
+ #parse_shallow ⇒ Hash
+
+
+
+
+
+
+
+
+
Shallow query parser (does not do PHP-like array keys)
+
+
+
+
+
+
+
+
+
+
+16
+17
+18
+19
+20
+
+
+ # File 'lib/hyde/util/query.rb', line 16
+
+def parse_shallow
+ URI . decode_www_form ( @query , Encoding :: UTF_8 )
+ . sort_by { | array | array [ 0 ] }
+ . to_h
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/_index.html b/doc/_index.html
index e298db3..fe474d2 100644
--- a/doc/_index.html
+++ b/doc/_index.html
@@ -76,10 +76,54 @@
+
+
+
+
+
+
G
+
+ GETHandler
+
+ (Hyde)
+
+
+
Glob
@@ -95,6 +139,20 @@
H
+
+ L
+
+
+
+ Lookup
+
+ (Hyde::Util)
+
+
+
+
+
+
+
+
+ N
+
+
+
+ Node
+
+ (Hyde)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Q
+
+
+
+ Query
+
+ (Hyde::Util)
+
+
+
@@ -151,6 +328,79 @@
+
+ Request
+
+ (Hyde)
+
+
+
+
+ Response
+
+ (Hyde)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ U
+
+
+
+ Util
+
+ (Hyde)
+
+
+
@@ -163,7 +413,7 @@
diff --git a/doc/class_list.html b/doc/class_list.html
index f991863..5f73cb9 100644
--- a/doc/class_list.html
+++ b/doc/class_list.html
@@ -43,7 +43,7 @@
-Glob < Object
Hyde::PatternMatching ReMatch < Object
Hyde::PatternMatching
+Glob < Object
Hyde::PatternMatching ReMatch < Object
Hyde::PatternMatching
diff --git a/doc/file.README.html b/doc/file.README.html
index 087fef9..0af2f42 100644
--- a/doc/file.README.html
+++ b/doc/file.README.html
@@ -67,108 +67,103 @@
A simple "Hello, World!" HTTP API using Hyde
-require ' Hyde '
+require ' hyde '
-server = Hyde :: Server . new Port: 8000 do
- get " /hello " do | ctx |
- ctx . response . body = " Hello, World! "
- ctx . response [ ' Content-Type ' ] = " text/plain "
- end
+app = Hyde :: Server . new do
+ get " /hello " do
+ " content-type " , " text/plain "
+ " Hello world! "
+ end
end
-server . start
+run app
A push/pull stack as an HTTP API
require ' hyde '
-Stack = [ ]
+stack = [ ]
-server = Hyde :: Server . new Port: 8000 do
- get " pull " do | ctx |
- ctx . response . body = " #{ Stack . pop } "
- ctx . response [ " Content-Type " ] = " text/plain "
- end
- post " push " do | ctx |
- Stack . push ctx . request . body
- ctx . response . body = " #{ ctx . request . body } "
- ctx . response [ " Content-Type " ] = " text/plain "
- end
+app = Hyde :: Server . new do
+ get " /pop " do
+ ' content-type ' , ' text/plain '
+ stack . pop . to_s
+ end
+ post " /push " do
+ ' content-type ' , ' text/plain '
+ stack . push ( request . body )
+ request . body
+ end
end
-server . start
+run app
Several push/pull buckets
require ' hyde '
-Stack = { " bucket_1 " => [ ] , " bucket_2 " => [ ] , " bucket_3 " => [ ] }
+stack = { " 1 " => [ ] , " 2 " => [ ] , " 3 " => [ ] }
-server = Hyde :: Server . new Port: 8000 do
- path [ " bucket_1 " , " bucket_2 " , " bucket_3 " ] do
- get " pull " do | ctx |
- bucket_name = ( ctx . filepath . match / bucket_[^\/]* / ) [ 0 ]
- ctx . response . body = " #{ Stack [ bucket_name ] . pop } "
- ctx . response [ " Content-Type " ] = " text/plain "
- end
- post " push " do | ctx |
- bucket_name = ( ctx . filepath . match / bucket_[^\/]* / ) [ 0 ]
- Stack [ bucket_name ] . push ctx . request . body
- ctx . response . body = " #{ ctx . request . body } "
- ctx . response [ " Content-Type " ] = " text/plain "
- end
+app = Hyde :: Server . new do
+ path " bucket_(1|2|3) " do
+ get " pop " do | bucket |
+ " content-type " , " text/plain "
+ stack [ bucket ] . pop . to_s
end
+ post " push " do | bucket |
+ " content-type " , " text/plain "
+ stack [ bucket ] . push ( request . body )
+ request . body
+ end
+ end
end
-server . start
+run app
Static file serving
(Note: index applies only to /var/www (to the path its defined in))
-require 'hyde'
+require ' hyde '
-server = Hyde::Server.new Port:8000 do
- path "static" do
- root "/var/www"
- index ["index.html","index.htm"]
- serve "*/*.html" safe_regexp: false
- serve "*.html"
- end
-end
+app = Hyde :: Server . new do
+ root " /var/www "
+ index [ " index.html " , " index.htm " ]
+ serve " **/*.(html|htm) "
+end
-server.start
+run app
Logging on a particular path
require ' hyde '
-server = Hyde :: Server . new Port: 8000 do
- path " unimportant " do
- get " version " do | ctx |
- ctx . response . body = ' {"version": "the good one"} '
- ctx . response [ ' Content-Type ' ] = " application/json "
- end
+app = Hyde :: Server . new do
+ path " unimportant " do
+ get " version " do
+ " content-type " , " text/plain "
+ " 1337 (the best one) "
end
- path " important " do
- preprocess do | ctx |
- puts " Client at #{ ctx . request . remote_ip } wanted to access something /important! "
- end
- get " answer " do | ctx |
- ctx . response . body = ' {"answer":42} '
- ctx . response [ ' Content-Type ' ] = " application/json "
- end
+ end
+ path " important " do
+ preprocess do | req |
+ puts " Client at #{ req . [ ' REMOTE_ADDR ' ] } wanted to access something /important! "
end
+ get " answer " do
+ " content-type " , " application/json "
+ ' {"answer":42, "desc":"something important!"} '
+ end
+ end
end
-server . start
+run app
-And a lot more to come (hopefully)
+And a lot more to be found in /examples in this repo.
Documentation
@@ -195,7 +190,7 @@ server.start
diff --git a/doc/index.html b/doc/index.html
index cb12e47..9ae2507 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -67,108 +67,103 @@
A simple "Hello, World!" HTTP API using Hyde
-require ' Hyde '
+require ' hyde '
-server = Hyde :: Server . new Port: 8000 do
- get " /hello " do | ctx |
- ctx . response . body = " Hello, World! "
- ctx . response [ ' Content-Type ' ] = " text/plain "
- end
+app = Hyde :: Server . new do
+ get " /hello " do
+ " content-type " , " text/plain "
+ " Hello world! "
+ end
end
-server . start
+run app
A push/pull stack as an HTTP API
require ' hyde '
-Stack = [ ]
+stack = [ ]
-server = Hyde :: Server . new Port: 8000 do
- get " pull " do | ctx |
- ctx . response . body = " #{ Stack . pop } "
- ctx . response [ " Content-Type " ] = " text/plain "
- end
- post " push " do | ctx |
- Stack . push ctx . request . body
- ctx . response . body = " #{ ctx . request . body } "
- ctx . response [ " Content-Type " ] = " text/plain "
- end
+app = Hyde :: Server . new do
+ get " /pop " do
+ ' content-type ' , ' text/plain '
+ stack . pop . to_s
+ end
+ post " /push " do
+ ' content-type ' , ' text/plain '
+ stack . push ( request . body )
+ request . body
+ end
end
-server . start
+run app
Several push/pull buckets
require ' hyde '
-Stack = { " bucket_1 " => [ ] , " bucket_2 " => [ ] , " bucket_3 " => [ ] }
+stack = { " 1 " => [ ] , " 2 " => [ ] , " 3 " => [ ] }
-server = Hyde :: Server . new Port: 8000 do
- path [ " bucket_1 " , " bucket_2 " , " bucket_3 " ] do
- get " pull " do | ctx |
- bucket_name = ( ctx . filepath . match / bucket_[^\/]* / ) [ 0 ]
- ctx . response . body = " #{ Stack [ bucket_name ] . pop } "
- ctx . response [ " Content-Type " ] = " text/plain "
- end
- post " push " do | ctx |
- bucket_name = ( ctx . filepath . match / bucket_[^\/]* / ) [ 0 ]
- Stack [ bucket_name ] . push ctx . request . body
- ctx . response . body = " #{ ctx . request . body } "
- ctx . response [ " Content-Type " ] = " text/plain "
- end
+app = Hyde :: Server . new do
+ path " bucket_(1|2|3) " do
+ get " pop " do | bucket |
+ " content-type " , " text/plain "
+ stack [ bucket ] . pop . to_s
end
+ post " push " do | bucket |
+ " content-type " , " text/plain "
+ stack [ bucket ] . push ( request . body )
+ request . body
+ end
+ end
end
-server . start
+run app
Static file serving
(Note: index applies only to /var/www (to the path its defined in))
-require 'hyde'
+require ' hyde '
-server = Hyde::Server.new Port:8000 do
- path "static" do
- root "/var/www"
- index ["index.html","index.htm"]
- serve "*/*.html" safe_regexp: false
- serve "*.html"
- end
-end
+app = Hyde :: Server . new do
+ root " /var/www "
+ index [ " index.html " , " index.htm " ]
+ serve " **/*.(html|htm) "
+end
-server.start
+run app
Logging on a particular path
require ' hyde '
-server = Hyde :: Server . new Port: 8000 do
- path " unimportant " do
- get " version " do | ctx |
- ctx . response . body = ' {"version": "the good one"} '
- ctx . response [ ' Content-Type ' ] = " application/json "
- end
+app = Hyde :: Server . new do
+ path " unimportant " do
+ get " version " do
+ " content-type " , " text/plain "
+ " 1337 (the best one) "
end
- path " important " do
- preprocess do | ctx |
- puts " Client at #{ ctx . request . remote_ip } wanted to access something /important! "
- end
- get " answer " do | ctx |
- ctx . response . body = ' {"answer":42} '
- ctx . response [ ' Content-Type ' ] = " application/json "
- end
+ end
+ path " important " do
+ preprocess do | req |
+ puts " Client at #{ req . [ ' REMOTE_ADDR ' ] } wanted to access something /important! "
end
+ get " answer " do
+ " content-type " , " application/json "
+ ' {"answer":42, "desc":"something important!"} '
+ end
+ end
end
-server . start
+run app
-And a lot more to come (hopefully)
+And a lot more to be found in /examples in this repo.
Documentation
@@ -195,7 +190,7 @@ server.start
diff --git a/doc/method_list.html b/doc/method_list.html
index 4ddfb6b..43b0bf2 100644
--- a/doc/method_list.html
+++ b/doc/method_list.html
@@ -44,6 +44,70 @@
+
+
+
[]
+
Hyde::Util::Lookup
+
+
+
+
+
+
+
#[]
+
Hyde::Util::Lookup
+
+
+
+
+
+
+
#[]=
+
Hyde::Util::Lookup
+
+
+
+
+
+
+
+
+
+
+
+
#body
+
Hyde::Request
+
+
+
+
+
+
+
#body
+
Hyde::Response
+
+
+
+
+
+
+
#bounce
+
Hyde::DSL::ProbeMethods
+
+
+
+
+
+
+
+
+
can_convert?
@@ -68,6 +132,262 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#connect
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#delete
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
#die
+
Hyde::DSL::ProbeMethods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#filter
+
Hyde::DSL::PathMethods
+
+
+
+
+
+
+
+
+
+
+
+
#get
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
#head
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
#header
+
Hyde::DSL::ProbeMethods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#index
+
Hyde::DSL::PathMethods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#initialize
@@ -77,6 +397,14 @@
+
+
+
+
+
#initialize
Hyde::PatternMatching::Glob
@@ -84,7 +412,7 @@
-
+
#initialize
Hyde::PatternMatching::ReMatch
@@ -92,7 +420,7 @@
-
+
#match
Hyde::Pattern
@@ -100,7 +428,7 @@
-
+
#match
Hyde::PatternMatching::Glob
@@ -108,7 +436,7 @@
-
+
#match
Hyde::PatternMatching::ReMatch
@@ -116,7 +444,7 @@
-
+
#match?
Hyde::Pattern
@@ -124,7 +452,7 @@
-
+
#match?
Hyde::PatternMatching::Glob
@@ -132,7 +460,7 @@
-
+
#match?
Hyde::PatternMatching::ReMatch
@@ -140,6 +468,382 @@
+
+
+
#options
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#parse
+
Hyde::Util::Query
+
+
+
+
+
+
+
+
+
+
+
+
#patch
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
#path
+
Hyde::Request
+
+
+
+
+
+
+
#path
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#post
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#probe
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#put
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#remap
+
Hyde::DSL::PathMethods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#root
+
Hyde::DSL::PathMethods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#serve
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#static?
@@ -148,6 +852,38 @@
+
+
+
+
+
+
+
+
#status
+
Hyde::DSL::ProbeMethods
+
+
+
+
+
+
+
#trace
+
Hyde::DSL::PathConstructors
+
+
+
+
+
+
+
+
+
diff --git a/doc/top-level-namespace.html b/doc/top-level-namespace.html
index 96455f7..6ebc842 100644
--- a/doc/top-level-namespace.html
+++ b/doc/top-level-namespace.html
@@ -100,7 +100,7 @@
diff --git a/examples/form/form.ru b/examples/form/form.ru
new file mode 100644
index 0000000..ccb7806
--- /dev/null
+++ b/examples/form/form.ru
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")
+require 'hyde'
+require 'hyde/util/multipart'
+require 'hyde/util/header'
+
+app = Hyde::Server.new do
+ root ENV["PWD"]
+ index ["index.html"]
+ post "/" do
+ _, opts = Hyde::Util.parse_value(request.headers["content-type"])
+ puts Hyde::Util::MultipartParser.new(
+ request.input, opts["boundary"]
+ ).to_h.pretty_inspect
+ bounce
+ end
+ serve "*.html"
+end
+
+run app
diff --git a/examples/form/index.html b/examples/form/index.html
new file mode 100644
index 0000000..bb209c2
--- /dev/null
+++ b/examples/form/index.html
@@ -0,0 +1,27 @@
+
+
+
+ Form upload test
+
+
+
+ Form upload test
+
+ Please enter the following details:
+
+
+
+
+
diff --git a/examples/form/lib b/examples/form/lib
new file mode 120000
index 0000000..58677dd
--- /dev/null
+++ b/examples/form/lib
@@ -0,0 +1 @@
+../../lib
\ No newline at end of file
diff --git a/examples/query/config.ru b/examples/query/config.ru
new file mode 100644
index 0000000..588afb6
--- /dev/null
+++ b/examples/query/config.ru
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")
+require_relative 'lib/hyde'
+
+app = Hyde::Server.new do
+ get "/hello" do
+ name = request.query["name"]
+ if name.is_a? String
+ "Hello #{name.downcase.capitalize}!"
+ elsif name.is_a? Array
+ "Hello #{name.map { |x| x.downcase.capitalize }.join(', ')}!"
+ else
+ "Hello user!"
+ end
+ end
+end
+
+run app
diff --git a/examples/query/lib b/examples/query/lib
new file mode 120000
index 0000000..58677dd
--- /dev/null
+++ b/examples/query/lib
@@ -0,0 +1 @@
+../../lib
\ No newline at end of file
diff --git a/examples/query/readme.txt b/examples/query/readme.txt
new file mode 100644
index 0000000..1295126
--- /dev/null
+++ b/examples/query/readme.txt
@@ -0,0 +1,6 @@
+This example illustrates a basic API that responds with "Hello !" and receives arrays and strings as parameter.
+
+P.S. there is at least *one* vulnerability in this exmaple.
+If you don't know which one you definitely want to read about XSS before it's too late
+(https://owasp.org/www-community/attacks/xss/)
+
diff --git a/lib/hyde/request.rb b/lib/hyde/request.rb
index 6681294..27e0b85 100644
--- a/lib/hyde/request.rb
+++ b/lib/hyde/request.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'uri'
+require_relative 'util/query'
module Hyde
# Request wrapper for Rack protocol
@@ -11,6 +12,8 @@ module Hyde
@_original_env = env
# Rack environment variable bindings. Should be public and frozen.
init_request_params(env)
+ # Query parsing
+ @query = Hyde::Util::Query.new(@query_string)
# Pattern matching parameters. Public, readable, unfrozen.
@param = {}
@splat = []
@@ -37,7 +40,13 @@ module Hyde
# Returns request body (if POST data exists)
# @return [nil, String]
def body
- @body ||= @rack.input&.gets
+ @body ||= @rack.input&.read
+ end
+
+ # Returns raw Rack input object
+ # @return [IO] (May not entirely be compatible with IO, see Rack/SPEC.rdoc)
+ def input
+ @rack.input
end
# Push current navigation state (path, splat, param) onto state stack
@@ -52,7 +61,7 @@ module Hyde
attr_reader :request_method, :script_name, :path_info, :server_name,
:server_port, :server_protocol, :headers, :param, :splat,
- :postprocessors
+ :postprocessors, :query
attr_accessor :path, :filepath
private
@@ -63,6 +72,7 @@ module Hyde
@request_method = env["REQUEST_METHOD"]
@script_name = env["SCRIPT_NAME"]
@path_info = env["PATH_INFO"]
+ @query_string = env["QUERY_STRING"]
@server_name = env["SERVER_NAME"]
@server_port = env["SERVER_PORT"]
@server_protocol = env["SERVER_PROTOCOL"]
@@ -111,10 +121,12 @@ module Hyde
headers = env.filter_map do |name, value|
[name.delete_prefix("HTTP_"), value] if name.start_with?("HTTP_")
end.to_h
- headers.merge!({ "CONTENT_TYPE" => env["CONTENT_TYPE"],
- "CONTENT_LENGTH" => env["CONTENT_LENGTH"],
+ headers.merge!({ "CONTENT-TYPE" => env["CONTENT_TYPE"],
+ "CONTENT-LENGTH" => env["CONTENT_LENGTH"],
"REMOTE_ADDR" => env["REMOTE_ADDR"] })
- headers.freeze
+ headers.transform_keys do |x|
+ x.downcase.gsub("_", "-") if x.is_a? String
+ end.freeze
end
end
end
diff --git a/lib/hyde/util/header.rb b/lib/hyde/util/header.rb
new file mode 100644
index 0000000..54671c1
--- /dev/null
+++ b/lib/hyde/util/header.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'uri'
+
+module Hyde
+ module Util
+ # Parse parametrized header values
+ # @param input [String]
+ # @param sep [String, Regexp]
+ # @return [Array(String, Hash)]
+ def self.parse_value(input, sep = ";")
+ parts = input.split(sep).map { |x| URI.decode_uri_component(x).strip }
+ base = parts.shift
+ opts = parts.map do |raw|
+ key, value = raw.match(/^([^=]*)(?:=(.*)|)\Z/).to_a[1..]
+ [key, ((value&.match?(/^".*"$/) ? value[1..-2] : value) or true)]
+ end.to_h
+ [base, opts]
+ end
+
+ # Construct a parametrized header value
+ # @param input [String]
+ # @param opts [Hash]
+ # @return [String]
+ def self.make_value(input, opts, sep = ";")
+ unless input.match?(/^[\w!#$%&'*+-.^_`|~]*=?[^[:cntrl:]\\",;]+$/)
+ raise StandardError, "input contains invalid characters"
+ end
+
+ output = input
+ opts.each do |key, value|
+ output += if value.is_a? String
+ "#{sep} #{key}=#{value}"
+ else
+ "#{sep} #{key}"
+ end
+ end
+ output
+ end
+ end
+end
diff --git a/lib/hyde/util/html.rb b/lib/hyde/util/html.rb
index ed797f2..867815f 100644
--- a/lib/hyde/util/html.rb
+++ b/lib/hyde/util/html.rb
@@ -58,7 +58,10 @@ module Hyde
511 => 'Network Authentication Required'
}.freeze
- # Return string with escaped HTML entities
+ # Return string with escaped HTML entities.
+ # @note Do **not** use this to inject untrusted input into JavaScript code
+ # or CSS style of the page.
+ # This function is not adequate to prevent string interpolation.
# @param str [String]
# @return [String]
def self.escape_html(str)
diff --git a/lib/hyde/util/multipart.rb b/lib/hyde/util/multipart.rb
new file mode 100644
index 0000000..8b589ad
--- /dev/null
+++ b/lib/hyde/util/multipart.rb
@@ -0,0 +1,165 @@
+# frozen_string_literal: false
+
+require 'uri'
+require 'stringio'
+require 'tempfile'
+require_relative 'header'
+
+module Hyde
+ module Util
+ # Valid element of form data with headers
+ # @!attribute headers [Hash] headers recevied from form data
+ # @!attribute name [String] name of the form part
+ # @!attribute data [String,nil] Data received in the field through form data
+ # @!attribute filename [String,nil] Original name of the sent file
+ # @!attribute filetype [String,nil] MIME-type of the file
+ # @!attribute tempfile [File,nil] Temporary file for storing sent file data.
+ FormPart = Struct.new(:data, :name, :filename,
+ :filetype, :tempfile, :headers) do
+ # Is this form part a file or plain data?
+ # @return [Boolean]
+ def file?
+ !tempfile.nil?
+ end
+
+ # If FormPart is not a file, simplify to string.
+ # @return [FormPart, String]
+ def simplify
+ file? ? self : self.data
+ end
+ end
+
+ # A very naive implementation of a Multipart form parser.
+ class MultipartParser
+ include Hyde::Util::ParserCommon
+ def initialize(io, boundary)
+ @input = io.is_a?(String) ? StringIO.new(io) : io
+ @boundary = boundary
+ @state = :idle
+ @data = []
+ end
+
+ # lord forgive me for what i'm about to do
+ # TODO: replace the god method with a state machine object
+ # rubocop:disable Metrics/*
+
+ # Parse multipart formdata
+ # @return [Array]
+ def parse
+ return @data unless @data.empty?
+
+ while (line = @input.gets)
+ case @state
+ when :idle # waiting for valid boundary
+ if line == "--#{@boundary}\r\n"
+ # transition to :headers on valid boundary
+ @state = :headers
+ @data.append(FormPart.new(*([nil] * 5), {}))
+ end
+ when :headers # after valid boundary - checking for headers
+ if line == "\r\n"
+ # prepare form field and transition to :data or :file
+ @state = file?(@data[-1].headers) ? :file : :data
+ if @state == :data
+ setup_data_meta(@data[-1])
+ else
+ setup_file_meta(@data[-1])
+ end
+ next
+ end
+ push_header(line, @data[-1].headers)
+ when :data, :file # after headers - processing form data
+ if @data[-1].headers.empty?
+ # transition to :idle on empty headers
+ @state = :idle
+ next
+ end
+ if ["--#{@boundary}\r\n", "--#{@boundary}--\r\n"].include? line
+ # finalize and transition to either :headers or :idle
+ if @state == :file
+ @data[-1].tempfile.truncate(@data[-1].tempfile.size - 2)
+ @data[-1].tempfile.close
+ else
+ @data[-1].data.delete_suffix! "\r\n"
+ end
+ @state = line == "--#{@boundary}\r\n" ? :headers : :idle
+ @data.append(FormPart.new(*([nil] * 5), {}))
+ next
+ end
+ if @state == :data
+ @data[-1].data ||= ""
+ @data[-1].data << line
+ else
+ @data[-1].tempfile << line
+ end
+ end
+ end
+ @state = :idle
+ @data.pop
+ @data.freeze
+ end
+ # rubocop:enable Metrics/*
+
+ # Return a hash of current form.
+ # (equivalent to Query.parse but for multipart/form-data)
+ # @return [Hash]
+ def to_h
+ flatten(sort(gen_hash(parse)))
+ end
+
+ private
+
+ def gen_hash(array)
+ hash = {}
+ array.each do |formpart|
+ key = formpart.name.to_s
+ if key.match?(/.*\[\d*\]\Z/)
+ new_key, index = key.match(/(.*)\[(\d*)\]\Z/).to_a[1..]
+ hash[new_key] = [] unless hash[new_key]
+ hash[new_key].append([index, formpart.simplify])
+ else
+ hash[key] = formpart.simplify
+ end
+ end
+ hash
+ end
+
+ # Setup file metadata
+ # @part part [FormPart]
+ def setup_file_meta(part)
+ part.name = part.headers.dig("content-disposition", 1, "name")
+ part.filename = part.headers.dig("content-disposition", 1, "filename")
+ part.filetype = part.headers["content-type"]
+ part.tempfile = Tempfile.new
+ end
+
+ # Setup plain metadata
+ # @part part [FormPart]
+ def setup_data_meta(part)
+ part.name = part.headers.dig("content-disposition", 1, "name")
+ end
+
+ # Analyze headers to check if current data part is a file.
+ # @param headers_hash [Hash]
+ # @return [Boolean]
+ def file?(headers_hash)
+ if headers_hash.dig("content-disposition", 1, "filename") and
+ headers_hash['content-type']
+ return true
+ end
+
+ false
+ end
+
+ # Parse a header and append it to headers_hash
+ # @param line [String]
+ # @param headers_hash [Hash]
+ def push_header(line, headers_hash)
+ return unless line.match(/^[\w!#$%&'*+-.^_`|~]+:.*\r\n$/)
+
+ k, v = line.match(/^([\w!#$%&'*+-.^_`|~]+):(.*)\r\n$/).to_a[1..]
+ headers_hash[k.downcase] = Hyde::Util.parse_value(v)
+ end
+ end
+ end
+end
diff --git a/lib/hyde/util/query.rb b/lib/hyde/util/query.rb
new file mode 100644
index 0000000..24858f0
--- /dev/null
+++ b/lib/hyde/util/query.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'uri'
+require_relative 'sorting'
+
+module Hyde
+ module Util
+ # Query string parser
+ class Query
+ include Hyde::Util::ParserCommon
+ # @param query [String]
+ def initialize(query)
+ @query = query
+ end
+
+ # Shallow query parser (does not do PHP-like array keys)
+ # @return [Hash]
+ def parse_shallow
+ URI.decode_www_form(@query, Encoding::UTF_8)
+ .sort_by { |array| array[0] }
+ .to_h
+ end
+
+ # Better(tm) query parser with
+ # Returns a hash with arrays
+ # Key semantics:
+ #
+ # - `key=value` creates a key value pair
+ # - `key[]=value` appends `value` to an array named `key`
+ # - `key[index]=value` sets `value` at `index` of array named `key`
+ # @return [Hash]
+ def parse
+ construct_deep_hash(URI.decode_www_form(@query, Encoding::UTF_8))
+ end
+
+ # Get key from query
+ # @param key [String]
+ # @return [String,Array]
+ def [](key)
+ (@cache ||= parse)[key]
+ end
+
+ private
+
+ # Construct a hash with array support
+ def construct_deep_hash(array)
+ flatten(sort(group(array)))
+ end
+
+ # Assign values to keys in a new hash and group arrayable keys
+ def group(array)
+ hash = {}
+ array.each do |key, value|
+ if key.match?(/.*\[\d*\]\Z/)
+ new_key, index = key.match(/(.*)\[(\d*)\]\Z/).to_a[1..]
+ hash[new_key] = [] unless hash[new_key]
+ hash[new_key].append([index, value])
+ else
+ hash[key] = value
+ end
+ end
+ hash
+ end
+ end
+ end
+end
diff --git a/lib/hyde/util/sorting.rb b/lib/hyde/util/sorting.rb
new file mode 100644
index 0000000..a9a1af4
--- /dev/null
+++ b/lib/hyde/util/sorting.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Hyde
+ module Util
+ # Internal library for generating form hashes
+ module ParserCommon
+ private
+
+ # Sort key-value pair arrays
+ def sort(hash)
+ hash.filter { |_, v| v.is_a? Array }.each do |_, value|
+ value.sort_by! { |array| array[0].to_i }
+ end
+ hash
+ end
+
+ # Flatten key-value pair arrays
+ def flatten(hash)
+ hash.transform_values do |value|
+ if value.is_a? Array
+ new_array = []
+ value.each do |k, v|
+ if k.match?(/\d+/) and k.to_i < new_array.size
+ new_array[k.to_i] = v
+ else
+ new_array.append(v)
+ end
+ end
+ new_array
+ else
+ value
+ end
+ end.to_h
+ end
+ end
+ end
+end
diff --git a/test/Hyde_Util_Query.rb b/test/Hyde_Util_Query.rb
new file mode 100644
index 0000000..eb9472c
--- /dev/null
+++ b/test/Hyde_Util_Query.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require_relative "../lib/hyde/util/query"
+require "test/unit"
+
+class TestQuery < Test::Unit::TestCase
+ include Hyde::Util
+ def test_query
+ test1 = Query.new("key1=1&key2=2&key3[]=1&key3[]=2&key3[]=3")
+ assert_equal({"key1"=>"1","key2"=>"2","key3"=>["1","2","3"]},test1.parse)
+ test2 = Query.new("key1[1]=1&key1[500]=3&key1[50]=2")
+ assert_equal({"key1"=>["1","2","3"]},test2.parse)
+ test3 = Query.new("array[]=1&array[]=2&array[0]=0&array[500]=3")
+ assert_equal({"array"=>["0","2","3"]},test3.parse)
+ end
+end