yahns 1.4.0 → 1.5.0
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 +4 -4
- data/GIT-VERSION-GEN +1 -1
- data/INSTALL +1 -3
- data/README +1 -2
- data/Rakefile +2 -2
- data/extras/autoindex.rb +3 -1
- data/lib/yahns/config.rb +3 -2
- data/lib/yahns/http_context.rb +0 -1
- data/lib/yahns/http_response.rb +5 -6
- data/lib/yahns/openssl_client.rb +54 -0
- data/lib/yahns/openssl_server.rb +21 -0
- data/lib/yahns/rackup_handler.rb +2 -2
- data/lib/yahns/sendfile_compat.rb +5 -7
- data/lib/yahns/server.rb +9 -9
- data/lib/yahns/socket_helper.rb +13 -4
- data/lib/yahns/tmpio.rb +1 -1
- data/lib/yahns/wbuf_common.rb +7 -3
- data/test/server_helper.rb +3 -3
- data/test/test_serve_static.rb +61 -0
- data/test/test_ssl.rb +79 -0
- data/yahns.gemspec +1 -1
- metadata +6 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b72841cf8d034892a5616279ac723d75439b9a2c
|
4
|
+
data.tar.gz: 01710a8efb79f9eb9262775c4f3dcea178c302c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d80a9d094e857d97f7192c1aa79ad7235dae23a85bd2a0967c8a83cf26960f04dcfc89300182b8fb2235dde9b6cae7ca3717d2c89e830f6815c625c0c2d99d15
|
7
|
+
data.tar.gz: 11a80294b69429051ddcdc3121f12f4179251271de70bf344a73b39deaea190b91d3004a273f162e57fcc12306ae48bd7cda1c5c6758d306de88585f6f7d7131
|
data/GIT-VERSION-GEN
CHANGED
data/INSTALL
CHANGED
data/README
CHANGED
@@ -48,8 +48,7 @@ We have experimental support kqueue on FreeBSD (and possibly OpenBSD and
|
|
48
48
|
NetBSD). Non-Free systems/dependencies will never be supported.
|
49
49
|
|
50
50
|
Supported Ruby implementations:
|
51
|
-
* (Matz) Ruby
|
52
|
-
* Rubinius 2.0 or later (best-effort)
|
51
|
+
* (Matz) Ruby 2.0.0 and later (we develop (and host our website) on trunk)
|
53
52
|
|
54
53
|
Contact
|
55
54
|
-------
|
data/Rakefile
CHANGED
@@ -116,11 +116,11 @@ task "NEWS" do
|
|
116
116
|
time = nil
|
117
117
|
tags.each do |tag|
|
118
118
|
time ||= tag[:time_obj]
|
119
|
-
line = tag[:subject] + " / " + tag[:time].
|
119
|
+
line = tag[:subject] + " / " + tag[:time].sub(/T.*/, '')
|
120
120
|
fp.puts line
|
121
121
|
fp.puts("-" * line.length)
|
122
122
|
fp.puts
|
123
|
-
fp.puts tag[:body]
|
123
|
+
fp.puts tag[:body]
|
124
124
|
fp.puts
|
125
125
|
end
|
126
126
|
fp.write("Unreleased\n\n") unless fp.size > 0
|
data/extras/autoindex.rb
CHANGED
@@ -107,7 +107,9 @@ class Autoindex
|
|
107
107
|
|
108
108
|
if ngz_idx
|
109
109
|
ngz_idx.each do |name, entry|
|
110
|
-
|
110
|
+
# n.b: use use dup.sub! to ensure ngz_path is nil
|
111
|
+
# if .gz is not found
|
112
|
+
ngz_path = name.dup.sub!(/\.gz\z/, '')
|
111
113
|
ngz_idx.include?(ngz_path) or files << entry
|
112
114
|
end
|
113
115
|
end
|
data/lib/yahns/config.rb
CHANGED
@@ -202,6 +202,8 @@ class Yahns::Config # :nodoc:
|
|
202
202
|
raise ArgumentError, "#{var}: not boolean: #{key}=#{value.inspect}"
|
203
203
|
end
|
204
204
|
|
205
|
+
require_relative('openssl_server') if options[:ssl_ctx]
|
206
|
+
|
205
207
|
options[:yahns_app_ctx] = @block.ctx
|
206
208
|
@config_listeners.include?(address) and
|
207
209
|
raise ArgumentError, "listen #{address} already in use"
|
@@ -363,7 +365,6 @@ class Yahns::Config # :nodoc:
|
|
363
365
|
# config name, minimum value
|
364
366
|
client_body_buffer_size: 1,
|
365
367
|
client_header_buffer_size: 1,
|
366
|
-
client_max_header_size: 1,
|
367
368
|
}.each do |_v,minval|
|
368
369
|
eval(
|
369
370
|
%Q(def #{_v}(val);) <<
|
@@ -403,7 +404,7 @@ class Yahns::Config # :nodoc:
|
|
403
404
|
val.close_on_exec = val.sync = true
|
404
405
|
val.binmode
|
405
406
|
else
|
406
|
-
rt =
|
407
|
+
rt = [ :puts, :write, :flush ] # match Rack::Lint
|
407
408
|
rt.all? { |m| val.respond_to?(m) } or raise ArgumentError,
|
408
409
|
"`#{var}' destination must respond to all of: #{rt.inspect}"
|
409
410
|
end
|
data/lib/yahns/http_context.rb
CHANGED
@@ -9,7 +9,6 @@ module Yahns::HttpContext # :nodoc:
|
|
9
9
|
attr_accessor :client_body_buffer_size
|
10
10
|
attr_accessor :client_header_buffer_size
|
11
11
|
attr_accessor :client_max_body_size
|
12
|
-
attr_accessor :client_max_header_size
|
13
12
|
attr_accessor :input_buffering # :lazy, true, false
|
14
13
|
attr_accessor :output_buffering # true, false
|
15
14
|
attr_accessor :persistent_connections # true or false only
|
data/lib/yahns/http_response.rb
CHANGED
@@ -27,10 +27,7 @@ module Yahns::HttpResponse # :nodoc:
|
|
27
27
|
CONN_CLOSE = "Connection: close\r\n\r\n"
|
28
28
|
Z = ""
|
29
29
|
CCC_RESPONSE_START = [ 'HTTP', '/1.1 ' ]
|
30
|
-
RESPONSE_START = CCC_RESPONSE_START.join
|
31
|
-
R100_RAW = "HTTP/1.1 100 Continue\r\n\r\n"
|
32
|
-
R100_CCC = "100 Continue\r\n\r\nHTTP/1.1 "
|
33
|
-
HTTP_EXPECT = "HTTP_EXPECT"
|
30
|
+
RESPONSE_START = CCC_RESPONSE_START.join
|
34
31
|
REQUEST_METHOD = "REQUEST_METHOD"
|
35
32
|
HEAD = "HEAD"
|
36
33
|
|
@@ -258,8 +255,10 @@ module Yahns::HttpResponse # :nodoc:
|
|
258
255
|
# returns nil on success
|
259
256
|
# returns :close, :wait_writable, or :wait_readable
|
260
257
|
def http_100_response(env)
|
261
|
-
env.delete(HTTP_EXPECT) =~ /\A100-continue\z/i or return
|
262
|
-
buf = @response_start_sent ?
|
258
|
+
env.delete("HTTP_EXPECT") =~ /\A100-continue\z/i or return
|
259
|
+
buf = @response_start_sent ? "100 Continue\r\n\r\nHTTP/1.1 ".freeze
|
260
|
+
: "HTTP/1.1 100 Continue\r\n\r\n".freeze
|
261
|
+
|
263
262
|
case rv = kgio_trywrite(buf)
|
264
263
|
when String
|
265
264
|
buf = rv
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Copyright (C) 2014, all contributors <yahns-public@yhbt.net>
|
2
|
+
# License: GPLv3 or later (see COPYING for details)
|
3
|
+
|
4
|
+
require_relative 'sendfile_compat'
|
5
|
+
|
6
|
+
# this is to be included into a Kgio::Socket-derived class
|
7
|
+
# this requires Ruby 2.1 and later for "exception: false"
|
8
|
+
module Yahns::OpenSSLClient # :nodoc:
|
9
|
+
include Yahns::SendfileCompat
|
10
|
+
|
11
|
+
def yahns_init_ssl(ssl_ctx)
|
12
|
+
@need_accept = true
|
13
|
+
@ssl = OpenSSL::SSL::SSLSocket.new(self, ssl_ctx)
|
14
|
+
end
|
15
|
+
|
16
|
+
def kgio_trywrite(buf)
|
17
|
+
rv = @ssl.write_nonblock(buf, exception: false)
|
18
|
+
Integer === rv and
|
19
|
+
rv = buf.bytesize == rv ? nil : buf.byteslice(rv, buf.bytesize)
|
20
|
+
rv
|
21
|
+
end
|
22
|
+
|
23
|
+
def kgio_syssend(buf, flags)
|
24
|
+
kgio_trywrite(buf)
|
25
|
+
end
|
26
|
+
|
27
|
+
def kgio_tryread(len, buf)
|
28
|
+
if @need_accept
|
29
|
+
# most protocols require read before write, so we start the negotiation
|
30
|
+
# process here:
|
31
|
+
begin
|
32
|
+
@ssl.accept_nonblock
|
33
|
+
rescue IO::WaitReadable
|
34
|
+
return :wait_readable
|
35
|
+
rescue IO::WaitWritable
|
36
|
+
return :wait_writable
|
37
|
+
rescue OpenSSL::SSL::SSLError
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
@need_accept = false
|
41
|
+
end
|
42
|
+
@ssl.read_nonblock(len, buf, exception: false)
|
43
|
+
end
|
44
|
+
|
45
|
+
def shutdown(*args)
|
46
|
+
@ssl.shutdown(*args)
|
47
|
+
super # BasicSocket#shutdown
|
48
|
+
end
|
49
|
+
|
50
|
+
def close
|
51
|
+
@ssl.close
|
52
|
+
super # IO#close
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright (C) 2014, all contributors <yahns-public@yhbt.net>
|
2
|
+
# License: GPLv3 or later (see COPYING for details)
|
3
|
+
|
4
|
+
require_relative 'acceptor'
|
5
|
+
require_relative 'openssl_client'
|
6
|
+
|
7
|
+
class Yahns::OpenSSLServer < Kgio::TCPServer # :nodoc:
|
8
|
+
include Yahns::Acceptor
|
9
|
+
|
10
|
+
def self.wrap(fd, ssl_ctx)
|
11
|
+
srv = for_fd(fd)
|
12
|
+
srv.instance_variable_set(:@ssl_ctx, ssl_ctx)
|
13
|
+
srv
|
14
|
+
end
|
15
|
+
|
16
|
+
def kgio_accept(klass, flags)
|
17
|
+
io = super
|
18
|
+
io.yahns_init_ssl(@ssl_ctx)
|
19
|
+
io
|
20
|
+
end
|
21
|
+
end
|
data/lib/yahns/rackup_handler.rb
CHANGED
@@ -18,8 +18,8 @@ module Yahns::RackupHandler # :nodoc:
|
|
18
18
|
app(:rack, app) do
|
19
19
|
addr = o[:listen] || "#{o[:Host]||default_host}:#{o[:Port]||8080}"
|
20
20
|
# allow listening to multiple addresses
|
21
|
-
if addr
|
22
|
-
addr.split(
|
21
|
+
if addr.include?(',')
|
22
|
+
addr.split(',').each { |l| listen(l) }
|
23
23
|
else
|
24
24
|
listen addr
|
25
25
|
end
|
@@ -1,25 +1,23 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
# Copyright (C) 2009-2014, Eric Wong <normalperson@yhbt.net> et. al.
|
3
3
|
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
|
-
require 'io/extra' # gem install io-extra
|
5
4
|
|
6
5
|
module Yahns::SendfileCompat
|
7
6
|
def trysendfile(io, offset, count)
|
8
7
|
return 0 if count == 0
|
9
8
|
count = 0x4000 if count > 0x4000
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
9
|
+
buf = Thread.current[:yahns_sfbuf] ||= ''
|
10
|
+
io.pos = offset
|
11
|
+
str = io.read(count, buf) or return # nil for EOF
|
14
12
|
n = 0
|
15
13
|
case rv = kgio_trywrite(str)
|
16
14
|
when String # partial write, keep trying
|
17
|
-
n += (str.
|
15
|
+
n += (str.size - rv.size)
|
18
16
|
str = rv
|
19
17
|
when :wait_writable, :wait_readable
|
20
18
|
return n > 0 ? n : rv
|
21
19
|
when nil
|
22
|
-
return n + str.
|
20
|
+
return n + str.size # yay!
|
23
21
|
end while true
|
24
22
|
end
|
25
23
|
end
|
data/lib/yahns/server.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
1
|
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
|
3
2
|
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
3
|
require_relative 'queue_quitter'
|
@@ -178,10 +177,9 @@ class Yahns::Server # :nodoc:
|
|
178
177
|
tries = 5
|
179
178
|
|
180
179
|
begin
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
end
|
180
|
+
opts = sock_opts(address)
|
181
|
+
io = bind_listen(address, opts)
|
182
|
+
io = server_cast(io, opts) unless io.class.name.start_with?('Yahns::')
|
185
183
|
@logger.info "listening on addr=#{sock_name(io)} fd=#{io.fileno}"
|
186
184
|
@listeners << io
|
187
185
|
io
|
@@ -299,7 +297,7 @@ class Yahns::Server # :nodoc:
|
|
299
297
|
end
|
300
298
|
|
301
299
|
def sock_opts(io)
|
302
|
-
@config.config_listeners[sock_name(io)]
|
300
|
+
@config.config_listeners[sock_name(io)] || {}
|
303
301
|
end
|
304
302
|
|
305
303
|
def inherit_listeners!
|
@@ -314,11 +312,12 @@ class Yahns::Server # :nodoc:
|
|
314
312
|
# because that can completely break the non-blocking one.
|
315
313
|
# Unfortunately, there is no one-off MSG_DONTWAIT-like flag for
|
316
314
|
# accept4(2).
|
317
|
-
inherited = ENV['YAHNS_FD'].to_s.split(
|
315
|
+
inherited = ENV['YAHNS_FD'].to_s.split(',').map! do |fd|
|
318
316
|
io = Socket.for_fd(fd.to_i)
|
319
|
-
|
317
|
+
opts = sock_opts(io)
|
318
|
+
set_server_sockopt(io, opts)
|
320
319
|
@logger.info "inherited addr=#{sock_name(io)} fd=#{fd}"
|
321
|
-
server_cast(io)
|
320
|
+
server_cast(io, opts)
|
322
321
|
end
|
323
322
|
|
324
323
|
@listeners.replace(inherited)
|
@@ -369,6 +368,7 @@ class Yahns::Server # :nodoc:
|
|
369
368
|
ctx.queue = queues[qegg] ||= qegg_vivify(qegg, fdmap)
|
370
369
|
ctx = ctx.dup
|
371
370
|
ctx.__send__(:include, l.expire_mod)
|
371
|
+
ctx.__send__(:include, Yahns::OpenSSLClient) if opts[:ssl_ctx]
|
372
372
|
ctx_list << ctx
|
373
373
|
# acceptors feed the the queues
|
374
374
|
l.spawn_acceptor(opts[:threads] || 1, @logger, ctx)
|
data/lib/yahns/socket_helper.rb
CHANGED
@@ -16,7 +16,7 @@ module Yahns::SocketHelper # :nodoc:
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def set_server_sockopt(sock, opt)
|
19
|
-
opt = {backlog: 1024}.merge!(opt
|
19
|
+
opt = {backlog: 1024}.merge!(opt)
|
20
20
|
sock.close_on_exec = true
|
21
21
|
|
22
22
|
TCPSocket === sock and sock.setsockopt(:IPPROTO_TCP, :TCP_NODELAY, 1)
|
@@ -97,7 +97,12 @@ module Yahns::SocketHelper # :nodoc:
|
|
97
97
|
|
98
98
|
sock.bind(Socket.pack_sockaddr_in(port, addr))
|
99
99
|
sock.autoclose = false
|
100
|
-
|
100
|
+
|
101
|
+
if ssl_ctx = opt[:ssl_ctx]
|
102
|
+
Yahns::OpenSSLServer.wrap(sock.fileno, ssl_ctx)
|
103
|
+
else
|
104
|
+
Yahns::TCPServer.for_fd(sock.fileno)
|
105
|
+
end
|
101
106
|
end
|
102
107
|
|
103
108
|
# returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6
|
@@ -128,11 +133,15 @@ module Yahns::SocketHelper # :nodoc:
|
|
128
133
|
end
|
129
134
|
|
130
135
|
# casts a given Socket to be a TCPServer or UNIXServer
|
131
|
-
def server_cast(sock)
|
136
|
+
def server_cast(sock, opts)
|
132
137
|
sock.autoclose = false
|
133
138
|
begin
|
134
139
|
Socket.unpack_sockaddr_in(sock.getsockname)
|
135
|
-
|
140
|
+
if ssl_ctx = opts[:ssl_ctx]
|
141
|
+
Yahns::OpenSSLServer.wrap(sock.fileno, ssl_ctx)
|
142
|
+
else
|
143
|
+
Yahns::TCPServer.for_fd(sock.fileno)
|
144
|
+
end
|
136
145
|
rescue ArgumentError
|
137
146
|
Yahns::UNIXServer.for_fd(sock.fileno)
|
138
147
|
end
|
data/lib/yahns/tmpio.rb
CHANGED
@@ -14,7 +14,7 @@ class Yahns::TmpIO < File # :nodoc:
|
|
14
14
|
def self.new(tmpdir = Dir.tmpdir)
|
15
15
|
retried = false
|
16
16
|
begin
|
17
|
-
fp = super("#{tmpdir}/#{rand}", RDWR|CREAT|EXCL, 0600)
|
17
|
+
fp = super("#{tmpdir}/#{rand}", RDWR|CREAT|EXCL|APPEND, 0600)
|
18
18
|
rescue Errno::EEXIST
|
19
19
|
retry
|
20
20
|
rescue Errno::EMFILE, Errno::ENFILE
|
data/lib/yahns/wbuf_common.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
# Copyright (C) 2009-2013, Eric Wong <normalperson@yhbt.net> et. al.
|
3
3
|
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
4
|
-
|
5
|
-
|
6
|
-
else
|
4
|
+
begin
|
5
|
+
raise LoadError, "SENDFILE_BROKEN env set" if ENV["SENDFILE_BROKEN"]
|
7
6
|
require 'sendfile'
|
7
|
+
rescue LoadError
|
8
|
+
require_relative 'sendfile_compat'
|
8
9
|
end
|
9
10
|
|
10
11
|
module Yahns::WbufCommon # :nodoc:
|
@@ -32,6 +33,9 @@ module Yahns::WbufCommon # :nodoc:
|
|
32
33
|
"sf_offset=#@sf_offset sf_count=#@sf_count"
|
33
34
|
end while @sf_count > 0
|
34
35
|
wbuf_close(client)
|
36
|
+
rescue
|
37
|
+
wbuf_close(client)
|
38
|
+
raise
|
35
39
|
end
|
36
40
|
|
37
41
|
def wbuf_close_common(client)
|
data/test/server_helper.rb
CHANGED
@@ -61,9 +61,9 @@ module ServerHelper
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def server_helper_teardown
|
64
|
-
@srv.close
|
65
|
-
@ru.close! if @ru
|
66
|
-
check_err
|
64
|
+
@srv.close if defined?(@srv) && !@srv.closed?
|
65
|
+
@ru.close! if defined?(@ru) && @ru
|
66
|
+
check_err if defined?(@err)
|
67
67
|
end
|
68
68
|
|
69
69
|
def server_helper_setup
|
data/test/test_serve_static.rb
CHANGED
@@ -85,6 +85,67 @@ class TestServeStatic < Testcase
|
|
85
85
|
[ off + 1, sparse ]
|
86
86
|
end
|
87
87
|
|
88
|
+
class ToPathClose
|
89
|
+
attr_reader :closed_p
|
90
|
+
|
91
|
+
def initialize(app, tmpdir)
|
92
|
+
@app = app
|
93
|
+
@tmpdir = tmpdir
|
94
|
+
@log = "#@tmpdir/to_path--close"
|
95
|
+
@body = nil
|
96
|
+
@closed_p = false
|
97
|
+
end
|
98
|
+
|
99
|
+
def call(env)
|
100
|
+
s, h, b = @app.call(env)
|
101
|
+
@body = b
|
102
|
+
[ s, h, self ]
|
103
|
+
end
|
104
|
+
|
105
|
+
def each
|
106
|
+
raise "ToPathClose#each should not be called"
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_path
|
110
|
+
File.open(@log, "a") { |fp| fp.write("to_path\n") }
|
111
|
+
"#@tmpdir/sparse"
|
112
|
+
end
|
113
|
+
|
114
|
+
def close
|
115
|
+
File.open(@log, "a") { |fp| fp.write("close\n") }
|
116
|
+
raise "Double close" if @closed_p
|
117
|
+
@closed_p = true
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_aborted_sendfile_closes_opened_path
|
123
|
+
tmpdir = Dir.mktmpdir
|
124
|
+
mksparse(tmpdir)
|
125
|
+
fifo = "#{tmpdir}/to_path--close"
|
126
|
+
assert system("mkfifo", fifo), "mkfifo"
|
127
|
+
err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
|
128
|
+
pid = mkserver(cfg) do
|
129
|
+
cfg.instance_eval do
|
130
|
+
app = Rack::Builder.new do
|
131
|
+
use ToPathClose, tmpdir
|
132
|
+
run Rack::File.new(tmpdir)
|
133
|
+
end
|
134
|
+
app(:rack, app) { listen "#{host}:#{port}" }
|
135
|
+
stderr_path err.path
|
136
|
+
end
|
137
|
+
end
|
138
|
+
c = get_tcp_client(host, port)
|
139
|
+
c.write "GET /sparse HTTP/1.1\r\nHost: example.com\r\n\r\n"
|
140
|
+
assert_equal "to_path\n", File.read(fifo)
|
141
|
+
wait_for_full(c)
|
142
|
+
assert_nil c.close
|
143
|
+
Timeout.timeout(30) { assert_equal "close\n", File.read(fifo) }
|
144
|
+
ensure
|
145
|
+
quit_wait(pid)
|
146
|
+
FileUtils.rm_rf(tmpdir)
|
147
|
+
end
|
148
|
+
|
88
149
|
def test_truncated_sendfile
|
89
150
|
tmpdir = Dir.mktmpdir
|
90
151
|
size, sparse = mksparse(tmpdir)
|
data/test/test_ssl.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright (C) 2014, all contributors <yahns-public@yhbt.net>
|
2
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
3
|
+
require_relative 'server_helper'
|
4
|
+
require 'openssl'
|
5
|
+
class TestSSL < Testcase
|
6
|
+
ENV["N"].to_i > 1 and parallelize_me!
|
7
|
+
include ServerHelper
|
8
|
+
|
9
|
+
r, w = IO.pipe
|
10
|
+
FAST_NB = begin
|
11
|
+
:wait_readable == r.read_nonblock(1, exception: false)
|
12
|
+
rescue
|
13
|
+
false
|
14
|
+
end
|
15
|
+
r.close
|
16
|
+
w.close
|
17
|
+
|
18
|
+
# copied from test/openssl/utils.rb in Ruby:
|
19
|
+
|
20
|
+
TEST_KEY_DH1024 = OpenSSL::PKey::DH.new <<-_end_of_pem_
|
21
|
+
-----BEGIN DH PARAMETERS-----
|
22
|
+
MIGHAoGBAKnKQ8MNK6nYZzLrrcuTsLxuiJGXoOO5gT+tljOTbHBuiktdMTITzIY0
|
23
|
+
pFxIvjG05D7HoBZQfrR0c92NGWPkAiCkhQKB8JCbPVzwNLDy6DZ0pmofDKrEsYHG
|
24
|
+
AQjjxMXhwULlmuR/K+WwlaZPiLIBYalLAZQ7ZbOPeVkJ8ePao0eLAgEC
|
25
|
+
-----END DH PARAMETERS-----
|
26
|
+
_end_of_pem_
|
27
|
+
|
28
|
+
TEST_KEY_DH1024.priv_key = OpenSSL::BN.new("48561834C67E65FFD2A9B47F41" \
|
29
|
+
"E5E78FDC95C387428FDB1E4B0188B64D1643C3A8D3455B945B7E8C4D166010C7C2" \
|
30
|
+
"CE23BFB9BEF43D0348FE7FA5284B0225E7FE1537546D114E3D8A4411B9B9351AB4" \
|
31
|
+
"51E1A358F50ED61B1F00DA29336EEBBD649980AC86D76AF8BBB065298C2052672E" \
|
32
|
+
"EF3EF13AB47A15275FC2836F3AC74CEA", 16)
|
33
|
+
|
34
|
+
def setup
|
35
|
+
unless FAST_NB
|
36
|
+
skip "missing exception-free non-blocking IO in " \
|
37
|
+
"#{RUBY_ENGINE} #{RUBY_VERSION}"
|
38
|
+
end
|
39
|
+
server_helper_setup
|
40
|
+
end
|
41
|
+
|
42
|
+
def teardown
|
43
|
+
server_helper_teardown
|
44
|
+
end
|
45
|
+
|
46
|
+
def ssl_client(host, port)
|
47
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
48
|
+
ctx.ciphers = "ADH"
|
49
|
+
s = TCPSocket.new(host, port)
|
50
|
+
ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
|
51
|
+
ssl.connect
|
52
|
+
ssl.sync_close = true
|
53
|
+
ssl
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_ssl_basic
|
57
|
+
err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
|
58
|
+
host, port = @srv.addr[3], @srv.addr[1]
|
59
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
60
|
+
ctx.ciphers = "ADH"
|
61
|
+
ctx.tmp_dh_callback = proc { TEST_KEY_DH1024 }
|
62
|
+
|
63
|
+
pid = mkserver(cfg) do
|
64
|
+
cfg.instance_eval do
|
65
|
+
ru = lambda { |_| [ 200, {'Content-Length'=>'2'}, ['HI'] ] }
|
66
|
+
app(:rack, ru) { listen "#{host}:#{port}", ssl_ctx: ctx }
|
67
|
+
logger(Logger.new(err.path))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
client = ssl_client(host, port)
|
71
|
+
client.write("GET / HTTP/1.0\r\n\r\n")
|
72
|
+
head, body = client.read.split("\r\n\r\n", 2)
|
73
|
+
assert_equal "HI", body
|
74
|
+
assert_match %r{\AHTTP/1\.\d 200 OK\r\n}, head
|
75
|
+
ensure
|
76
|
+
client.close if client
|
77
|
+
quit_wait(pid)
|
78
|
+
end
|
79
|
+
end if defined?(OpenSSL)
|
data/yahns.gemspec
CHANGED
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.files = manifest
|
13
13
|
s.add_dependency(%q<kgio>, '~> 2.9')
|
14
14
|
s.add_dependency(%q<sleepy_penguin>, '~> 3.2')
|
15
|
-
s.add_dependency(%q<kgio-sendfile>, '~> 1.2')
|
16
15
|
s.add_dependency(%q<unicorn>, '~> 4.6', '>= 4.6.3')
|
16
|
+
# s.add_dependency(%q<kgio-sendfile>, '~> 1.2') # optional
|
17
17
|
|
18
18
|
# minitest is standard in Ruby 2.0, 4.3 is packaged with Ruby 2.0.0,
|
19
19
|
# 4.7.5 with 2.1. We work with minitest 5, too. 6.x does not exist
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yahns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yahns hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kgio
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.2'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: kgio-sendfile
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.2'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.2'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: unicorn
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -149,6 +135,8 @@ files:
|
|
149
135
|
- lib/yahns/max_body.rb
|
150
136
|
- lib/yahns/max_body/rewindable_wrapper.rb
|
151
137
|
- lib/yahns/max_body/wrapper.rb
|
138
|
+
- lib/yahns/openssl_client.rb
|
139
|
+
- lib/yahns/openssl_server.rb
|
152
140
|
- lib/yahns/queue.rb
|
153
141
|
- lib/yahns/queue_egg.rb
|
154
142
|
- lib/yahns/queue_epoll.rb
|
@@ -201,6 +189,7 @@ files:
|
|
201
189
|
- test/test_response.rb
|
202
190
|
- test/test_serve_static.rb
|
203
191
|
- test/test_server.rb
|
192
|
+
- test/test_ssl.rb
|
204
193
|
- test/test_stream_file.rb
|
205
194
|
- test/test_unix_socket.rb
|
206
195
|
- test/test_wbuf.rb
|
@@ -225,7 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
214
|
version: '0'
|
226
215
|
requirements: []
|
227
216
|
rubyforge_project:
|
228
|
-
rubygems_version: 2.4.
|
217
|
+
rubygems_version: 2.4.5
|
229
218
|
signing_key:
|
230
219
|
specification_version: 4
|
231
220
|
summary: sleepy, multi-threaded, non-blocking application server
|