/
util.rb
152 lines (126 loc) · 3.81 KB
/
util.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# frozen_string_literal: true
require 'uri/common'
module Puma
module Util
module_function
def pipe
IO.pipe
end
# 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
# Escapes and 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 escape(s, encoding = Encoding::UTF_8)
URI.encode_www_form_component(s, encoding)
end
def unescape(s, encoding = Encoding::UTF_8)
URI.decode_www_form_component(s, encoding)
end
else
def escape(s, encoding = nil)
URI.encode_www_form_component(s, encoding)
end
def unescape(s, encoding = nil)
URI.decode_www_form_component(s, encoding)
end
end
module_function :unescape, :escape
# @version 5.0.0
def nakayoshi_gc(events)
events.log "! Promoting existing objects to old generation..."
4.times { GC.start(full_mark: false) }
if GC.respond_to?(:compact)
events.log "! Compacting..."
GC.compact
end
events.log "! Friendly fork preparation complete."
end
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
params
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
# @!attribute [r] to_hash
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
end
end