made form parser easier to use
This commit is contained in:
parent
bfc9a3066b
commit
bc8750daf7
|
@ -2,17 +2,12 @@
|
||||||
|
|
||||||
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")
|
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")
|
||||||
require 'hyde'
|
require 'hyde'
|
||||||
require 'hyde/util/multipart'
|
|
||||||
require 'hyde/util/header'
|
|
||||||
|
|
||||||
app = Hyde::Server.new do
|
app = Hyde::Server.new do
|
||||||
root ENV["PWD"]
|
root ENV["PWD"]
|
||||||
index ["index.html"]
|
index ["index.html"]
|
||||||
post "/" do
|
post "/" do
|
||||||
_, opts = Hyde::Util.parse_value(request.headers["content-type"])
|
puts form.pretty_inspect if form?
|
||||||
puts Hyde::Util::MultipartParser.new(
|
|
||||||
request.input, opts["boundary"]
|
|
||||||
).to_h.pretty_inspect
|
|
||||||
bounce
|
bounce
|
||||||
end
|
end
|
||||||
serve "*.html"
|
serve "*.html"
|
||||||
|
|
|
@ -12,8 +12,9 @@ app = Hyde::Server.new do
|
||||||
end
|
end
|
||||||
path "important" do
|
path "important" do
|
||||||
preprocess do |req|
|
preprocess do |req|
|
||||||
|
|
||||||
# Implement logging logic here
|
# Implement logging logic here
|
||||||
puts "Client at #{req.headers['REMOTE_ADDR']} wanted to access something /important!"
|
puts "Client at #{req.headers['remote-addr']} wanted to access something /important!"
|
||||||
end
|
end
|
||||||
get "answer" do
|
get "answer" do
|
||||||
header "content-type", "application/json"
|
header "content-type", "application/json"
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Hyde
|
||||||
|
module DSL
|
||||||
|
# Methods shared by probes, preprocessors and filters.
|
||||||
|
module CommonMethods
|
||||||
|
# Stop execution and generate a boilerplate response with the given code
|
||||||
|
# @param errorcode [Integer]
|
||||||
|
# @param backtrace [Array(String), nil]
|
||||||
|
# @raise [UncaughtThrowError] throws :finish to return back to Server
|
||||||
|
def die(errorcode, backtrace: nil)
|
||||||
|
throw :finish, [errorcode].append(
|
||||||
|
*(@origin.properties["handle.#{errorcode}"] or
|
||||||
|
@origin.properties["handle.default"]).call(
|
||||||
|
errorcode,
|
||||||
|
backtrace: backtrace
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Bounce request to the next handler
|
||||||
|
# @raise [UncaughtThrowError] throws :break to get out of the callback
|
||||||
|
def bounce
|
||||||
|
throw :break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative '../response'
|
require_relative '../response'
|
||||||
|
require_relative '../util/multipart'
|
||||||
|
require_relative '../util/header'
|
||||||
|
|
||||||
module Hyde
|
module Hyde
|
||||||
module DSL
|
module DSL
|
||||||
|
@ -12,31 +14,11 @@ module Hyde
|
||||||
@origin.request
|
@origin.request
|
||||||
end
|
end
|
||||||
|
|
||||||
# Stop execution and generate a boilerplate response with the given code
|
|
||||||
# @param errorcode [Integer]
|
|
||||||
# @param backtrace [Array(String), nil]
|
|
||||||
# @raise [UncaughtThrowError] throws :finish to return back to Server
|
|
||||||
def die(errorcode, backtrace: nil)
|
|
||||||
throw :finish, [errorcode].append(
|
|
||||||
*(@origin.properties["handle.#{errorcode}"] or
|
|
||||||
@origin.properties["handle.default"]).call(
|
|
||||||
errorcode,
|
|
||||||
backtrace: backtrace
|
|
||||||
)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Bounce request to the next handler
|
|
||||||
# @raise [UncaughtThrowError] throws :break to get out of the callback
|
|
||||||
def bounce
|
|
||||||
throw :break
|
|
||||||
end
|
|
||||||
|
|
||||||
# Set response status (generate response if one doesn't exist yet)
|
# Set response status (generate response if one doesn't exist yet)
|
||||||
# @param status [Integer] http status code
|
# @param status [Integer] http status code
|
||||||
def status(status)
|
def status(status)
|
||||||
@response = (@response or Hyde::Response.new)
|
@origin.response = (@origin.response or Hyde::Response.new)
|
||||||
@response.status = status
|
@origin.response.status = status
|
||||||
end
|
end
|
||||||
|
|
||||||
alias code status
|
alias code status
|
||||||
|
@ -79,6 +61,27 @@ module Hyde
|
||||||
|
|
||||||
@origin.response.delete_header(key, value)
|
@origin.response.delete_header(key, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Checks if current request has multipart/form-data associated with it
|
||||||
|
# @return [Boolean]
|
||||||
|
def form?
|
||||||
|
value, opts = Hyde::Util.parse_value(request.headers["content-type"])
|
||||||
|
if value == "multipart/form-data" and
|
||||||
|
opts["boundary"]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns formdata
|
||||||
|
# @return [Hash{String=>(String,Hyde::Util::FormPart)}]
|
||||||
|
def form
|
||||||
|
_, opts = Hyde::Util.parse_value(request.headers["content-type"])
|
||||||
|
Hyde::Util::MultipartParser.new(
|
||||||
|
request.input, opts["boundary"]
|
||||||
|
).to_h
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,10 +4,20 @@ require_relative 'pattern_matching'
|
||||||
require_relative 'node'
|
require_relative 'node'
|
||||||
require_relative 'dsl/path_constructors'
|
require_relative 'dsl/path_constructors'
|
||||||
require_relative 'dsl/path_methods'
|
require_relative 'dsl/path_methods'
|
||||||
|
require_relative 'dsl/common_methods'
|
||||||
require_relative 'util/lookup'
|
require_relative 'util/lookup'
|
||||||
|
|
||||||
module Hyde
|
module Hyde
|
||||||
# Protected interface that provides DSL context for setup block.
|
# Binding that provides execution context for filters and preprocessors.
|
||||||
|
class ProcessorBinding
|
||||||
|
include Hyde::DSL::CommonMethods
|
||||||
|
|
||||||
|
def initialize(path)
|
||||||
|
@origin = path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Binding that provides execution context for path setup block.
|
||||||
class PathBinding
|
class PathBinding
|
||||||
include Hyde::DSL::PathConstructors
|
include Hyde::DSL::PathConstructors
|
||||||
include Hyde::DSL::PathMethods
|
include Hyde::DSL::PathMethods
|
||||||
|
@ -19,6 +29,7 @@ module Hyde
|
||||||
|
|
||||||
# Primary building block of request navigation.
|
# Primary building block of request navigation.
|
||||||
class Path < Hyde::Node
|
class Path < Hyde::Node
|
||||||
|
ProcBinding = Hyde::ProcessorBinding
|
||||||
Binding = Hyde::PathBinding
|
Binding = Hyde::PathBinding
|
||||||
|
|
||||||
# @param path [Object] Object to generate {Hyde::Pattern} from
|
# @param path [Object] Object to generate {Hyde::Pattern} from
|
||||||
|
@ -32,9 +43,10 @@ module Hyde
|
||||||
@preprocessors = []
|
@preprocessors = []
|
||||||
@postprocessors = []
|
@postprocessors = []
|
||||||
@filters = []
|
@filters = []
|
||||||
|
# Bindings setup
|
||||||
binding = Binding.new(self)
|
binding = self.class::Binding.new(self)
|
||||||
binding.instance_exec(&setup)
|
binding.instance_exec(&setup)
|
||||||
|
@procbinding = self.class::ProcBinding.new(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Method callback on successful request navigation.
|
# Method callback on successful request navigation.
|
||||||
|
@ -92,7 +104,7 @@ module Hyde
|
||||||
# @return [Boolean] true if request passed all filters
|
# @return [Boolean] true if request passed all filters
|
||||||
def run_filters(request)
|
def run_filters(request)
|
||||||
@filters.each do |filter|
|
@filters.each do |filter|
|
||||||
return false if filter.call(request).is_a? FalseClass
|
return false unless @procbinding.instance_exec(request, &filter)
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
@ -101,7 +113,7 @@ module Hyde
|
||||||
# @param request [Hyde::Request]
|
# @param request [Hyde::Request]
|
||||||
def run_preprocessors(request)
|
def run_preprocessors(request)
|
||||||
@preprocessors.each do |preproc|
|
@preprocessors.each do |preproc|
|
||||||
preproc.call(request)
|
@procbinding.instance_exec(request, &preproc)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative "../dsl/probe_methods"
|
require_relative "../dsl/probe_methods"
|
||||||
|
require_relative "../dsl/common_methods"
|
||||||
|
|
||||||
module Hyde
|
module Hyde
|
||||||
|
# Binding that provides execution context for Probes.
|
||||||
class ProbeBinding
|
class ProbeBinding
|
||||||
|
include Hyde::DSL::ProbeMethods
|
||||||
|
include Hyde::DSL::CommonMethods
|
||||||
|
|
||||||
def initialize(origin)
|
def initialize(origin)
|
||||||
@origin = origin
|
@origin = origin
|
||||||
end
|
end
|
||||||
include Hyde::DSL::ProbeMethods
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'cgi/escape'
|
||||||
|
|
||||||
module Hyde
|
module Hyde
|
||||||
module Util
|
module Util
|
||||||
# HTTP status codes and descriptions
|
# HTTP status codes and descriptions
|
||||||
|
@ -40,6 +42,7 @@ module Hyde
|
||||||
415 => 'Unsupported Media Type',
|
415 => 'Unsupported Media Type',
|
||||||
416 => 'Request Range Not Satisfiable',
|
416 => 'Request Range Not Satisfiable',
|
||||||
417 => 'Expectation Failed',
|
417 => 'Expectation Failed',
|
||||||
|
418 => "I'm a teapot",
|
||||||
422 => 'Unprocessable Entity',
|
422 => 'Unprocessable Entity',
|
||||||
423 => 'Locked',
|
423 => 'Locked',
|
||||||
424 => 'Failed Dependency',
|
424 => 'Failed Dependency',
|
||||||
|
@ -65,11 +68,14 @@ module Hyde
|
||||||
# @param str [String]
|
# @param str [String]
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def self.escape_html(str)
|
def self.escape_html(str)
|
||||||
str.gsub("&", "&")
|
CGI.escapeHTML(str)
|
||||||
.gsub("<", "<")
|
end
|
||||||
.gsub(">", ">")
|
|
||||||
.gsub("\"", """)
|
# Return string with unescaped HTML entities.
|
||||||
.gsub("'", "'")
|
# @param str [String]
|
||||||
|
# @return [String]
|
||||||
|
def self.unescape_html(str)
|
||||||
|
CGI.unescapeHTML(str)
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics/MethodLength
|
# rubocop:disable Metrics/MethodLength
|
||||||
|
|
|
@ -5,6 +5,7 @@ require_relative 'sorting'
|
||||||
|
|
||||||
module Hyde
|
module Hyde
|
||||||
module Util
|
module Util
|
||||||
|
# TODO: encoding support????
|
||||||
# Query string parser
|
# Query string parser
|
||||||
class Query
|
class Query
|
||||||
include Hyde::Util::ParserCommon
|
include Hyde::Util::ParserCommon
|
||||||
|
@ -16,13 +17,13 @@ module Hyde
|
||||||
# Shallow query parser (does not do PHP-like array keys)
|
# Shallow query parser (does not do PHP-like array keys)
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def parse_shallow
|
def parse_shallow
|
||||||
URI.decode_www_form(@query, Encoding::UTF_8)
|
URI.decode_www_form(@query)
|
||||||
.sort_by { |array| array[0] }
|
.sort_by { |array| array[0] }
|
||||||
.to_h
|
.to_h
|
||||||
end
|
end
|
||||||
|
|
||||||
# Better(tm) query parser with
|
# Better(tm) query parser.
|
||||||
# Returns a hash with arrays
|
# Returns a hash with arrays.
|
||||||
# Key semantics:
|
# Key semantics:
|
||||||
#
|
#
|
||||||
# - `key=value` creates a key value pair
|
# - `key=value` creates a key value pair
|
||||||
|
@ -30,10 +31,10 @@ module Hyde
|
||||||
# - `key[index]=value` sets `value` at `index` of array named `key`
|
# - `key[index]=value` sets `value` at `index` of array named `key`
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def parse
|
def parse
|
||||||
construct_deep_hash(URI.decode_www_form(@query, Encoding::UTF_8))
|
construct_deep_hash(URI.decode_www_form(@query))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get key from query
|
# Get key from query.
|
||||||
# @param key [String]
|
# @param key [String]
|
||||||
# @return [String,Array]
|
# @return [String,Array]
|
||||||
def [](key)
|
def [](key)
|
||||||
|
|
Loading…
Reference in New Issue