webrick 1.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of webrick might be problematic. Click here for more details.

Files changed (63) hide show
  1. data/README.txt +21 -0
  2. data/lib/webrick.rb +227 -0
  3. data/lib/webrick/accesslog.rb +151 -0
  4. data/lib/webrick/cgi.rb +260 -0
  5. data/lib/webrick/compat.rb +35 -0
  6. data/lib/webrick/config.rb +121 -0
  7. data/lib/webrick/cookie.rb +110 -0
  8. data/lib/webrick/htmlutils.rb +28 -0
  9. data/lib/webrick/httpauth.rb +95 -0
  10. data/lib/webrick/httpauth/authenticator.rb +112 -0
  11. data/lib/webrick/httpauth/basicauth.rb +108 -0
  12. data/lib/webrick/httpauth/digestauth.rb +392 -0
  13. data/lib/webrick/httpauth/htdigest.rb +128 -0
  14. data/lib/webrick/httpauth/htgroup.rb +93 -0
  15. data/lib/webrick/httpauth/htpasswd.rb +121 -0
  16. data/lib/webrick/httpauth/userdb.rb +52 -0
  17. data/lib/webrick/httpproxy.rb +305 -0
  18. data/lib/webrick/httprequest.rb +461 -0
  19. data/lib/webrick/httpresponse.rb +399 -0
  20. data/lib/webrick/https.rb +64 -0
  21. data/lib/webrick/httpserver.rb +264 -0
  22. data/lib/webrick/httpservlet.rb +22 -0
  23. data/lib/webrick/httpservlet/abstract.rb +153 -0
  24. data/lib/webrick/httpservlet/cgi_runner.rb +46 -0
  25. data/lib/webrick/httpservlet/cgihandler.rb +108 -0
  26. data/lib/webrick/httpservlet/erbhandler.rb +87 -0
  27. data/lib/webrick/httpservlet/filehandler.rb +470 -0
  28. data/lib/webrick/httpservlet/prochandler.rb +33 -0
  29. data/lib/webrick/httpstatus.rb +184 -0
  30. data/lib/webrick/httputils.rb +394 -0
  31. data/lib/webrick/httpversion.rb +49 -0
  32. data/lib/webrick/log.rb +136 -0
  33. data/lib/webrick/server.rb +218 -0
  34. data/lib/webrick/ssl.rb +127 -0
  35. data/lib/webrick/utils.rb +241 -0
  36. data/lib/webrick/version.rb +13 -0
  37. data/sample/webrick/demo-app.rb +66 -0
  38. data/sample/webrick/demo-multipart.cgi +12 -0
  39. data/sample/webrick/demo-servlet.rb +6 -0
  40. data/sample/webrick/demo-urlencoded.cgi +12 -0
  41. data/sample/webrick/hello.cgi +11 -0
  42. data/sample/webrick/hello.rb +8 -0
  43. data/sample/webrick/httpd.rb +23 -0
  44. data/sample/webrick/httpproxy.rb +25 -0
  45. data/sample/webrick/httpsd.rb +33 -0
  46. data/test/openssl/utils.rb +313 -0
  47. data/test/ruby/envutil.rb +208 -0
  48. data/test/webrick/test_cgi.rb +134 -0
  49. data/test/webrick/test_cookie.rb +131 -0
  50. data/test/webrick/test_filehandler.rb +285 -0
  51. data/test/webrick/test_httpauth.rb +167 -0
  52. data/test/webrick/test_httpproxy.rb +282 -0
  53. data/test/webrick/test_httprequest.rb +411 -0
  54. data/test/webrick/test_httpresponse.rb +49 -0
  55. data/test/webrick/test_httpserver.rb +305 -0
  56. data/test/webrick/test_httputils.rb +96 -0
  57. data/test/webrick/test_httpversion.rb +40 -0
  58. data/test/webrick/test_server.rb +67 -0
  59. data/test/webrick/test_utils.rb +64 -0
  60. data/test/webrick/utils.rb +58 -0
  61. data/test/webrick/webrick.cgi +36 -0
  62. data/test/webrick/webrick_long_filename.cgi +36 -0
  63. metadata +106 -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
@@ -0,0 +1,136 @@
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
+
13
+ ##
14
+ # A generic logging class
15
+
16
+ class BasicLog
17
+ # log-level constants
18
+ FATAL, ERROR, WARN, INFO, DEBUG = 1, 2, 3, 4, 5
19
+
20
+ # log-level, messages above this level will be logged
21
+ attr_accessor :level
22
+
23
+ ##
24
+ # Initializes a new logger for +log_file+ that outputs messages at +level+
25
+ # or higher. +log_file+ can be a filename, an IO-like object that
26
+ # responds to #<< or nil which outputs to $stderr.
27
+ #
28
+ # If no level is given INFO is chosen by default
29
+
30
+ def initialize(log_file=nil, level=nil)
31
+ @level = level || INFO
32
+ case log_file
33
+ when String
34
+ @log = open(log_file, "a+")
35
+ @log.sync = true
36
+ @opened = true
37
+ when NilClass
38
+ @log = $stderr
39
+ else
40
+ @log = log_file # requires "<<". (see BasicLog#log)
41
+ end
42
+ end
43
+
44
+ ##
45
+ # Closes the logger (also closes the log device associated to the logger)
46
+ def close
47
+ @log.close if @opened
48
+ @log = nil
49
+ end
50
+
51
+ ##
52
+ # Logs +data+ at +level+ if the given level is above the current log
53
+ # level.
54
+
55
+ def log(level, data)
56
+ if @log && level <= @level
57
+ data += "\n" if /\n\Z/ !~ data
58
+ @log << data
59
+ end
60
+ end
61
+
62
+ ##
63
+ # Synonym for log(INFO, obj.to_s)
64
+ def <<(obj)
65
+ log(INFO, obj.to_s)
66
+ end
67
+
68
+ # Shortcut for logging a FATAL message
69
+ def fatal(msg) log(FATAL, "FATAL " << format(msg)); end
70
+ # Shortcut for logging an ERROR message
71
+ def error(msg) log(ERROR, "ERROR " << format(msg)); end
72
+ # Shortcut for logging a WARN message
73
+ def warn(msg) log(WARN, "WARN " << format(msg)); end
74
+ # Shortcut for logging an INFO message
75
+ def info(msg) log(INFO, "INFO " << format(msg)); end
76
+ # Shortcut for logging a DEBUG message
77
+ def debug(msg) log(DEBUG, "DEBUG " << format(msg)); end
78
+
79
+ # Will the logger output FATAL messages?
80
+ def fatal?; @level >= FATAL; end
81
+ # Will the logger output ERROR messages?
82
+ def error?; @level >= ERROR; end
83
+ # Will the logger output WARN messages?
84
+ def warn?; @level >= WARN; end
85
+ # Will the logger output INFO messages?
86
+ def info?; @level >= INFO; end
87
+ # Will the logger output DEBUG messages?
88
+ def debug?; @level >= DEBUG; end
89
+
90
+ private
91
+
92
+ ##
93
+ # Formats +arg+ for the logger
94
+ #
95
+ # * If +arg+ is an Exception, it will format the error message and
96
+ # the back trace.
97
+ # * If +arg+ responds to #to_str, it will return it.
98
+ # * Otherwise it will return +arg+.inspect.
99
+ def format(arg)
100
+ if arg.is_a?(Exception)
101
+ "#{arg.class}: #{arg.message}\n\t" <<
102
+ arg.backtrace.join("\n\t") << "\n"
103
+ elsif arg.respond_to?(:to_str)
104
+ arg.to_str
105
+ else
106
+ arg.inspect
107
+ end
108
+ end
109
+ end
110
+
111
+ ##
112
+ # A logging class that prepends a timestamp to each message.
113
+
114
+ class Log < BasicLog
115
+ # Format of the timestamp which is applied to each logged line. The
116
+ # default is <tt>"[%Y-%m-%d %H:%M:%S]"</tt>
117
+ attr_accessor :time_format
118
+
119
+ ##
120
+ # Same as BasicLog#initialize
121
+ #
122
+ # You can set the timestamp format through #time_format
123
+ def initialize(log_file=nil, level=nil)
124
+ super(log_file, level)
125
+ @time_format = "[%Y-%m-%d %H:%M:%S]"
126
+ end
127
+
128
+ ##
129
+ # Same as BasicLog#log
130
+ def log(level, data)
131
+ tmp = Time.now.strftime(@time_format)
132
+ tmp << " " << data
133
+ super(level, tmp)
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,218 @@
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 'webrick/config'
14
+ require 'webrick/log'
15
+
16
+ module WEBrick
17
+
18
+ class ServerError < StandardError; end
19
+
20
+ class SimpleServer
21
+ def SimpleServer.start
22
+ yield
23
+ end
24
+ end
25
+
26
+ ##
27
+ # A generic module for daemonizing a process
28
+
29
+ class Daemon
30
+
31
+ ##
32
+ # Performs the standard operations for daemonizing a process. Runs a
33
+ # block, if given.
34
+
35
+ def Daemon.start
36
+ exit!(0) if fork
37
+ Process::setsid
38
+ exit!(0) if fork
39
+ Dir::chdir("/")
40
+ File::umask(0)
41
+ STDIN.reopen("/dev/null")
42
+ STDOUT.reopen("/dev/null", "w")
43
+ STDERR.reopen("/dev/null", "w")
44
+ yield if block_given?
45
+ end
46
+ end
47
+
48
+ class GenericServer
49
+ attr_reader :status, :config, :logger, :tokens, :listeners
50
+
51
+ def initialize(config={}, default=Config::General)
52
+ @config = default.dup.update(config)
53
+ @status = :Stop
54
+ @config[:Logger] ||= Log::new
55
+ @logger = @config[:Logger]
56
+
57
+ @tokens = SizedQueue.new(@config[:MaxClients])
58
+ @config[:MaxClients].times{ @tokens.push(nil) }
59
+
60
+ webrickv = WEBrick::VERSION
61
+ rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
62
+ @logger.info("WEBrick #{webrickv}")
63
+ @logger.info("ruby #{rubyv}")
64
+
65
+ @listeners = []
66
+ unless @config[:DoNotListen]
67
+ if @config[:Listen]
68
+ warn(":Listen option is deprecated; use GenericServer#listen")
69
+ end
70
+ listen(@config[:BindAddress], @config[:Port])
71
+ if @config[:Port] == 0
72
+ @config[:Port] = @listeners[0].addr[1]
73
+ end
74
+ end
75
+ end
76
+
77
+ def [](key)
78
+ @config[key]
79
+ end
80
+
81
+ def listen(address, port)
82
+ @listeners += Utils::create_listeners(address, port, @logger)
83
+ end
84
+
85
+ def start(&block)
86
+ raise ServerError, "already started." if @status != :Stop
87
+ server_type = @config[:ServerType] || SimpleServer
88
+
89
+ server_type.start{
90
+ @logger.info \
91
+ "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
92
+ call_callback(:StartCallback)
93
+
94
+ thgroup = ThreadGroup.new
95
+ @status = :Running
96
+ while @status == :Running
97
+ begin
98
+ if svrs = IO.select(@listeners, nil, nil, 2.0)
99
+ svrs[0].each{|svr|
100
+ @tokens.pop # blocks while no token is there.
101
+ if sock = accept_client(svr)
102
+ sock.do_not_reverse_lookup = config[:DoNotReverseLookup]
103
+ th = start_thread(sock, &block)
104
+ th[:WEBrickThread] = true
105
+ thgroup.add(th)
106
+ else
107
+ @tokens.push(nil)
108
+ end
109
+ }
110
+ end
111
+ rescue Errno::EBADF, IOError => ex
112
+ # if the listening socket was closed in GenericServer#shutdown,
113
+ # IO::select raise it.
114
+ rescue Exception => ex
115
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
116
+ @logger.error msg
117
+ end
118
+ end
119
+
120
+ @logger.info "going to shutdown ..."
121
+ thgroup.list.each{|th| th.join if th[:WEBrickThread] }
122
+ call_callback(:StopCallback)
123
+ @logger.info "#{self.class}#start done."
124
+ @status = :Stop
125
+ }
126
+ end
127
+
128
+ def stop
129
+ if @status == :Running
130
+ @status = :Shutdown
131
+ end
132
+ end
133
+
134
+ def shutdown
135
+ stop
136
+ @listeners.each{|s|
137
+ if @logger.debug?
138
+ addr = s.addr
139
+ @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
140
+ end
141
+ begin
142
+ s.shutdown
143
+ rescue Errno::ENOTCONN
144
+ # when `Errno::ENOTCONN: Socket is not connected' on some platforms,
145
+ # call #close instead of #shutdown.
146
+ # (ignore @config[:ShutdownSocketWithoutClose])
147
+ s.close
148
+ else
149
+ unless @config[:ShutdownSocketWithoutClose]
150
+ s.close
151
+ end
152
+ end
153
+ }
154
+ @listeners.clear
155
+ end
156
+
157
+ def run(sock)
158
+ @logger.fatal "run() must be provided by user."
159
+ end
160
+
161
+ private
162
+
163
+ def accept_client(svr)
164
+ sock = nil
165
+ begin
166
+ sock = svr.accept
167
+ sock.sync = true
168
+ Utils::set_non_blocking(sock)
169
+ Utils::set_close_on_exec(sock)
170
+ rescue Errno::ECONNRESET, Errno::ECONNABORTED,
171
+ Errno::EPROTO, Errno::EINVAL => ex
172
+ rescue Exception => ex
173
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
174
+ @logger.error msg
175
+ end
176
+ return sock
177
+ end
178
+
179
+ def start_thread(sock, &block)
180
+ Thread.start{
181
+ begin
182
+ Thread.current[:WEBrickSocket] = sock
183
+ begin
184
+ addr = sock.peeraddr
185
+ @logger.debug "accept: #{addr[3]}:#{addr[1]}"
186
+ rescue SocketError
187
+ @logger.debug "accept: <address unknown>"
188
+ raise
189
+ end
190
+ call_callback(:AcceptCallback, sock)
191
+ block ? block.call(sock) : run(sock)
192
+ rescue Errno::ENOTCONN
193
+ @logger.debug "Errno::ENOTCONN raised"
194
+ rescue ServerError => ex
195
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
196
+ @logger.error msg
197
+ rescue Exception => ex
198
+ @logger.error ex
199
+ ensure
200
+ @tokens.push(nil)
201
+ Thread.current[:WEBrickSocket] = nil
202
+ if addr
203
+ @logger.debug "close: #{addr[3]}:#{addr[1]}"
204
+ else
205
+ @logger.debug "close: <address unknown>"
206
+ end
207
+ sock.close
208
+ end
209
+ }
210
+ end
211
+
212
+ def call_callback(callback_name, *args)
213
+ if cb = @config[callback_name]
214
+ cb.call(*args)
215
+ end
216
+ end
217
+ end # end of GenericServer
218
+ end
@@ -0,0 +1,127 @@
1
+ #
2
+ # ssl.rb -- SSL/TLS enhancement for GenericServer
3
+ #
4
+ # Copyright (c) 2003 GOTOU Yuuzou All rights reserved.
5
+ #
6
+ # $Id$
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 = 2
54
+ cert.serial = 1
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
+ undef listen
87
+ def listen(address, port)
88
+ listeners = Utils::create_listeners(address, port, @logger)
89
+ if @config[:SSLEnable]
90
+ unless ssl_context
91
+ @ssl_context = setup_ssl_context(@config)
92
+ @logger.info("\n" + @config[:SSLCertificate].to_text)
93
+ end
94
+ listeners.collect!{|svr|
95
+ ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
96
+ ssvr.start_immediately = @config[:SSLStartImmediately]
97
+ ssvr
98
+ }
99
+ end
100
+ @listeners += listeners
101
+ end
102
+
103
+ def setup_ssl_context(config)
104
+ unless config[:SSLCertificate]
105
+ cn = config[:SSLCertName]
106
+ comment = config[:SSLCertComment]
107
+ cert, key = Utils::create_self_signed_cert(1024, cn, comment)
108
+ config[:SSLCertificate] = cert
109
+ config[:SSLPrivateKey] = key
110
+ end
111
+ ctx = OpenSSL::SSL::SSLContext.new
112
+ ctx.key = config[:SSLPrivateKey]
113
+ ctx.cert = config[:SSLCertificate]
114
+ ctx.client_ca = config[:SSLClientCA]
115
+ ctx.extra_chain_cert = config[:SSLExtraChainCert]
116
+ ctx.ca_file = config[:SSLCACertificateFile]
117
+ ctx.ca_path = config[:SSLCACertificatePath]
118
+ ctx.cert_store = config[:SSLCertificateStore]
119
+ ctx.verify_mode = config[:SSLVerifyClient]
120
+ ctx.verify_depth = config[:SSLVerifyDepth]
121
+ ctx.verify_callback = config[:SSLVerifyCallback]
122
+ ctx.timeout = config[:SSLTimeout]
123
+ ctx.options = config[:SSLOptions]
124
+ ctx
125
+ end
126
+ end
127
+ end