puma-simon 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/issue_template.md +20 -0
- data/.gitignore +18 -0
- data/.hoeignore +12 -0
- data/.travis.yml +29 -0
- data/DEPLOYMENT.md +91 -0
- data/Gemfile +12 -0
- data/History.md +1254 -0
- data/LICENSE +26 -0
- data/Manifest.txt +78 -0
- data/README.md +353 -0
- data/Rakefile +158 -0
- data/Release.md +9 -0
- data/bin/puma +10 -0
- data/bin/puma-wild +31 -0
- data/bin/pumactl +12 -0
- data/docs/nginx.md +80 -0
- data/docs/signals.md +43 -0
- data/docs/systemd.md +197 -0
- data/examples/CA/cacert.pem +23 -0
- data/examples/CA/newcerts/cert_1.pem +19 -0
- data/examples/CA/newcerts/cert_2.pem +19 -0
- data/examples/CA/private/cakeypair.pem +30 -0
- data/examples/CA/serial +1 -0
- data/examples/config.rb +200 -0
- data/examples/plugins/redis_stop_puma.rb +46 -0
- data/examples/puma/cert_puma.pem +19 -0
- data/examples/puma/client-certs/ca.crt +19 -0
- data/examples/puma/client-certs/ca.key +27 -0
- data/examples/puma/client-certs/client.crt +19 -0
- data/examples/puma/client-certs/client.key +27 -0
- data/examples/puma/client-certs/client_expired.crt +19 -0
- data/examples/puma/client-certs/client_expired.key +27 -0
- data/examples/puma/client-certs/client_unknown.crt +19 -0
- data/examples/puma/client-certs/client_unknown.key +27 -0
- data/examples/puma/client-certs/generate.rb +78 -0
- data/examples/puma/client-certs/keystore.jks +0 -0
- data/examples/puma/client-certs/server.crt +19 -0
- data/examples/puma/client-certs/server.key +27 -0
- data/examples/puma/client-certs/server.p12 +0 -0
- data/examples/puma/client-certs/unknown_ca.crt +19 -0
- data/examples/puma/client-certs/unknown_ca.key +27 -0
- data/examples/puma/csr_puma.pem +11 -0
- data/examples/puma/keystore.jks +0 -0
- data/examples/puma/puma_keypair.pem +15 -0
- data/examples/qc_config.rb +13 -0
- data/ext/puma_http11/PumaHttp11Service.java +17 -0
- data/ext/puma_http11/ext_help.h +15 -0
- data/ext/puma_http11/extconf.rb +15 -0
- data/ext/puma_http11/http11_parser.c +1069 -0
- data/ext/puma_http11/http11_parser.h +65 -0
- data/ext/puma_http11/http11_parser.java.rl +161 -0
- data/ext/puma_http11/http11_parser.rl +147 -0
- data/ext/puma_http11/http11_parser_common.rl +54 -0
- data/ext/puma_http11/io_buffer.c +155 -0
- data/ext/puma_http11/mini_ssl.c +457 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +234 -0
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +473 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +339 -0
- data/ext/puma_http11/puma_http11.c +500 -0
- data/gemfiles/2.1-Gemfile +12 -0
- data/lib/puma.rb +15 -0
- data/lib/puma/accept_nonblock.rb +23 -0
- data/lib/puma/app/status.rb +66 -0
- data/lib/puma/binder.rb +402 -0
- data/lib/puma/cli.rb +220 -0
- data/lib/puma/client.rb +434 -0
- data/lib/puma/cluster.rb +510 -0
- data/lib/puma/commonlogger.rb +106 -0
- data/lib/puma/compat.rb +14 -0
- data/lib/puma/configuration.rb +364 -0
- data/lib/puma/const.rb +224 -0
- data/lib/puma/control_cli.rb +259 -0
- data/lib/puma/convenient.rb +23 -0
- data/lib/puma/daemon_ext.rb +31 -0
- data/lib/puma/delegation.rb +11 -0
- data/lib/puma/detect.rb +13 -0
- data/lib/puma/dsl.rb +486 -0
- data/lib/puma/events.rb +152 -0
- data/lib/puma/io_buffer.rb +7 -0
- data/lib/puma/java_io_buffer.rb +45 -0
- data/lib/puma/jruby_restart.rb +83 -0
- data/lib/puma/launcher.rb +410 -0
- data/lib/puma/minissl.rb +221 -0
- data/lib/puma/null_io.rb +42 -0
- data/lib/puma/plugin.rb +115 -0
- data/lib/puma/plugin/tmp_restart.rb +35 -0
- data/lib/puma/rack/backports/uri/common_193.rb +33 -0
- data/lib/puma/rack/builder.rb +298 -0
- data/lib/puma/rack/urlmap.rb +91 -0
- data/lib/puma/rack_default.rb +7 -0
- data/lib/puma/reactor.rb +210 -0
- data/lib/puma/runner.rb +171 -0
- data/lib/puma/server.rb +949 -0
- data/lib/puma/single.rb +112 -0
- data/lib/puma/state_file.rb +29 -0
- data/lib/puma/tcp_logger.rb +39 -0
- data/lib/puma/thread_pool.rb +297 -0
- data/lib/puma/util.rb +128 -0
- data/lib/rack/handler/puma.rb +78 -0
- data/puma.gemspec +52 -0
- data/test/ab_rs.rb +22 -0
- data/test/config.rb +2 -0
- data/test/config/app.rb +9 -0
- data/test/config/plugin.rb +1 -0
- data/test/config/settings.rb +2 -0
- data/test/config/state_file_testing_config.rb +14 -0
- data/test/hello-bind.ru +2 -0
- data/test/hello-delay.ru +3 -0
- data/test/hello-map.ru +3 -0
- data/test/hello-post.ru +4 -0
- data/test/hello-stuck.ru +1 -0
- data/test/hello-tcp.ru +5 -0
- data/test/hello.ru +1 -0
- data/test/hijack.ru +6 -0
- data/test/hijack2.ru +5 -0
- data/test/lobster.ru +4 -0
- data/test/shell/run.sh +24 -0
- data/test/shell/t1.rb +19 -0
- data/test/shell/t1_conf.rb +3 -0
- data/test/shell/t2.rb +17 -0
- data/test/shell/t2_conf.rb +6 -0
- data/test/shell/t3.rb +25 -0
- data/test/shell/t3_conf.rb +5 -0
- data/test/slow.ru +4 -0
- data/test/ssl_config.rb +4 -0
- data/test/test_app_status.rb +93 -0
- data/test/test_binder.rb +31 -0
- data/test/test_cli.rb +209 -0
- data/test/test_config.rb +95 -0
- data/test/test_events.rb +161 -0
- data/test/test_helper.rb +50 -0
- data/test/test_http10.rb +27 -0
- data/test/test_http11.rb +186 -0
- data/test/test_integration.rb +247 -0
- data/test/test_iobuffer.rb +39 -0
- data/test/test_minissl.rb +29 -0
- data/test/test_null_io.rb +49 -0
- data/test/test_persistent.rb +245 -0
- data/test/test_puma_server.rb +626 -0
- data/test/test_puma_server_ssl.rb +222 -0
- data/test/test_rack_handler.rb +57 -0
- data/test/test_rack_server.rb +138 -0
- data/test/test_tcp_logger.rb +39 -0
- data/test/test_tcp_rack.rb +36 -0
- data/test/test_thread_pool.rb +250 -0
- data/test/test_unix_socket.rb +35 -0
- data/test/test_web_server.rb +88 -0
- data/tools/jungle/README.md +9 -0
- data/tools/jungle/init.d/README.md +59 -0
- data/tools/jungle/init.d/puma +421 -0
- data/tools/jungle/init.d/run-puma +18 -0
- data/tools/jungle/upstart/README.md +61 -0
- data/tools/jungle/upstart/puma-manager.conf +31 -0
- data/tools/jungle/upstart/puma.conf +69 -0
- data/tools/trickletest.rb +45 -0
- metadata +297 -0
data/lib/puma/minissl.rb
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
module Puma
|
|
2
|
+
module MiniSSL
|
|
3
|
+
class Socket
|
|
4
|
+
def initialize(socket, engine)
|
|
5
|
+
@socket = socket
|
|
6
|
+
@engine = engine
|
|
7
|
+
@peercert = nil
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_io
|
|
11
|
+
@socket
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def readpartial(size)
|
|
15
|
+
while true
|
|
16
|
+
output = @engine.read
|
|
17
|
+
return output if output
|
|
18
|
+
|
|
19
|
+
data = @socket.readpartial(size)
|
|
20
|
+
@engine.inject(data)
|
|
21
|
+
output = @engine.read
|
|
22
|
+
|
|
23
|
+
return output if output
|
|
24
|
+
|
|
25
|
+
while neg_data = @engine.extract
|
|
26
|
+
@socket.write neg_data
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def engine_read_all
|
|
32
|
+
output = @engine.read
|
|
33
|
+
while output and additional_output = @engine.read
|
|
34
|
+
output << additional_output
|
|
35
|
+
end
|
|
36
|
+
output
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def read_nonblock(size)
|
|
40
|
+
while true
|
|
41
|
+
output = engine_read_all
|
|
42
|
+
return output if output
|
|
43
|
+
|
|
44
|
+
data = @socket.read_nonblock(size)
|
|
45
|
+
|
|
46
|
+
@engine.inject(data)
|
|
47
|
+
output = engine_read_all
|
|
48
|
+
|
|
49
|
+
return output if output
|
|
50
|
+
|
|
51
|
+
while neg_data = @engine.extract
|
|
52
|
+
@socket.write neg_data
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def write(data)
|
|
58
|
+
need = data.bytesize
|
|
59
|
+
|
|
60
|
+
while true
|
|
61
|
+
wrote = @engine.write data
|
|
62
|
+
enc = @engine.extract
|
|
63
|
+
|
|
64
|
+
while enc
|
|
65
|
+
@socket.write enc
|
|
66
|
+
enc = @engine.extract
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
need -= wrote
|
|
70
|
+
|
|
71
|
+
return data.bytesize if need == 0
|
|
72
|
+
|
|
73
|
+
data = data[wrote..-1]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
alias_method :syswrite, :write
|
|
78
|
+
alias_method :<<, :write
|
|
79
|
+
|
|
80
|
+
def flush
|
|
81
|
+
@socket.flush
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def close
|
|
85
|
+
begin
|
|
86
|
+
# Try to setup (so that we can then close them) any
|
|
87
|
+
# partially initialized sockets.
|
|
88
|
+
while @engine.init?
|
|
89
|
+
# Don't let this socket hold this loop forever.
|
|
90
|
+
# If it can't send more packets within 1s, then
|
|
91
|
+
# give up.
|
|
92
|
+
return unless IO.select([@socket], nil, nil, 1)
|
|
93
|
+
begin
|
|
94
|
+
read_nonblock(1024)
|
|
95
|
+
rescue Errno::EAGAIN
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
done = @engine.shutdown
|
|
100
|
+
|
|
101
|
+
while true
|
|
102
|
+
enc = @engine.extract
|
|
103
|
+
@socket.write enc
|
|
104
|
+
|
|
105
|
+
notify = @socket.sysread(1024)
|
|
106
|
+
|
|
107
|
+
@engine.inject notify
|
|
108
|
+
done = @engine.shutdown
|
|
109
|
+
|
|
110
|
+
break if done
|
|
111
|
+
end
|
|
112
|
+
rescue IOError, SystemCallError
|
|
113
|
+
# nothing
|
|
114
|
+
ensure
|
|
115
|
+
@socket.close
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def peeraddr
|
|
120
|
+
@socket.peeraddr
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def peercert
|
|
124
|
+
return @peercert if @peercert
|
|
125
|
+
|
|
126
|
+
raw = @engine.peercert
|
|
127
|
+
return nil unless raw
|
|
128
|
+
|
|
129
|
+
@peercert = OpenSSL::X509::Certificate.new raw
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
if defined?(JRUBY_VERSION)
|
|
134
|
+
class SSLError < StandardError
|
|
135
|
+
# Define this for jruby even though it isn't used.
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def self.check; end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
class Context
|
|
142
|
+
attr_accessor :verify_mode
|
|
143
|
+
|
|
144
|
+
if defined?(JRUBY_VERSION)
|
|
145
|
+
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
|
|
146
|
+
attr_reader :keystore
|
|
147
|
+
attr_accessor :keystore_pass
|
|
148
|
+
|
|
149
|
+
def keystore=(keystore)
|
|
150
|
+
raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore
|
|
151
|
+
@keystore = keystore
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def check
|
|
155
|
+
raise "Keystore not configured" unless @keystore
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
else
|
|
159
|
+
# non-jruby Context properties
|
|
160
|
+
attr_reader :key
|
|
161
|
+
attr_reader :cert
|
|
162
|
+
attr_reader :ca
|
|
163
|
+
|
|
164
|
+
def key=(key)
|
|
165
|
+
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
|
|
166
|
+
@key = key
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def cert=(cert)
|
|
170
|
+
raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
|
|
171
|
+
@cert = cert
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def ca=(ca)
|
|
175
|
+
raise ArgumentError, "No such ca file '#{ca}'" unless File.exist? ca
|
|
176
|
+
@ca = ca
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def check
|
|
180
|
+
raise "Key not configured" unless @key
|
|
181
|
+
raise "Cert not configured" unless @cert
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
VERIFY_NONE = 0
|
|
187
|
+
VERIFY_PEER = 1
|
|
188
|
+
VERIFY_FAIL_IF_NO_PEER_CERT = 2
|
|
189
|
+
|
|
190
|
+
class Server
|
|
191
|
+
def initialize(socket, ctx)
|
|
192
|
+
@socket = socket
|
|
193
|
+
@ctx = ctx
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def to_io
|
|
197
|
+
@socket
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def accept
|
|
201
|
+
@ctx.check
|
|
202
|
+
io = @socket.accept
|
|
203
|
+
engine = Engine.server @ctx
|
|
204
|
+
|
|
205
|
+
Socket.new io, engine
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def accept_nonblock
|
|
209
|
+
@ctx.check
|
|
210
|
+
io = @socket.accept_nonblock
|
|
211
|
+
engine = Engine.server @ctx
|
|
212
|
+
|
|
213
|
+
Socket.new io, engine
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def close
|
|
217
|
+
@socket.close
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
data/lib/puma/null_io.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Puma
|
|
2
|
+
# Provides an IO-like object that always appears to contain no data.
|
|
3
|
+
# Used as the value for rack.input when the request has no body.
|
|
4
|
+
#
|
|
5
|
+
class NullIO
|
|
6
|
+
def gets
|
|
7
|
+
nil
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def each
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Mimics IO#read with no data.
|
|
14
|
+
#
|
|
15
|
+
def read(count = nil, _buffer = nil)
|
|
16
|
+
(count && count > 0) ? nil : ""
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def rewind
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def close
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def size
|
|
26
|
+
0
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def eof?
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def sync=(v)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def puts(*ary)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def write(*ary)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/puma/plugin.rb
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
module Puma
|
|
2
|
+
class UnknownPlugin < RuntimeError; end
|
|
3
|
+
|
|
4
|
+
class PluginLoader
|
|
5
|
+
def initialize
|
|
6
|
+
@instances = []
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def create(name)
|
|
10
|
+
if cls = Plugins.find(name)
|
|
11
|
+
plugin = cls.new(Plugin)
|
|
12
|
+
@instances << plugin
|
|
13
|
+
return plugin
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
raise UnknownPlugin, "File failed to register properly named plugin"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def fire_starts(launcher)
|
|
20
|
+
@instances.each do |i|
|
|
21
|
+
if i.respond_to? :start
|
|
22
|
+
i.start(launcher)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class PluginRegistry
|
|
29
|
+
def initialize
|
|
30
|
+
@plugins = {}
|
|
31
|
+
@background = []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def register(name, cls)
|
|
35
|
+
@plugins[name] = cls
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def find(name)
|
|
39
|
+
name = name.to_s
|
|
40
|
+
|
|
41
|
+
if cls = @plugins[name]
|
|
42
|
+
return cls
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
begin
|
|
46
|
+
require "puma/plugin/#{name}"
|
|
47
|
+
rescue LoadError
|
|
48
|
+
raise UnknownPlugin, "Unable to find plugin: #{name}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if cls = @plugins[name]
|
|
52
|
+
return cls
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
raise UnknownPlugin, "file failed to register a plugin"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def add_background(blk)
|
|
59
|
+
@background << blk
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def fire_background
|
|
63
|
+
@background.each do |b|
|
|
64
|
+
Thread.new(&b)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
Plugins = PluginRegistry.new
|
|
70
|
+
|
|
71
|
+
class Plugin
|
|
72
|
+
# Matches
|
|
73
|
+
# "C:/Ruby22/lib/ruby/gems/2.2.0/gems/puma-3.0.1/lib/puma/plugin/tmp_restart.rb:3:in `<top (required)>'"
|
|
74
|
+
# AS
|
|
75
|
+
# C:/Ruby22/lib/ruby/gems/2.2.0/gems/puma-3.0.1/lib/puma/plugin/tmp_restart.rb
|
|
76
|
+
CALLER_FILE = /
|
|
77
|
+
\A # start of string
|
|
78
|
+
.+ # file path (one or more characters)
|
|
79
|
+
(?= # stop previous match when
|
|
80
|
+
:\d+ # a colon is followed by one or more digits
|
|
81
|
+
:in # followed by a colon followed by in
|
|
82
|
+
)
|
|
83
|
+
/x
|
|
84
|
+
|
|
85
|
+
def self.extract_name(ary)
|
|
86
|
+
path = ary.first[CALLER_FILE]
|
|
87
|
+
|
|
88
|
+
m = %r!puma/plugin/([^/]*)\.rb$!.match(path)
|
|
89
|
+
return m[1]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.create(&blk)
|
|
93
|
+
name = extract_name(caller)
|
|
94
|
+
|
|
95
|
+
cls = Class.new(self)
|
|
96
|
+
|
|
97
|
+
cls.class_eval(&blk)
|
|
98
|
+
|
|
99
|
+
Plugins.register name, cls
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def initialize(loader)
|
|
103
|
+
@loader = loader
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def in_background(&blk)
|
|
107
|
+
Plugins.add_background blk
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def workers_supported?
|
|
111
|
+
return false if Puma.jruby? || Puma.windows?
|
|
112
|
+
true
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'puma/plugin'
|
|
2
|
+
|
|
3
|
+
Puma::Plugin.create do
|
|
4
|
+
def start(launcher)
|
|
5
|
+
path = File.join("tmp", "restart.txt")
|
|
6
|
+
|
|
7
|
+
orig = nil
|
|
8
|
+
|
|
9
|
+
# If we can't write to the path, then just don't bother with this plugin
|
|
10
|
+
begin
|
|
11
|
+
File.write path, ""
|
|
12
|
+
orig = File.stat(path).mtime
|
|
13
|
+
rescue SystemCallError
|
|
14
|
+
return
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
in_background do
|
|
18
|
+
while true
|
|
19
|
+
sleep 2
|
|
20
|
+
|
|
21
|
+
begin
|
|
22
|
+
mtime = File.stat(path).mtime
|
|
23
|
+
rescue SystemCallError
|
|
24
|
+
# If the file has disappeared, assume that means don't restart
|
|
25
|
+
else
|
|
26
|
+
if mtime > orig
|
|
27
|
+
launcher.restart
|
|
28
|
+
break
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# :stopdoc:
|
|
2
|
+
|
|
3
|
+
require 'uri/common'
|
|
4
|
+
|
|
5
|
+
# Issue:
|
|
6
|
+
# http://bugs.ruby-lang.org/issues/5925
|
|
7
|
+
#
|
|
8
|
+
# Relevant commit:
|
|
9
|
+
# https://github.com/ruby/ruby/commit/edb7cdf1eabaff78dfa5ffedfbc2e91b29fa9ca1
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
module URI
|
|
13
|
+
begin
|
|
14
|
+
256.times do |i|
|
|
15
|
+
TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
|
|
16
|
+
end
|
|
17
|
+
TBLENCWWWCOMP_[' '] = '+'
|
|
18
|
+
TBLENCWWWCOMP_.freeze
|
|
19
|
+
|
|
20
|
+
256.times do |i|
|
|
21
|
+
h, l = i>>4, i&15
|
|
22
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
|
23
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
|
24
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
|
25
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
|
26
|
+
end
|
|
27
|
+
TBLDECWWWCOMP_['+'] = ' '
|
|
28
|
+
TBLDECWWWCOMP_.freeze
|
|
29
|
+
rescue Exception
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# :startdoc:
|