Compare commits
5 Commits
1039d66c73
...
1e546aa417
Author | SHA1 | Date |
---|---|---|
Yessiest | 1e546aa417 | |
Yessiest | dce0937e2e | |
Yessiest | eb7e44a537 | |
Yessiest | 59aa1206ff | |
Yessiest | 9030b5ef05 |
|
@ -1,3 +1,4 @@
|
||||||
/*.gem
|
/*.gem
|
||||||
/doc
|
/doc
|
||||||
/.yardoc
|
/.yardoc
|
||||||
|
/examples/uploader/files/*
|
||||||
|
|
|
@ -23,8 +23,3 @@ To keep things beautiful, consider following recommendations:
|
||||||
- Document classes as if the next maintainer after you has you at gunpoint.
|
- Document classes as if the next maintainer after you has you at gunpoint.
|
||||||
Document thoroughly, use YARD tags and **never** skip on public method
|
Document thoroughly, use YARD tags and **never** skip on public method
|
||||||
docs and class docs. As an example, consider Landline::PatternMatching::Glob.
|
docs and class docs. As an example, consider Landline::PatternMatching::Glob.
|
||||||
- Unit tests suck for many reasons. However, if you're writing a class that
|
|
||||||
does not have any dependents and which is frequently used, consider making
|
|
||||||
a unit test for it. People that might have to fix things further along
|
|
||||||
will be very thankful.
|
|
||||||
|
|
||||||
|
|
55
LAYOUT.md
55
LAYOUT.md
|
@ -8,15 +8,17 @@ layout as closely as possible.
|
||||||
These are core classes of Landline and they are loaded as soon as the library is loaded.
|
These are core classes of Landline and they are loaded as soon as the library is loaded.
|
||||||
|
|
||||||
- Landline::Path [path.rb]
|
- Landline::Path [path.rb]
|
||||||
- Landline::PathBinding [path.rb]
|
- Landline::PathContext [path.rb]
|
||||||
- Landline::Probe [probe.rb]
|
- Landline::Probe [probe.rb]
|
||||||
- Landline::ProbeBinding [probe.rb]
|
- Landline::ProbeContext [probe.rb]
|
||||||
- Landline::Node (parent of Path and Probe) [node.rb]
|
- Landline::Node (parent of Path and Probe) [node.rb]
|
||||||
- Landline::Server (Rack application interface) [server.rb]
|
- Landline::Server (Rack application interface) [server.rb]
|
||||||
- Landline::ServerBinding [server.rb]
|
- Landline::ServerContext [server.rb]
|
||||||
- Landline::Request (Rack request wrapper) [request.rb]
|
- Landline::Request (Rack request wrapper) [request.rb]
|
||||||
- Landline::Response (Rack response wrapper) [response.rb]
|
- Landline::Response (Rack response wrapper) [response.rb]
|
||||||
- Landline::Pattern [pattern\_matching.rb]
|
- Landline::Pattern [pattern\_matching.rb]
|
||||||
|
- Landline::TemplateContext [tempalte.rb]
|
||||||
|
- Landline::Template (template engine interface) [template.rb]
|
||||||
|
|
||||||
## Patterns
|
## Patterns
|
||||||
|
|
||||||
|
@ -29,31 +31,56 @@ These are classes that Landline::Pattern can interface with to create Patterns.
|
||||||
|
|
||||||
These are module mixins that add common methods to DSL bindings.
|
These are module mixins that add common methods to DSL bindings.
|
||||||
|
|
||||||
- Landline::DSL::PathConstructors [dsl/path\_constructors.rb]
|
- Landline::DSL::PathConstructors [dsl/constructors\_path.rb]
|
||||||
|
- Landline::DSL::ProbeConstructures [dsl/constructors\_probe.rb]
|
||||||
|
- Landline::DSL::CommonMethods [dsl/methods\_common.rb]
|
||||||
|
- Landline::DSL::PathMethods [dsl/methods\_path.rb]
|
||||||
|
- Landline::DSL::ProbeMethods [dsl/methods\_probe.rb]
|
||||||
|
- Landline::DSL::TemplateMethods [dsl/methods\_template.rb]
|
||||||
|
|
||||||
## Utilities
|
## Utilities
|
||||||
|
|
||||||
These are self-contained classes and methods that add extra functionality to Landline.
|
These are self-contained classes and methods that add extra functionality to Landline.
|
||||||
|
|
||||||
- Landline::Util::Lookup [util/lookup.rb]
|
- Landline::Util::Lookup [util/lookup.rb]
|
||||||
|
- Landline::PatternMatching [pattern\_matching/util.rb]
|
||||||
|
- Landline::Cookie (class) [util/cookie.rb]
|
||||||
|
- Landline::Error (class) [util/errors.rb]
|
||||||
|
- Landline::ParsingError (class) [util/errors.rb]
|
||||||
|
- Landline::Util (html/http utilities) [util/html.rb]
|
||||||
|
- Landline::MIME (MIME extension to type association) [util/mime.rb]
|
||||||
|
- Landline::Util::ParserSorting (functions for sorting form/query hashes) [util/parsesorting.rb]
|
||||||
|
- Landline::Util::Query (query class) [util/query.rb]
|
||||||
|
- Landline::Util::FormPart (formparser struct) [util/multipart.rb]
|
||||||
|
- Landline::Util::MultipartParser (multipart form parser) [util/multipart.rb]
|
||||||
|
- Landline::Util::HeaderRegexp (helper regexps for headers) [util/parseutils.rb]
|
||||||
|
- Landline::Util (parser methods) [util/parseutils.rb]
|
||||||
|
|
||||||
## Probe subclasses
|
## Probe subclasses
|
||||||
|
|
||||||
These are reactive request handlers with their own semantics, if needed.
|
These are reactive request handlers with their own semantics, if needed.
|
||||||
|
|
||||||
- Landline::Handler [probe/handler.rb]
|
- Landline::Handlers::Handler [probe/handler.rb]
|
||||||
- Landline::GETHandler [probe/http\_method.rb]
|
- Landline::Handlers::GETHandler [probe/http\_method.rb]
|
||||||
- Landline::POSTHandler [probe/http\_method.rb]
|
- Landline::Handlers::POSTHandler [probe/http\_method.rb]
|
||||||
- Landline::HEADHandler [probe/http\_method.rb]
|
- Landline::Handlers::HEADHandler [probe/http\_method.rb]
|
||||||
- Landline::PUTHandler [probe/http\_method.rb]
|
- Landline::Handlers::PUTHandler [probe/http\_method.rb]
|
||||||
- Landline::DELETEHandler [probe/http\_method.rb]
|
- Landline::Handlers::DELETEHandler [probe/http\_method.rb]
|
||||||
- Landline::CONNECTHandler [probe/http\_method.rb]
|
- Landline::Handlers::CONNECTHandler [probe/http\_method.rb]
|
||||||
- Landline::OPTIONSHandler [probe/http\_method.rb]
|
- Landline::Handlers::OPTIONSHandler [probe/http\_method.rb]
|
||||||
- Landline::TRACEHandler [probe/http\_method.rb]
|
- Landline::Handlers::TRACEHandler [probe/http\_method.rb]
|
||||||
- Landline::PATCHHandler [probe/http\_method.rb]
|
- Landline::Handlers::PATCHHandler [probe/http\_method.rb]
|
||||||
|
- Landline::Handlers::Serve
|
||||||
|
|
||||||
## Path subclasses
|
## Path subclasses
|
||||||
|
|
||||||
These are navigation handlers with their own semantics.
|
These are navigation handlers with their own semantics.
|
||||||
|
|
||||||
(currently none)
|
(currently none)
|
||||||
|
|
||||||
|
## Template engine interfaces
|
||||||
|
|
||||||
|
These are uniform interfaces for various templating engines.
|
||||||
|
|
||||||
|
- Landline::Templates::ERB [template/erb.rb]
|
||||||
|
- Landline::Templates::Erubi [template/erubi.rb]
|
||||||
|
|
Binary file not shown.
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Gem::Specification.new do |spec|
|
Gem::Specification.new do |spec|
|
||||||
spec.name = "landline"
|
spec.name = "landline"
|
||||||
spec.version = "0.10.0"
|
spec.version = "0.11.0"
|
||||||
spec.summary = "Elegant HTTP DSL"
|
spec.summary = "Elegant HTTP DSL"
|
||||||
spec.description = <<~DESC
|
spec.description = <<~DESC
|
||||||
Landline is a no-hard-dependencies HTTP routing DSL that was made entirely for fun.
|
Landline is a no-hard-dependencies HTTP routing DSL that was made entirely for fun.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'landline/util/jwt'
|
||||||
require_relative 'landline/server'
|
require_relative 'landline/server'
|
||||||
require_relative 'landline/path'
|
require_relative 'landline/path'
|
||||||
require_relative 'landline/probe'
|
require_relative 'landline/probe'
|
||||||
|
@ -10,10 +11,10 @@ require_relative 'landline/template'
|
||||||
# Landline is a hideously simple ruby web framework
|
# Landline is a hideously simple ruby web framework
|
||||||
module Landline
|
module Landline
|
||||||
# Landline version
|
# Landline version
|
||||||
VERSION = '0.9 "Moonsong" (beta/rewrite)'
|
VERSION = '0.11 "Decades of science" (beta)'
|
||||||
|
|
||||||
# Landline branding and version
|
# Landline branding and version
|
||||||
VLINE = "Landline/#{Landline::VERSION} (Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})\n"
|
VLINE = "Landline/#{Landline::VERSION} (Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})\n".freeze
|
||||||
|
|
||||||
# Landline copyright
|
# Landline copyright
|
||||||
COPYRIGHT = "Copyright 2023 Yessiest"
|
COPYRIGHT = "Copyright 2023 Yessiest"
|
||||||
|
|
|
@ -42,13 +42,13 @@ module Landline
|
||||||
# Set root path (appends matched part of the path).
|
# Set root path (appends matched part of the path).
|
||||||
# @param path [String]
|
# @param path [String]
|
||||||
def root(path)
|
def root(path)
|
||||||
@origin.root = path
|
@origin.root = File.expand_path(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set root path (without appending matched part).
|
# Set root path (without appending matched part).
|
||||||
# @param path [String]
|
# @param path [String]
|
||||||
def remap(path)
|
def remap(path)
|
||||||
@origin.remap = path
|
@origin.remap = File.expand_path(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add a preprocessor to the path.
|
# Add a preprocessor to the path.
|
||||||
|
@ -69,6 +69,9 @@ module Landline
|
||||||
block
|
block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
alias before preprocess
|
||||||
|
alias after postprocess
|
||||||
|
|
||||||
# Add a filter to the path.
|
# Add a filter to the path.
|
||||||
# Blocks path access if a filter returns false.
|
# Blocks path access if a filter returns false.
|
||||||
# @param block [#call]
|
# @param block [#call]
|
||||||
|
@ -81,7 +84,7 @@ module Landline
|
||||||
# Include an application as a child of path.
|
# Include an application as a child of path.
|
||||||
# @param filename [String]
|
# @param filename [String]
|
||||||
def plugin(filename)
|
def plugin(filename)
|
||||||
self.define_singleton_method(:run) do |object|
|
define_singleton_method(:run) do |object|
|
||||||
unless object.is_a? Landline::Node
|
unless object.is_a? Landline::Node
|
||||||
raise ArgumentError, "not a node instance or subclass instance"
|
raise ArgumentError, "not a node instance or subclass instance"
|
||||||
end
|
end
|
||||||
|
@ -89,9 +92,9 @@ module Landline
|
||||||
object
|
object
|
||||||
end
|
end
|
||||||
@origin.children.append(
|
@origin.children.append(
|
||||||
self.instance_eval(File.read(filename), filename)
|
instance_eval(File.read(filename), filename)
|
||||||
)
|
)
|
||||||
self.singleton_class.undef_method :run
|
singleton_class.undef_method :run
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ require_relative '../response'
|
||||||
require_relative '../util/multipart'
|
require_relative '../util/multipart'
|
||||||
require_relative '../util/parseutils'
|
require_relative '../util/parseutils'
|
||||||
require_relative '../util/html'
|
require_relative '../util/html'
|
||||||
|
require 'json'
|
||||||
|
|
||||||
module Landline
|
module Landline
|
||||||
module DSL
|
module DSL
|
||||||
|
@ -85,18 +86,12 @@ module Landline
|
||||||
# Checks if current request has multipart/form-data associated with it
|
# Checks if current request has multipart/form-data associated with it
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def form?
|
def form?
|
||||||
value, opts = Landline::Util::ParserCommon.parse_value(
|
value, opts = _verify_content_type('multipart/form-data')
|
||||||
request.headers["content-type"]
|
!!(value && opts && opts['boundary'])
|
||||||
)
|
|
||||||
if value == "multipart/form-data" and
|
|
||||||
opts["boundary"]
|
|
||||||
true
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns formdata
|
# Returns formdata
|
||||||
|
# @note reads request.input - may nullify request.body.
|
||||||
# @return [Hash{String=>(String,Landline::Util::FormPart)}]
|
# @return [Hash{String=>(String,Landline::Util::FormPart)}]
|
||||||
def form
|
def form
|
||||||
_, opts = Landline::Util::ParserCommon.parse_value(
|
_, opts = Landline::Util::ParserCommon.parse_value(
|
||||||
|
@ -107,6 +102,39 @@ module Landline
|
||||||
).to_h
|
).to_h
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Checks if current request has urlencoded query string
|
||||||
|
# @return [Boolean]
|
||||||
|
def query?
|
||||||
|
!!_verify_content_type("application/x-www-form-urlencode")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns parsed query hash
|
||||||
|
# @note reads request.body - may nullify .input, .body data is memoized
|
||||||
|
# @return [Hash{String => Object}] query data
|
||||||
|
def query
|
||||||
|
Landline::Util::Query.new(request.body).parse
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns shallow parsed query hash
|
||||||
|
# @note reads request.body - may nullify .input, .body data is memoized
|
||||||
|
# @return [Hash{String => Object}] query data
|
||||||
|
def query_shallow
|
||||||
|
Landline::Util::Query.new(request.body).parse_shallow
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if body is a JSON object
|
||||||
|
# @return [Boolean]
|
||||||
|
def json?
|
||||||
|
!!_verify_content_type('application/json')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return parse JSON object
|
||||||
|
# @note reads request.input - may nullify request.body.
|
||||||
|
# @return [Object]
|
||||||
|
def json
|
||||||
|
JSON.parse(request.input)
|
||||||
|
end
|
||||||
|
|
||||||
# Open a file relative to current filepath
|
# Open a file relative to current filepath
|
||||||
# @see File.open
|
# @see File.open
|
||||||
def file(path, mode = "r", *all, &block)
|
def file(path, mode = "r", *all, &block)
|
||||||
|
@ -124,6 +152,22 @@ module Landline
|
||||||
def unescape_html(text)
|
def unescape_html(text)
|
||||||
Landline::Util.unescape_html(text)
|
Landline::Util.unescape_html(text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def _verify_content_type(type)
|
||||||
|
return false unless request.headers['content-type']
|
||||||
|
|
||||||
|
value, opts = Landline::Util::ParserCommon.parse_value(
|
||||||
|
request.headers["content-type"]
|
||||||
|
)
|
||||||
|
if value == type and
|
||||||
|
request.input
|
||||||
|
[value, opts]
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,12 +41,14 @@ module Landline
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns request body (if POST data exists)
|
# Returns request body (if POST data exists)
|
||||||
|
# @note reads data from rack.input, which is not rewindable. .body data is memoized.
|
||||||
# @return [nil, String]
|
# @return [nil, String]
|
||||||
def body
|
def body
|
||||||
@body ||= @rack.input&.read
|
@body ||= @rack.input&.read
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns raw Rack input object
|
# Returns raw Rack input object
|
||||||
|
# @note Rack IO is not always rewindable - if it is read once, the data is gone (i.e. request.body will return nothing).
|
||||||
# @return [IO] (May not entirely be compatible with IO, see Rack/SPEC.rdoc)
|
# @return [IO] (May not entirely be compatible with IO, see Rack/SPEC.rdoc)
|
||||||
def input
|
def input
|
||||||
@rack.input
|
@rack.input
|
||||||
|
|
|
@ -4,9 +4,16 @@ require_relative 'parseutils'
|
||||||
require_relative 'errors'
|
require_relative 'errors'
|
||||||
require 'date'
|
require 'date'
|
||||||
require 'openssl'
|
require 'openssl'
|
||||||
|
require 'base64'
|
||||||
HeaderRegexp = Landline::Util::HeaderRegexp
|
HeaderRegexp = Landline::Util::HeaderRegexp
|
||||||
ParserCommon = Landline::Util::ParserCommon
|
ParserCommon = Landline::Util::ParserCommon
|
||||||
|
|
||||||
|
if RUBY_ENGINE == 'jruby' # fix for JRuby
|
||||||
|
OpenSSL::HMAC.define_singleton_method(:base64digest) do |*args|
|
||||||
|
Base64.strict_encode64(OpenSSL::HMAC.digest(*args)).strip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
module Landline
|
module Landline
|
||||||
# Utility class for handling cookies
|
# Utility class for handling cookies
|
||||||
class Cookie
|
class Cookie
|
||||||
|
@ -22,11 +29,11 @@ module Landline
|
||||||
# @option params [String, Date] "expires"
|
# @option params [String, Date] "expires"
|
||||||
# @raise Landline::ParsingError invalid cookie parameters
|
# @raise Landline::ParsingError invalid cookie parameters
|
||||||
def initialize(key, value, params = {})
|
def initialize(key, value, params = {})
|
||||||
unless key.match? HeaderRegexp::COOKIE_NAME
|
unless key.match?(/\A#{HeaderRegexp::COOKIE_NAME}\z/o)
|
||||||
raise Landline::ParsingError, "invalid cookie key: #{key}"
|
raise Landline::ParsingError, "invalid cookie key: #{key}"
|
||||||
end
|
end
|
||||||
|
|
||||||
unless value.match? HeaderRegexp::COOKIE_VALUE
|
unless value.match?(/\A#{HeaderRegexp::COOKIE_VALUE}\z/o)
|
||||||
raise Landline::ParsingError, "invalid cookie value: #{value}"
|
raise Landline::ParsingError, "invalid cookie value: #{value}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -81,7 +88,7 @@ module Landline
|
||||||
# @param sep [String] Hash separator
|
# @param sep [String] Hash separator
|
||||||
# @return [Boolean] whether value is signed and valid
|
# @return [Boolean] whether value is signed and valid
|
||||||
def verify(key, algorithm: "sha256", sep: "&")
|
def verify(key, algorithm: "sha256", sep: "&")
|
||||||
val, sig = @value.match(/\A(.*)#{sep}([A-Za-z0-9+\/=]+)\Z/).to_a[1..]
|
val, sig = @value.match(/\A(.*)#{sep}([A-Za-z0-9+\/=]+)\z/).to_a[1..]
|
||||||
return false unless val and sig
|
return false unless val and sig
|
||||||
|
|
||||||
sig == ::OpenSSL::HMAC.base64digest(algorithm, key, val)
|
sig == ::OpenSSL::HMAC.base64digest(algorithm, key, val)
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'openssl'
|
||||||
|
require 'json'
|
||||||
|
require 'base64'
|
||||||
|
|
||||||
|
if RUBY_ENGINE == 'jruby' # fix for JRuby
|
||||||
|
OpenSSL::HMAC.define_singleton_method(:base64digest) do |*args|
|
||||||
|
Base64.strict_encode64(OpenSSL::HMAC.digest(*args)).strip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Landline
|
||||||
|
module Util
|
||||||
|
# JSON Web Token construction class
|
||||||
|
class JWT
|
||||||
|
# Create a new JWT token wrapper
|
||||||
|
# @param data [Hash, Array] JSON-formattable data
|
||||||
|
# @param halgo [String] Name of the hash algorithm to use
|
||||||
|
def initialize(data, halgo = "SHA256")
|
||||||
|
@halgo = halgo
|
||||||
|
@data = data
|
||||||
|
end
|
||||||
|
|
||||||
|
# Construct a string representation of the current token
|
||||||
|
# @param key [String]
|
||||||
|
# @return [String]
|
||||||
|
def make(key)
|
||||||
|
jsondata = @data.to_json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"hash" => @halgo
|
||||||
|
}.to_json,
|
||||||
|
jsondata,
|
||||||
|
OpenSSL::HMAC.digest(@halgo, key, jsondata)
|
||||||
|
].map(&Base64.method(:strict_encode64)).map(&:strip).join "&"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Construct an object from string
|
||||||
|
# @param input [String]
|
||||||
|
# @param key [String]
|
||||||
|
# @return [JWT, nil] returns nil if verification couldn't complete
|
||||||
|
def self.from_string(input, key)
|
||||||
|
halgoj, dataj, sig = input.split("&").map(&Base64.method(:strict_decode64))
|
||||||
|
halgo = JSON.parse(halgoj)["hash"]
|
||||||
|
return nil if OpenSSL::HMAC.digest(halgo, key, dataj) != sig
|
||||||
|
|
||||||
|
new(JSON.parse(dataj), halgo)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,28 +8,28 @@ module Landline
|
||||||
# (not exactly precise) Regular expressions for some RFC definitions
|
# (not exactly precise) Regular expressions for some RFC definitions
|
||||||
module HeaderRegexp
|
module HeaderRegexp
|
||||||
# Matches the RFC2616 definiton of token
|
# Matches the RFC2616 definiton of token
|
||||||
TOKEN = /[!-~&&[^()<>@,;:\\"\/\[\]?={}\t]]+/.freeze
|
TOKEN = /[!-~&&[^()<>@,;:\\"\/\[\]?={}\t]]+/
|
||||||
# Matches the RFC2616 definition of quoted-string
|
# Matches the RFC2616 definition of quoted-string
|
||||||
QUOTED = /"[\x0-\x7E&&[^\x1-\x8\xb-\x1f]]*(?<!\\)"/.freeze
|
QUOTED = /"[\x0-\x7E&&[^\x1-\x8\xb-\x1f]]*(?<!\\)"/
|
||||||
# Matches any CHAR except CTLs
|
# Matches any CHAR except CTLs
|
||||||
PRINTCHAR = /[\x2-\x7E]/.freeze
|
PRINTCHAR = /[\x2-\x7E]/
|
||||||
# Matches 1 or more CHARs excluding CTLs
|
# Matches 1 or more CHARs excluding CTLs
|
||||||
PRINTABLE = /#{PRINTCHAR}+/o.freeze
|
PRINTABLE = /#{PRINTCHAR}+/o
|
||||||
# Matches the RFC6265 definition of a cookie-octet
|
# Matches the RFC6265 definition of a cookie-octet
|
||||||
COOKIE_OCTET = /[\x21-\x7E&&[^",;\\]]*/.freeze
|
COOKIE_OCTET = /[\x21-\x7E&&[^",;\\]]*/
|
||||||
COOKIE_VALUE = /(?:#{QUOTED}|#{COOKIE_OCTET})/o.freeze
|
COOKIE_VALUE = /(?:#{QUOTED}|#{COOKIE_OCTET})/o
|
||||||
COOKIE_NAME = TOKEN
|
COOKIE_NAME = TOKEN
|
||||||
# Matches the RFC6265 definition of cookie-pair.
|
# Matches the RFC6265 definition of cookie-pair.
|
||||||
# Captures name (1) and value (2).
|
# Captures name (1) and value (2).
|
||||||
COOKIE_PAIR = /\A(#{COOKIE_NAME})=(#{COOKIE_VALUE})\Z/o.freeze
|
COOKIE_PAIR = /\A(#{COOKIE_NAME})=(#{COOKIE_VALUE})\z/o
|
||||||
# Matches a very abstract definition of a quoted header paramter.
|
# Matches a very abstract definition of a quoted header paramter.
|
||||||
# Captures name (1) and value (2).
|
# Captures name (1) and value (2).
|
||||||
PARAM_QUOTED = /\A(#{TOKEN})=?(#{QUOTED}|#{PRINTCHAR}*)\Z/o.freeze
|
PARAM_QUOTED = /\A(#{TOKEN})=?(#{QUOTED}|#{PRINTCHAR}*)\z/o
|
||||||
# Matches a very abstract definition of a header parameter.
|
# Matches a very abstract definition of a header parameter.
|
||||||
# Captures name (1) and value (2).
|
# Captures name (1) and value (2).
|
||||||
PARAM = /\A(#{TOKEN})=?(#{PRINTCHAR}*)\Z/o.freeze
|
PARAM = /\A(#{TOKEN})=?(#{PRINTCHAR}*)\z/o
|
||||||
# Specifically matches cookie parameters
|
# Specifically matches cookie parameters
|
||||||
COOKIE_PARAM = /\A(#{TOKEN})=?(#{QUOTED}|#{COOKIE_OCTET})\Z/o.freeze
|
COOKIE_PARAM = /\A(#{TOKEN})=?(#{QUOTED}|#{COOKIE_OCTET})\z/o
|
||||||
end
|
end
|
||||||
|
|
||||||
# Module for all things related to parsing HTTP and related syntax.
|
# Module for all things related to parsing HTTP and related syntax.
|
||||||
|
@ -48,7 +48,9 @@ module Landline
|
||||||
# @param regexp [Regexp,nil] override param matching regexp
|
# @param regexp [Regexp,nil] override param matching regexp
|
||||||
# @return [Array(String, Hash)]
|
# @return [Array(String, Hash)]
|
||||||
def self.parse_value(input, sep: ";", unquote: false, regexp: nil)
|
def self.parse_value(input, sep: ";", unquote: false, regexp: nil)
|
||||||
parts = input.split(sep).map { |x| URI.decode_uri_component(x).strip }
|
parts = input.split(sep).map do |x|
|
||||||
|
URI.decode_www_form_component(x).strip
|
||||||
|
end
|
||||||
base = parts.shift
|
base = parts.shift
|
||||||
opts = parts.map do |raw|
|
opts = parts.map do |raw|
|
||||||
key, value = raw.match(if regexp
|
key, value = raw.match(if regexp
|
||||||
|
|
Loading…
Reference in New Issue