rubysl-webrick 1.0.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 +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/rubysl/webrick.rb +2 -0
- data/lib/rubysl/webrick/version.rb +5 -0
- data/lib/rubysl/webrick/webrick.rb +29 -0
- data/lib/webrick.rb +1 -0
- data/lib/webrick/accesslog.rb +67 -0
- data/lib/webrick/cgi.rb +257 -0
- data/lib/webrick/compat.rb +15 -0
- data/lib/webrick/config.rb +97 -0
- data/lib/webrick/cookie.rb +110 -0
- data/lib/webrick/htmlutils.rb +25 -0
- data/lib/webrick/httpauth.rb +45 -0
- data/lib/webrick/httpauth/authenticator.rb +79 -0
- data/lib/webrick/httpauth/basicauth.rb +65 -0
- data/lib/webrick/httpauth/digestauth.rb +343 -0
- data/lib/webrick/httpauth/htdigest.rb +91 -0
- data/lib/webrick/httpauth/htgroup.rb +61 -0
- data/lib/webrick/httpauth/htpasswd.rb +83 -0
- data/lib/webrick/httpauth/userdb.rb +29 -0
- data/lib/webrick/httpproxy.rb +254 -0
- data/lib/webrick/httprequest.rb +365 -0
- data/lib/webrick/httpresponse.rb +327 -0
- data/lib/webrick/https.rb +63 -0
- data/lib/webrick/httpserver.rb +210 -0
- data/lib/webrick/httpservlet.rb +22 -0
- data/lib/webrick/httpservlet/abstract.rb +71 -0
- data/lib/webrick/httpservlet/cgi_runner.rb +45 -0
- data/lib/webrick/httpservlet/cgihandler.rb +104 -0
- data/lib/webrick/httpservlet/erbhandler.rb +54 -0
- data/lib/webrick/httpservlet/filehandler.rb +398 -0
- data/lib/webrick/httpservlet/prochandler.rb +33 -0
- data/lib/webrick/httpstatus.rb +126 -0
- data/lib/webrick/httputils.rb +391 -0
- data/lib/webrick/httpversion.rb +49 -0
- data/lib/webrick/log.rb +88 -0
- data/lib/webrick/server.rb +200 -0
- data/lib/webrick/ssl.rb +126 -0
- data/lib/webrick/utils.rb +100 -0
- data/lib/webrick/version.rb +13 -0
- data/rubysl-webrick.gemspec +23 -0
- metadata +145 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
#
|
2
|
+
# HTTPVersion.rb -- presentation of HTTP version
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
6
|
+
# reserved.
|
7
|
+
#
|
8
|
+
# $IPR: httpversion.rb,v 1.5 2002/09/21 12:23:37 gotoyuzo Exp $
|
9
|
+
|
10
|
+
module WEBrick
|
11
|
+
class HTTPVersion
|
12
|
+
include Comparable
|
13
|
+
|
14
|
+
attr_accessor :major, :minor
|
15
|
+
|
16
|
+
def self.convert(version)
|
17
|
+
version.is_a?(self) ? version : new(version)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(version)
|
21
|
+
case version
|
22
|
+
when HTTPVersion
|
23
|
+
@major, @minor = version.major, version.minor
|
24
|
+
when String
|
25
|
+
if /^(\d+)\.(\d+)$/ =~ version
|
26
|
+
@major, @minor = $1.to_i, $2.to_i
|
27
|
+
end
|
28
|
+
end
|
29
|
+
if @major.nil? || @minor.nil?
|
30
|
+
raise ArgumentError,
|
31
|
+
format("cannot convert %s into %s", version.class, self.class)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def <=>(other)
|
36
|
+
unless other.is_a?(self.class)
|
37
|
+
other = self.class.new(other)
|
38
|
+
end
|
39
|
+
if (ret = @major <=> other.major) == 0
|
40
|
+
return @minor <=> other.minor
|
41
|
+
end
|
42
|
+
return ret
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
format("%d.%d", @major, @minor)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/webrick/log.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
#
|
2
|
+
# log.rb -- Log Class
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
|
6
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
7
|
+
# reserved.
|
8
|
+
#
|
9
|
+
# $IPR: log.rb,v 1.26 2002/10/06 17:06:10 gotoyuzo Exp $
|
10
|
+
|
11
|
+
module WEBrick
|
12
|
+
class BasicLog
|
13
|
+
# log-level constant
|
14
|
+
FATAL, ERROR, WARN, INFO, DEBUG = 1, 2, 3, 4, 5
|
15
|
+
|
16
|
+
attr_accessor :level
|
17
|
+
|
18
|
+
def initialize(log_file=nil, level=nil)
|
19
|
+
@level = level || INFO
|
20
|
+
case log_file
|
21
|
+
when String
|
22
|
+
@log = open(log_file, "a+")
|
23
|
+
@log.sync = true
|
24
|
+
@opened = true
|
25
|
+
when NilClass
|
26
|
+
@log = $stderr
|
27
|
+
else
|
28
|
+
@log = log_file # requires "<<". (see BasicLog#log)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def close
|
33
|
+
@log.close if @opened
|
34
|
+
@log = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def log(level, data)
|
38
|
+
if @log && level <= @level
|
39
|
+
data += "\n" if /\n\Z/ !~ data
|
40
|
+
@log << data
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def <<(obj)
|
45
|
+
log(INFO, obj.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
def fatal(msg) log(FATAL, "FATAL " << format(msg)); end
|
49
|
+
def error(msg) log(ERROR, "ERROR " << format(msg)); end
|
50
|
+
def warn(msg) log(WARN, "WARN " << format(msg)); end
|
51
|
+
def info(msg) log(INFO, "INFO " << format(msg)); end
|
52
|
+
def debug(msg) log(DEBUG, "DEBUG " << format(msg)); end
|
53
|
+
|
54
|
+
def fatal?; @level >= FATAL; end
|
55
|
+
def error?; @level >= ERROR; end
|
56
|
+
def warn?; @level >= WARN; end
|
57
|
+
def info?; @level >= INFO; end
|
58
|
+
def debug?; @level >= DEBUG; end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def format(arg)
|
63
|
+
str = if arg.is_a?(Exception)
|
64
|
+
"#{arg.class}: #{arg.message}\n\t" <<
|
65
|
+
arg.backtrace.join("\n\t") << "\n"
|
66
|
+
elsif arg.respond_to?(:to_str)
|
67
|
+
arg.to_str
|
68
|
+
else
|
69
|
+
arg.inspect
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Log < BasicLog
|
75
|
+
attr_accessor :time_format
|
76
|
+
|
77
|
+
def initialize(log_file=nil, level=nil)
|
78
|
+
super(log_file, level)
|
79
|
+
@time_format = "[%Y-%m-%d %H:%M:%S]"
|
80
|
+
end
|
81
|
+
|
82
|
+
def log(level, data)
|
83
|
+
tmp = Time.now.strftime(@time_format)
|
84
|
+
tmp << " " << data
|
85
|
+
super(level, tmp)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
#
|
2
|
+
# server.rb -- GenericServer Class
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
|
6
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
7
|
+
# reserved.
|
8
|
+
#
|
9
|
+
# $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $
|
10
|
+
|
11
|
+
require 'thread'
|
12
|
+
require 'socket'
|
13
|
+
require 'timeout'
|
14
|
+
require 'webrick/config'
|
15
|
+
require 'webrick/log'
|
16
|
+
|
17
|
+
module WEBrick
|
18
|
+
|
19
|
+
class ServerError < StandardError; end
|
20
|
+
|
21
|
+
class SimpleServer
|
22
|
+
def SimpleServer.start
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Daemon
|
28
|
+
def Daemon.start
|
29
|
+
exit!(0) if fork
|
30
|
+
Process::setsid
|
31
|
+
exit!(0) if fork
|
32
|
+
Dir::chdir("/")
|
33
|
+
File::umask(0)
|
34
|
+
STDIN.reopen("/dev/null")
|
35
|
+
STDOUT.reopen("/dev/null", "w")
|
36
|
+
STDERR.reopen("/dev/null", "w")
|
37
|
+
yield if block_given?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class GenericServer
|
42
|
+
attr_reader :status, :config, :logger, :tokens, :listeners
|
43
|
+
|
44
|
+
def initialize(config={}, default=Config::General)
|
45
|
+
@config = default.dup.update(config)
|
46
|
+
@status = :Stop
|
47
|
+
@config[:Logger] ||= Log::new
|
48
|
+
@logger = @config[:Logger]
|
49
|
+
|
50
|
+
@tokens = SizedQueue.new(@config[:MaxClients])
|
51
|
+
@config[:MaxClients].times{ @tokens.push(nil) }
|
52
|
+
|
53
|
+
webrickv = WEBrick::VERSION
|
54
|
+
rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
55
|
+
@logger.info("WEBrick #{webrickv}")
|
56
|
+
@logger.info("ruby #{rubyv}")
|
57
|
+
|
58
|
+
@listeners = []
|
59
|
+
unless @config[:DoNotListen]
|
60
|
+
if @config[:Listen]
|
61
|
+
warn(":Listen option is deprecated; use GenericServer#listen")
|
62
|
+
end
|
63
|
+
listen(@config[:BindAddress], @config[:Port])
|
64
|
+
if @config[:Port] == 0
|
65
|
+
@config[:Port] = @listeners[0].addr[1]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def [](key)
|
71
|
+
@config[key]
|
72
|
+
end
|
73
|
+
|
74
|
+
def listen(address, port)
|
75
|
+
@listeners += Utils::create_listeners(address, port, @logger)
|
76
|
+
end
|
77
|
+
|
78
|
+
def start(&block)
|
79
|
+
raise ServerError, "already started." if @status != :Stop
|
80
|
+
server_type = @config[:ServerType] || SimpleServer
|
81
|
+
|
82
|
+
server_type.start{
|
83
|
+
@logger.info \
|
84
|
+
"#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
|
85
|
+
call_callback(:StartCallback)
|
86
|
+
|
87
|
+
thgroup = ThreadGroup.new
|
88
|
+
@status = :Running
|
89
|
+
while @status == :Running
|
90
|
+
begin
|
91
|
+
if svrs = IO.select(@listeners, nil, nil, 2.0)
|
92
|
+
svrs[0].each{|svr|
|
93
|
+
@tokens.pop # blocks while no token is there.
|
94
|
+
if sock = accept_client(svr)
|
95
|
+
th = start_thread(sock, &block)
|
96
|
+
th[:WEBrickThread] = true
|
97
|
+
thgroup.add(th)
|
98
|
+
else
|
99
|
+
@tokens.push(nil)
|
100
|
+
end
|
101
|
+
}
|
102
|
+
end
|
103
|
+
rescue Errno::EBADF, IOError => ex
|
104
|
+
# if the listening socket was closed in GenericServer#shutdown,
|
105
|
+
# IO::select raise it.
|
106
|
+
rescue Exception => ex
|
107
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
108
|
+
@logger.error msg
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
@logger.info "going to shutdown ..."
|
113
|
+
thgroup.list.each{|th| th.join if th[:WEBrickThread] }
|
114
|
+
call_callback(:StopCallback)
|
115
|
+
@logger.info "#{self.class}#start done."
|
116
|
+
@status = :Stop
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
def stop
|
121
|
+
if @status == :Running
|
122
|
+
@status = :Shutdown
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def shutdown
|
127
|
+
stop
|
128
|
+
@listeners.each{|s|
|
129
|
+
if @logger.debug?
|
130
|
+
addr = s.addr
|
131
|
+
@logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
|
132
|
+
end
|
133
|
+
s.close
|
134
|
+
}
|
135
|
+
@listeners.clear
|
136
|
+
end
|
137
|
+
|
138
|
+
def run(sock)
|
139
|
+
@logger.fatal "run() must be provided by user."
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def accept_client(svr)
|
145
|
+
sock = nil
|
146
|
+
begin
|
147
|
+
sock = svr.accept
|
148
|
+
sock.sync = true
|
149
|
+
Utils::set_non_blocking(sock)
|
150
|
+
Utils::set_close_on_exec(sock)
|
151
|
+
rescue Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPROTO => ex
|
152
|
+
# TCP connection was established but RST segment was sent
|
153
|
+
# from peer before calling TCPServer#accept.
|
154
|
+
rescue Exception => ex
|
155
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
156
|
+
@logger.error msg
|
157
|
+
end
|
158
|
+
return sock
|
159
|
+
end
|
160
|
+
|
161
|
+
def start_thread(sock, &block)
|
162
|
+
Thread.start{
|
163
|
+
begin
|
164
|
+
Thread.current[:WEBrickSocket] = sock
|
165
|
+
begin
|
166
|
+
addr = sock.peeraddr
|
167
|
+
@logger.debug "accept: #{addr[3]}:#{addr[1]}"
|
168
|
+
rescue SocketError
|
169
|
+
@logger.debug "accept: <address unknown>"
|
170
|
+
raise
|
171
|
+
end
|
172
|
+
call_callback(:AcceptCallback, sock)
|
173
|
+
block ? block.call(sock) : run(sock)
|
174
|
+
rescue Errno::ENOTCONN
|
175
|
+
@logger.debug "Errno::ENOTCONN raised"
|
176
|
+
rescue ServerError => ex
|
177
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
178
|
+
@logger.error msg
|
179
|
+
rescue Exception => ex
|
180
|
+
@logger.error ex
|
181
|
+
ensure
|
182
|
+
@tokens.push(nil)
|
183
|
+
Thread.current[:WEBrickSocket] = nil
|
184
|
+
if addr
|
185
|
+
@logger.debug "close: #{addr[3]}:#{addr[1]}"
|
186
|
+
else
|
187
|
+
@logger.debug "close: <address unknown>"
|
188
|
+
end
|
189
|
+
sock.close
|
190
|
+
end
|
191
|
+
}
|
192
|
+
end
|
193
|
+
|
194
|
+
def call_callback(callback_name, *args)
|
195
|
+
if cb = @config[callback_name]
|
196
|
+
cb.call(*args)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end # end of GenericServer
|
200
|
+
end
|
data/lib/webrick/ssl.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
#
|
2
|
+
# ssl.rb -- SSL/TLS enhancement for GenericServer
|
3
|
+
#
|
4
|
+
# Copyright (c) 2003 GOTOU Yuuzou All rights reserved.
|
5
|
+
#
|
6
|
+
# $Id: ssl.rb 11708 2007-02-12 23:01:19Z shyouhei $
|
7
|
+
|
8
|
+
require 'webrick'
|
9
|
+
require 'openssl'
|
10
|
+
|
11
|
+
module WEBrick
|
12
|
+
module Config
|
13
|
+
svrsoft = General[:ServerSoftware]
|
14
|
+
osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
|
15
|
+
SSL = {
|
16
|
+
:ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}",
|
17
|
+
:SSLEnable => false,
|
18
|
+
:SSLCertificate => nil,
|
19
|
+
:SSLPrivateKey => nil,
|
20
|
+
:SSLClientCA => nil,
|
21
|
+
:SSLExtraChainCert => nil,
|
22
|
+
:SSLCACertificateFile => nil,
|
23
|
+
:SSLCACertificatePath => nil,
|
24
|
+
:SSLCertificateStore => nil,
|
25
|
+
:SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
|
26
|
+
:SSLVerifyDepth => nil,
|
27
|
+
:SSLVerifyCallback => nil, # custom verification
|
28
|
+
:SSLTimeout => nil,
|
29
|
+
:SSLOptions => nil,
|
30
|
+
:SSLStartImmediately => true,
|
31
|
+
# Must specify if you use auto generated certificate.
|
32
|
+
:SSLCertName => nil,
|
33
|
+
:SSLCertComment => "Generated by Ruby/OpenSSL"
|
34
|
+
}
|
35
|
+
General.update(SSL)
|
36
|
+
end
|
37
|
+
|
38
|
+
module Utils
|
39
|
+
def create_self_signed_cert(bits, cn, comment)
|
40
|
+
rsa = OpenSSL::PKey::RSA.new(bits){|p, n|
|
41
|
+
case p
|
42
|
+
when 0; $stderr.putc "." # BN_generate_prime
|
43
|
+
when 1; $stderr.putc "+" # BN_generate_prime
|
44
|
+
when 2; $stderr.putc "*" # searching good prime,
|
45
|
+
# n = #of try,
|
46
|
+
# but also data from BN_generate_prime
|
47
|
+
when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
|
48
|
+
# but also data from BN_generate_prime
|
49
|
+
else; $stderr.putc "*" # BN_generate_prime
|
50
|
+
end
|
51
|
+
}
|
52
|
+
cert = OpenSSL::X509::Certificate.new
|
53
|
+
cert.version = 3
|
54
|
+
cert.serial = 0
|
55
|
+
name = OpenSSL::X509::Name.new(cn)
|
56
|
+
cert.subject = name
|
57
|
+
cert.issuer = name
|
58
|
+
cert.not_before = Time.now
|
59
|
+
cert.not_after = Time.now + (365*24*60*60)
|
60
|
+
cert.public_key = rsa.public_key
|
61
|
+
|
62
|
+
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
63
|
+
ef.issuer_certificate = cert
|
64
|
+
cert.extensions = [
|
65
|
+
ef.create_extension("basicConstraints","CA:FALSE"),
|
66
|
+
ef.create_extension("keyUsage", "keyEncipherment"),
|
67
|
+
ef.create_extension("subjectKeyIdentifier", "hash"),
|
68
|
+
ef.create_extension("extendedKeyUsage", "serverAuth"),
|
69
|
+
ef.create_extension("nsComment", comment),
|
70
|
+
]
|
71
|
+
aki = ef.create_extension("authorityKeyIdentifier",
|
72
|
+
"keyid:always,issuer:always")
|
73
|
+
cert.add_extension(aki)
|
74
|
+
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
75
|
+
|
76
|
+
return [ cert, rsa ]
|
77
|
+
end
|
78
|
+
module_function :create_self_signed_cert
|
79
|
+
end
|
80
|
+
|
81
|
+
class GenericServer
|
82
|
+
def ssl_context
|
83
|
+
@ssl_context ||= nil
|
84
|
+
end
|
85
|
+
|
86
|
+
def listen(address, port)
|
87
|
+
listeners = Utils::create_listeners(address, port, @logger)
|
88
|
+
if @config[:SSLEnable]
|
89
|
+
unless ssl_context
|
90
|
+
@ssl_context = setup_ssl_context(@config)
|
91
|
+
@logger.info("\n" + @config[:SSLCertificate].to_text)
|
92
|
+
end
|
93
|
+
listeners.collect!{|svr|
|
94
|
+
ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
|
95
|
+
ssvr.start_immediately = @config[:SSLStartImmediately]
|
96
|
+
ssvr
|
97
|
+
}
|
98
|
+
end
|
99
|
+
@listeners += listeners
|
100
|
+
end
|
101
|
+
|
102
|
+
def setup_ssl_context(config)
|
103
|
+
unless config[:SSLCertificate]
|
104
|
+
cn = config[:SSLCertName]
|
105
|
+
comment = config[:SSLCertComment]
|
106
|
+
cert, key = Utils::create_self_signed_cert(1024, cn, comment)
|
107
|
+
config[:SSLCertificate] = cert
|
108
|
+
config[:SSLPrivateKey] = key
|
109
|
+
end
|
110
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
111
|
+
ctx.key = config[:SSLPrivateKey]
|
112
|
+
ctx.cert = config[:SSLCertificate]
|
113
|
+
ctx.client_ca = config[:SSLClientCA]
|
114
|
+
ctx.extra_chain_cert = config[:SSLExtraChainCert]
|
115
|
+
ctx.ca_file = config[:SSLCACertificateFile]
|
116
|
+
ctx.ca_path = config[:SSLCACertificatePath]
|
117
|
+
ctx.cert_store = config[:SSLCertificateStore]
|
118
|
+
ctx.verify_mode = config[:SSLVerifyClient]
|
119
|
+
ctx.verify_depth = config[:SSLVerifyDepth]
|
120
|
+
ctx.verify_callback = config[:SSLVerifyCallback]
|
121
|
+
ctx.timeout = config[:SSLTimeout]
|
122
|
+
ctx.options = config[:SSLOptions]
|
123
|
+
ctx
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|