Update to ruby/spec@330c641
This commit is contained in:
parent
ac4d53bd46
commit
73085c8d8e
@ -4,7 +4,11 @@ describe "GC.stat" do
|
|||||||
it "returns hash of values" do
|
it "returns hash of values" do
|
||||||
stat = GC.stat
|
stat = GC.stat
|
||||||
stat.should be_kind_of(Hash)
|
stat.should be_kind_of(Hash)
|
||||||
stat.keys.should include(:count)
|
stat.keys.should.include?(:count)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "the values are all Integer since rb_gc_stat() returns size_t" do
|
||||||
|
GC.stat.values.each { |value| value.should be_kind_of(Integer) }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can return a single value" do
|
it "can return a single value" do
|
||||||
|
@ -45,6 +45,10 @@ describe "A number literal" do
|
|||||||
eval('-3r').should == Rational(-3, 1)
|
eval('-3r').should == Rational(-3, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can be an float literal with trailing 'r' to represent a Rational in a canonical form" do
|
||||||
|
eval('1.0r').should == Rational(1, 1)
|
||||||
|
end
|
||||||
|
|
||||||
it "can be a float literal with trailing 'r' to represent a Rational" do
|
it "can be a float literal with trailing 'r' to represent a Rational" do
|
||||||
eval('0.0174532925199432957r').should == Rational(174532925199432957, 10000000000000000000)
|
eval('0.0174532925199432957r').should == Rational(174532925199432957, 10000000000000000000)
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
require 'webrick'
|
require 'socket'
|
||||||
require 'webrick/httpservlet/abstract'
|
|
||||||
|
|
||||||
module NetHTTPSpecs
|
module NetHTTPSpecs
|
||||||
class NullWriter
|
class NullWriter
|
||||||
@ -9,102 +8,117 @@ module NetHTTPSpecs
|
|||||||
def printf(*args) end
|
def printf(*args) end
|
||||||
end
|
end
|
||||||
|
|
||||||
class SpecServlet < WEBrick::HTTPServlet::AbstractServlet
|
class SmallHTTPServer
|
||||||
def handle(req, res)
|
def initialize(bind_address)
|
||||||
reply(req, res)
|
@server = TCPServer.new(bind_address, 0)
|
||||||
|
@running = Mutex.new
|
||||||
|
@thread = Thread.new {
|
||||||
|
Thread.current.abort_on_exception = true
|
||||||
|
listen
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
%w{ do_GET do_HEAD do_POST do_PUT do_PROPPATCH do_LOCK do_UNLOCK
|
def port
|
||||||
do_OPTIONS do_PROPFIND do_DELETE do_MOVE do_COPY
|
@server.addr[1]
|
||||||
do_MKCOL do_TRACE }.each do |method|
|
|
||||||
alias_method method.to_sym, :handle
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
class RequestServlet < SpecServlet
|
def listen
|
||||||
def reply(req, res)
|
loop do
|
||||||
res.content_type = "text/plain"
|
begin
|
||||||
res.body = "Request type: #{req.request_method}"
|
client = @server.accept
|
||||||
end
|
rescue IOError => e
|
||||||
end
|
if @running.locked? # close
|
||||||
|
break
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class RequestBodyServlet < SpecServlet
|
handle_client(client)
|
||||||
def reply(req, res)
|
|
||||||
res.content_type = "text/plain"
|
|
||||||
res.body = req.body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class RequestHeaderServlet < SpecServlet
|
|
||||||
def reply(req, res)
|
|
||||||
res.content_type = "text/plain"
|
|
||||||
res.body = req.header.inspect
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class RequestBasicAuthServlet < SpecServlet
|
|
||||||
def reply(req, res)
|
|
||||||
res.content_type = "text/plain"
|
|
||||||
|
|
||||||
WEBrick::HTTPAuth.basic_auth(req, res, "realm") do |user, pass|
|
|
||||||
res.body = "username: #{user}\npassword: #{pass}"
|
|
||||||
true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_client(client)
|
||||||
|
begin
|
||||||
|
until client.closed?
|
||||||
|
request = client.gets("\r\n\r\n")
|
||||||
|
break unless request
|
||||||
|
handle_request(client, request)
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
client.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_request(request)
|
||||||
|
request, *headers = request.chomp.lines.map { |line| line.chomp }
|
||||||
|
request_method, request_uri, _http_version = request.split
|
||||||
|
headers = headers.map { |line| line.split(': ', 2) }.to_h
|
||||||
|
[request_method, request_uri, headers]
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_request(client, request)
|
||||||
|
request_method, request_uri, headers = parse_request(request)
|
||||||
|
|
||||||
|
if headers.include? 'Content-Length'
|
||||||
|
request_body_size = Integer(headers['Content-Length'])
|
||||||
|
request_body = client.read(request_body_size)
|
||||||
|
end
|
||||||
|
|
||||||
|
case request_uri
|
||||||
|
when '/'
|
||||||
|
raise request_method unless request_method == 'GET'
|
||||||
|
reply(client, "This is the index page.", request_method)
|
||||||
|
when '/request'
|
||||||
|
reply(client, "Request type: #{request_method}", request_method)
|
||||||
|
when '/request/body'
|
||||||
|
reply(client, request_body, request_method)
|
||||||
|
when '/request/header'
|
||||||
|
reply(client, headers.inspect, request_method)
|
||||||
|
when '/request/basic_auth'
|
||||||
|
reply(client, "username: \npassword: ", request_method)
|
||||||
|
else
|
||||||
|
raise request_uri
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def reply(client, body, request_method)
|
||||||
|
client.print "HTTP/1.1 200 OK\r\n"
|
||||||
|
if request_method == 'HEAD'
|
||||||
|
client.close
|
||||||
|
else
|
||||||
|
client.print "Content-Type: text/plain\r\n"
|
||||||
|
client.print "Content-Length: #{body.bytesize}\r\n"
|
||||||
|
client.print "\r\n"
|
||||||
|
client.print body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def close
|
||||||
|
@running.lock
|
||||||
|
@server.close
|
||||||
|
@thread.join
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@server = nil
|
@server = nil
|
||||||
@server_thread = nil
|
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def port
|
def port
|
||||||
raise "server not started" unless @server
|
raise "server not started" unless @server
|
||||||
@server.config[:Port]
|
@server.port
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_server
|
def start_server
|
||||||
bind_address = platform_is(:windows) ? "localhost" : "127.0.0.1"
|
bind_address = platform_is(:windows) ? "localhost" : "127.0.0.1"
|
||||||
server_config = {
|
@server = SmallHTTPServer.new(bind_address)
|
||||||
BindAddress: bind_address,
|
|
||||||
Port: 0,
|
|
||||||
Logger: WEBrick::Log.new(NullWriter.new),
|
|
||||||
AccessLog: [],
|
|
||||||
ServerType: Thread
|
|
||||||
}
|
|
||||||
|
|
||||||
@server = WEBrick::HTTPServer.new(server_config)
|
|
||||||
|
|
||||||
@server.mount_proc('/') do |req, res|
|
|
||||||
res.content_type = "text/plain"
|
|
||||||
res.body = "This is the index page."
|
|
||||||
end
|
|
||||||
@server.mount('/request', RequestServlet)
|
|
||||||
@server.mount("/request/body", RequestBodyServlet)
|
|
||||||
@server.mount("/request/header", RequestHeaderServlet)
|
|
||||||
@server.mount("/request/basic_auth", RequestBasicAuthServlet)
|
|
||||||
|
|
||||||
@server_thread = @server.start
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def stop_server
|
def stop_server
|
||||||
if @server
|
if @server
|
||||||
begin
|
@server.close
|
||||||
@server.shutdown
|
|
||||||
rescue Errno::EPIPE, Errno::EBADF
|
|
||||||
# Because WEBrick is not thread-safe and only catches IOError
|
|
||||||
|
|
||||||
# EBADF can happen because WEBrick @server_thread concurrently closes the shutdown pipe
|
|
||||||
# once @status = :Shutdown, while the current thread does write_nonblock("\0").
|
|
||||||
# On MRI this EBADF is replaced by IOError due to the GIL around both #close and #write_nonblock.
|
|
||||||
end
|
|
||||||
@server = nil
|
@server = nil
|
||||||
end
|
end
|
||||||
if @server_thread
|
|
||||||
@server_thread.join
|
|
||||||
@server_thread = nil
|
|
||||||
end
|
|
||||||
timeout = WEBrick::Utils::TimeoutHandler
|
|
||||||
timeout.terminate if timeout.respond_to?(:terminate)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,7 +27,7 @@ describe "Net::HTTP.post" do
|
|||||||
|
|
||||||
it "sends Content-Type: application/x-www-form-urlencoded by default" do
|
it "sends Content-Type: application/x-www-form-urlencoded by default" do
|
||||||
response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request/header"), "test=test")
|
response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request/header"), "test=test")
|
||||||
response.body.should include('"content-type"=>["application/x-www-form-urlencoded"]')
|
response.body.should include('"Content-Type"=>"application/x-www-form-urlencoded"')
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not support HTTP Basic Auth" do
|
it "does not support HTTP Basic Auth" do
|
||||||
|
@ -54,7 +54,7 @@ describe "Net::HTTP#send_request" do
|
|||||||
|
|
||||||
@methods.each do |method|
|
@methods.each do |method|
|
||||||
response = @http.send_request(method, "/request/header", "test=test", "referer" => referer)
|
response = @http.send_request(method, "/request/header", "test=test", "referer" => referer)
|
||||||
response.body.should include('"referer"=>["' + referer + '"]')
|
response.body.should include('"Referer"=>"' + referer + '"')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,34 +1,37 @@
|
|||||||
require_relative '../spec_helper'
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
require "webrick"
|
# webrick is no longer in stdlib in Ruby 3+
|
||||||
require "stringio"
|
ruby_version_is ""..."3.0" do
|
||||||
require "net/http"
|
require "webrick"
|
||||||
|
require "stringio"
|
||||||
|
require "net/http"
|
||||||
|
|
||||||
describe "WEBrick" do
|
describe "WEBrick" do
|
||||||
describe "resists CVE-2017-17742" do
|
describe "resists CVE-2017-17742" do
|
||||||
it "for a response splitting headers" do
|
it "for a response splitting headers" do
|
||||||
config = WEBrick::Config::HTTP
|
config = WEBrick::Config::HTTP
|
||||||
res = WEBrick::HTTPResponse.new config
|
res = WEBrick::HTTPResponse.new config
|
||||||
res['X-header'] = "malicious\r\nCookie: hack"
|
res['X-header'] = "malicious\r\nCookie: hack"
|
||||||
io = StringIO.new
|
io = StringIO.new
|
||||||
res.send_response io
|
res.send_response io
|
||||||
io.rewind
|
io.rewind
|
||||||
res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io))
|
res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io))
|
||||||
res.code.should == '500'
|
res.code.should == '500'
|
||||||
io.string.should_not =~ /hack/
|
io.string.should_not =~ /hack/
|
||||||
end
|
end
|
||||||
|
|
||||||
it "for a response splitting cookie headers" do
|
it "for a response splitting cookie headers" do
|
||||||
user_input = "malicious\r\nCookie: hack"
|
user_input = "malicious\r\nCookie: hack"
|
||||||
config = WEBrick::Config::HTTP
|
config = WEBrick::Config::HTTP
|
||||||
res = WEBrick::HTTPResponse.new config
|
res = WEBrick::HTTPResponse.new config
|
||||||
res.cookies << WEBrick::Cookie.new('author', user_input)
|
res.cookies << WEBrick::Cookie.new('author', user_input)
|
||||||
io = StringIO.new
|
io = StringIO.new
|
||||||
res.send_response io
|
res.send_response io
|
||||||
io.rewind
|
io.rewind
|
||||||
res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io))
|
res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io))
|
||||||
res.code.should == '500'
|
res.code.should == '500'
|
||||||
io.string.should_not =~ /hack/
|
io.string.should_not =~ /hack/
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user