made form parser easier to use

This commit is contained in:
Yessiest 2023-09-10 20:17:07 +04:00
parent bfc9a3066b
commit bc8750daf7
8 changed files with 95 additions and 45 deletions

View File

@ -2,17 +2,12 @@
$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
puts form.pretty_inspect if form?
bounce
end
serve "*.html"

View File

@ -12,8 +12,9 @@ app = Hyde::Server.new do
end
path "important" do
preprocess do |req|
# 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
get "answer" do
header "content-type", "application/json"

View File

@ -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

View File

@ -1,6 +1,8 @@
# frozen_string_literal: true
require_relative '../response'
require_relative '../util/multipart'
require_relative '../util/header'
module Hyde
module DSL
@ -12,31 +14,11 @@ module Hyde
@origin.request
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)
# @param status [Integer] http status code
def status(status)
@response = (@response or Hyde::Response.new)
@response.status = status
@origin.response = (@origin.response or Hyde::Response.new)
@origin.response.status = status
end
alias code status
@ -79,6 +61,27 @@ module Hyde
@origin.response.delete_header(key, value)
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

View File

@ -4,10 +4,20 @@ require_relative 'pattern_matching'
require_relative 'node'
require_relative 'dsl/path_constructors'
require_relative 'dsl/path_methods'
require_relative 'dsl/common_methods'
require_relative 'util/lookup'
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
include Hyde::DSL::PathConstructors
include Hyde::DSL::PathMethods
@ -19,6 +29,7 @@ module Hyde
# Primary building block of request navigation.
class Path < Hyde::Node
ProcBinding = Hyde::ProcessorBinding
Binding = Hyde::PathBinding
# @param path [Object] Object to generate {Hyde::Pattern} from
@ -32,9 +43,10 @@ module Hyde
@preprocessors = []
@postprocessors = []
@filters = []
binding = Binding.new(self)
# Bindings setup
binding = self.class::Binding.new(self)
binding.instance_exec(&setup)
@procbinding = self.class::ProcBinding.new(self)
end
# Method callback on successful request navigation.
@ -92,7 +104,7 @@ module Hyde
# @return [Boolean] true if request passed all filters
def run_filters(request)
@filters.each do |filter|
return false if filter.call(request).is_a? FalseClass
return false unless @procbinding.instance_exec(request, &filter)
end
true
end
@ -101,7 +113,7 @@ module Hyde
# @param request [Hyde::Request]
def run_preprocessors(request)
@preprocessors.each do |preproc|
preproc.call(request)
@procbinding.instance_exec(request, &preproc)
end
end

View File

@ -1,12 +1,16 @@
# frozen_string_literal: true
require_relative "../dsl/probe_methods"
require_relative "../dsl/common_methods"
module Hyde
# Binding that provides execution context for Probes.
class ProbeBinding
include Hyde::DSL::ProbeMethods
include Hyde::DSL::CommonMethods
def initialize(origin)
@origin = origin
end
include Hyde::DSL::ProbeMethods
end
end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'cgi/escape'
module Hyde
module Util
# HTTP status codes and descriptions
@ -40,6 +42,7 @@ module Hyde
415 => 'Unsupported Media Type',
416 => 'Request Range Not Satisfiable',
417 => 'Expectation Failed',
418 => "I'm a teapot",
422 => 'Unprocessable Entity',
423 => 'Locked',
424 => 'Failed Dependency',
@ -65,11 +68,14 @@ module Hyde
# @param str [String]
# @return [String]
def self.escape_html(str)
str.gsub("&", "&amp;")
.gsub("<", "&lt;")
.gsub(">", "&gt;")
.gsub("\"", "&quot;")
.gsub("'", "&#39;")
CGI.escapeHTML(str)
end
# Return string with unescaped HTML entities.
# @param str [String]
# @return [String]
def self.unescape_html(str)
CGI.unescapeHTML(str)
end
# rubocop:disable Metrics/MethodLength

View File

@ -5,6 +5,7 @@ require_relative 'sorting'
module Hyde
module Util
# TODO: encoding support????
# Query string parser
class Query
include Hyde::Util::ParserCommon
@ -16,13 +17,13 @@ module Hyde
# Shallow query parser (does not do PHP-like array keys)
# @return [Hash]
def parse_shallow
URI.decode_www_form(@query, Encoding::UTF_8)
URI.decode_www_form(@query)
.sort_by { |array| array[0] }
.to_h
end
# Better(tm) query parser with
# Returns a hash with arrays
# Better(tm) query parser.
# Returns a hash with arrays.
# Key semantics:
#
# - `key=value` creates a key value pair
@ -30,10 +31,10 @@ module Hyde
# - `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))
construct_deep_hash(URI.decode_www_form(@query))
end
# Get key from query
# Get key from query.
# @param key [String]
# @return [String,Array]
def [](key)