module Protocol::HTTP::URL

Constants

NON_PCHAR

According to tools.ietf.org/html/rfc3986#section-3.3, we escape non-pchar.

Public Class Methods

assign(keys, value, parent) click to toggle source
# File lib/protocol/http/url.rb, line 83
def self.assign(keys, value, parent)
        top, *middle = keys
        
        middle.each_with_index do |key, index|
                if key.nil? or key.empty?
                        parent = (parent[top] ||= Array.new)
                        top = parent.size
                        
                        if nested = middle[index+1] and last = parent.last
                                top -= 1 unless last.include?(nested)
                        end
                else
                        parent = (parent[top] ||= Hash.new)
                        top = key
                end
        end
        
        parent[top] = value
end
decode(string, maximum = 8, symbolize_keys: false) click to toggle source

TODO use native C extension from `Trenni::Reference`.

# File lib/protocol/http/url.rb, line 104
def self.decode(string, maximum = 8, symbolize_keys: false)
        parameters = {}
        
        self.scan(string) do |name, value|
                keys = self.split(name)
                
                if keys.size > maximum
                        raise ArgumentError, "Key length exceeded limit!"
                end
                
                if symbolize_keys
                        keys.collect!{|key| key.empty? ? nil : key.to_sym}
                end
                
                self.assign(keys, value, parameters)
        end
        
        return parameters
end
encode(value, prefix = nil) click to toggle source

Encodes a hash or array into a query string

# File lib/protocol/http/url.rb, line 51
def self.encode(value, prefix = nil)
        case value
        when Array
                return value.map {|v|
                        self.encode(v, "#{prefix}[]")
                }.join("&")
        when Hash
                return value.map {|k, v|
                        self.encode(v, prefix ? "#{prefix}[#{escape(k.to_s)}]" : escape(k.to_s))
                }.reject(&:empty?).join('&')
        when nil
                return prefix
        else
                raise ArgumentError, "value must be a Hash" if prefix.nil?
                
                return "#{prefix}=#{escape(value.to_s)}"
        end
end
escape(string, encoding = string.encoding) click to toggle source

Escapes a generic string, using percent encoding.

# File lib/protocol/http/url.rb, line 27
def self.escape(string, encoding = string.encoding)
        string.b.gsub(/([^a-zA-Z0-9_.\-]+)/) do |m|
                '%' + m.unpack('H2' * m.bytesize).join('%').upcase
        end.force_encoding(encoding)
end
escape_path(path) click to toggle source

Escapes a path

# File lib/protocol/http/url.rb, line 43
def self.escape_path(path)
        encoding = path.encoding
        path.b.gsub(NON_PCHAR) do |m|
                '%' + m.unpack('H2' * m.bytesize).join('%').upcase
        end.force_encoding(encoding)
end
scan(string) { |unescape(key), unescape(value)| ... } click to toggle source
# File lib/protocol/http/url.rb, line 70
def self.scan(string)
        # TODO Ruby 2.6 doesn't require `.each`
        string.split('&').each do |assignment|
                key, value = assignment.split('=', 2)
                
                yield unescape(key), unescape(value)
        end
end
split(name) click to toggle source
# File lib/protocol/http/url.rb, line 79
def self.split(name)
        name.scan(/([^\[]+)|(?:\[(.*?)\])/).flatten!.compact!
end
unescape(string, encoding = string.encoding) click to toggle source
# File lib/protocol/http/url.rb, line 33
def self.unescape(string, encoding = string.encoding)
        string.b.gsub(/%(\h\h)/) do |hex|
                Integer(hex, 16).chr
        end.force_encoding(encoding)
end