2018-09-17 12:41:14 -04:00
|
|
|
# frozen_string_literal: true
|
2015-07-14 13:28:59 -04:00
|
|
|
|
2019-02-14 16:37:27 -05:00
|
|
|
require 'uri/common'
|
2015-07-14 13:28:59 -04:00
|
|
|
|
2013-02-05 01:39:19 -05:00
|
|
|
module Puma
|
|
|
|
module Util
|
|
|
|
module_function
|
|
|
|
|
|
|
|
def pipe
|
|
|
|
IO.pipe
|
|
|
|
end
|
2015-07-14 13:28:59 -04:00
|
|
|
|
2021-10-01 16:11:15 -04:00
|
|
|
# An instance method on Thread has been provided to address https://bugs.ruby-lang.org/issues/13632,
|
|
|
|
# which currently effects some older versions of Ruby: 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1
|
|
|
|
# Additional context: https://github.com/puma/puma/pull/1345
|
|
|
|
def purge_interrupt_queue
|
|
|
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
|
|
|
end
|
|
|
|
|
2015-07-14 13:28:59 -04:00
|
|
|
# Unescapes a URI escaped string with +encoding+. +encoding+ will be the
|
|
|
|
# target encoding of the string returned, and it defaults to UTF-8
|
|
|
|
if defined?(::Encoding)
|
|
|
|
def unescape(s, encoding = Encoding::UTF_8)
|
|
|
|
URI.decode_www_form_component(s, encoding)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
def unescape(s, encoding = nil)
|
|
|
|
URI.decode_www_form_component(s, encoding)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
module_function :unescape
|
|
|
|
|
2020-09-29 09:21:52 -04:00
|
|
|
# @version 5.0.0
|
2022-02-05 12:06:22 -05:00
|
|
|
def nakayoshi_gc(log_writer)
|
|
|
|
log_writer.log "! Promoting existing objects to old generation..."
|
2020-09-29 09:21:52 -04:00
|
|
|
4.times { GC.start(full_mark: false) }
|
|
|
|
if GC.respond_to?(:compact)
|
2022-02-05 12:06:22 -05:00
|
|
|
log_writer.log "! Compacting..."
|
2020-09-29 09:21:52 -04:00
|
|
|
GC.compact
|
|
|
|
end
|
2022-02-05 12:06:22 -05:00
|
|
|
log_writer.log "! Friendly fork preparation complete."
|
2020-09-29 09:21:52 -04:00
|
|
|
end
|
|
|
|
|
2015-07-14 13:28:59 -04:00
|
|
|
DEFAULT_SEP = /[&;] */n
|
|
|
|
|
|
|
|
# Stolen from Mongrel, with some small modifications:
|
|
|
|
# Parses a query string by breaking it up at the '&'
|
|
|
|
# and ';' characters. You can also use this to parse
|
|
|
|
# cookies by changing the characters used in the second
|
|
|
|
# parameter (which defaults to '&;').
|
|
|
|
def parse_query(qs, d = nil, &unescaper)
|
|
|
|
unescaper ||= method(:unescape)
|
|
|
|
|
|
|
|
params = {}
|
|
|
|
|
|
|
|
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
|
|
|
next if p.empty?
|
|
|
|
k, v = p.split('=', 2).map(&unescaper)
|
|
|
|
|
|
|
|
if cur = params[k]
|
|
|
|
if cur.class == Array
|
|
|
|
params[k] << v
|
|
|
|
else
|
|
|
|
params[k] = [cur, v]
|
|
|
|
end
|
|
|
|
else
|
|
|
|
params[k] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-10 14:28:35 -04:00
|
|
|
params
|
2015-07-14 13:28:59 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# A case-insensitive Hash that preserves the original case of a
|
|
|
|
# header when set.
|
|
|
|
class HeaderHash < Hash
|
|
|
|
def self.new(hash={})
|
|
|
|
HeaderHash === hash ? hash : super(hash)
|
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(hash={})
|
|
|
|
super()
|
|
|
|
@names = {}
|
|
|
|
hash.each { |k, v| self[k] = v }
|
|
|
|
end
|
|
|
|
|
|
|
|
def each
|
|
|
|
super do |k, v|
|
|
|
|
yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-09-25 14:50:57 -04:00
|
|
|
# @!attribute [r] to_hash
|
2015-07-14 13:28:59 -04:00
|
|
|
def to_hash
|
|
|
|
hash = {}
|
|
|
|
each { |k,v| hash[k] = v }
|
|
|
|
hash
|
|
|
|
end
|
|
|
|
|
|
|
|
def [](k)
|
|
|
|
super(k) || super(@names[k.downcase])
|
|
|
|
end
|
|
|
|
|
|
|
|
def []=(k, v)
|
|
|
|
canonical = k.downcase
|
|
|
|
delete k if @names[canonical] && @names[canonical] != k # .delete is expensive, don't invoke it unless necessary
|
|
|
|
@names[k] = @names[canonical] = k
|
|
|
|
super k, v
|
|
|
|
end
|
|
|
|
|
|
|
|
def delete(k)
|
|
|
|
canonical = k.downcase
|
|
|
|
result = super @names.delete(canonical)
|
|
|
|
@names.delete_if { |name,| name.downcase == canonical }
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def include?(k)
|
|
|
|
@names.include?(k) || @names.include?(k.downcase)
|
|
|
|
end
|
|
|
|
|
|
|
|
alias_method :has_key?, :include?
|
|
|
|
alias_method :member?, :include?
|
|
|
|
alias_method :key?, :include?
|
|
|
|
|
|
|
|
def merge!(other)
|
|
|
|
other.each { |k, v| self[k] = v }
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def merge(other)
|
|
|
|
hash = dup
|
|
|
|
hash.merge! other
|
|
|
|
end
|
|
|
|
|
|
|
|
def replace(other)
|
|
|
|
clear
|
|
|
|
other.each { |k, v| self[k] = v }
|
|
|
|
self
|
|
|
|
end
|
|
|
|
end
|
2013-02-05 01:39:19 -05:00
|
|
|
end
|
|
|
|
end
|