webrick 1.3.1 → 1.4.0.beta1
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.
- checksums.yaml +7 -0
- data/lib/webrick.rb +6 -6
- data/lib/webrick/accesslog.rb +9 -1
- data/lib/webrick/cgi.rb +51 -2
- data/lib/webrick/compat.rb +2 -1
- data/lib/webrick/config.rb +42 -5
- data/lib/webrick/cookie.rb +68 -6
- data/lib/webrick/htmlutils.rb +4 -2
- data/lib/webrick/httpauth.rb +1 -0
- data/lib/webrick/httpauth/authenticator.rb +13 -8
- data/lib/webrick/httpauth/basicauth.rb +3 -3
- data/lib/webrick/httpauth/digestauth.rb +25 -9
- data/lib/webrick/httpauth/htdigest.rb +8 -4
- data/lib/webrick/httpauth/htgroup.rb +1 -0
- data/lib/webrick/httpauth/htpasswd.rb +7 -3
- data/lib/webrick/httpauth/userdb.rb +1 -0
- data/lib/webrick/httpproxy.rb +47 -14
- data/lib/webrick/httprequest.rb +142 -16
- data/lib/webrick/httpresponse.rb +96 -24
- data/lib/webrick/https.rb +24 -1
- data/lib/webrick/httpserver.rb +20 -4
- data/lib/webrick/httpservlet.rb +1 -0
- data/lib/webrick/httpservlet/abstract.rb +2 -1
- data/lib/webrick/httpservlet/cgi_runner.rb +1 -0
- data/lib/webrick/httpservlet/cgihandler.rb +19 -5
- data/lib/webrick/httpservlet/erbhandler.rb +2 -1
- data/lib/webrick/httpservlet/filehandler.rb +87 -34
- data/lib/webrick/httpservlet/prochandler.rb +14 -0
- data/lib/webrick/httpstatus.rb +24 -10
- data/lib/webrick/httputils.rb +129 -13
- data/lib/webrick/httpversion.rb +28 -1
- data/lib/webrick/log.rb +22 -2
- data/lib/webrick/server.rb +203 -60
- data/lib/webrick/ssl.rb +80 -5
- data/lib/webrick/utils.rb +97 -67
- data/lib/webrick/version.rb +6 -1
- metadata +59 -69
- data/README.txt +0 -21
- data/sample/webrick/demo-app.rb +0 -66
- data/sample/webrick/demo-multipart.cgi +0 -12
- data/sample/webrick/demo-servlet.rb +0 -6
- data/sample/webrick/demo-urlencoded.cgi +0 -12
- data/sample/webrick/hello.cgi +0 -11
- data/sample/webrick/hello.rb +0 -8
- data/sample/webrick/httpd.rb +0 -23
- data/sample/webrick/httpproxy.rb +0 -25
- data/sample/webrick/httpsd.rb +0 -33
- data/test/openssl/utils.rb +0 -313
- data/test/ruby/envutil.rb +0 -208
- data/test/webrick/test_cgi.rb +0 -134
- data/test/webrick/test_cookie.rb +0 -131
- data/test/webrick/test_filehandler.rb +0 -285
- data/test/webrick/test_httpauth.rb +0 -167
- data/test/webrick/test_httpproxy.rb +0 -282
- data/test/webrick/test_httprequest.rb +0 -411
- data/test/webrick/test_httpresponse.rb +0 -49
- data/test/webrick/test_httpserver.rb +0 -305
- data/test/webrick/test_httputils.rb +0 -96
- data/test/webrick/test_httpversion.rb +0 -40
- data/test/webrick/test_server.rb +0 -67
- data/test/webrick/test_utils.rb +0 -64
- data/test/webrick/utils.rb +0 -58
- data/test/webrick/webrick.cgi +0 -36
- data/test/webrick/webrick_long_filename.cgi +0 -36
data/lib/webrick/httpversion.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: false
|
1
2
|
#--
|
2
3
|
# HTTPVersion.rb -- presentation of HTTP version
|
3
4
|
#
|
@@ -8,15 +9,33 @@
|
|
8
9
|
# $IPR: httpversion.rb,v 1.5 2002/09/21 12:23:37 gotoyuzo Exp $
|
9
10
|
|
10
11
|
module WEBrick
|
12
|
+
|
13
|
+
##
|
14
|
+
# Represents an HTTP protocol version
|
15
|
+
|
11
16
|
class HTTPVersion
|
12
17
|
include Comparable
|
13
18
|
|
14
|
-
|
19
|
+
##
|
20
|
+
# The major protocol version number
|
21
|
+
|
22
|
+
attr_accessor :major
|
23
|
+
|
24
|
+
##
|
25
|
+
# The minor protocol version number
|
26
|
+
|
27
|
+
attr_accessor :minor
|
28
|
+
|
29
|
+
##
|
30
|
+
# Converts +version+ into an HTTPVersion
|
15
31
|
|
16
32
|
def self.convert(version)
|
17
33
|
version.is_a?(self) ? version : new(version)
|
18
34
|
end
|
19
35
|
|
36
|
+
##
|
37
|
+
# Creates a new HTTPVersion from +version+.
|
38
|
+
|
20
39
|
def initialize(version)
|
21
40
|
case version
|
22
41
|
when HTTPVersion
|
@@ -32,6 +51,10 @@ module WEBrick
|
|
32
51
|
end
|
33
52
|
end
|
34
53
|
|
54
|
+
##
|
55
|
+
# Compares this version with +other+ according to the HTTP specification
|
56
|
+
# rules.
|
57
|
+
|
35
58
|
def <=>(other)
|
36
59
|
unless other.is_a?(self.class)
|
37
60
|
other = self.class.new(other)
|
@@ -42,6 +65,10 @@ module WEBrick
|
|
42
65
|
return ret
|
43
66
|
end
|
44
67
|
|
68
|
+
##
|
69
|
+
# The HTTP version as show in the HTTP request and response. For example,
|
70
|
+
# "1.1"
|
71
|
+
|
45
72
|
def to_s
|
46
73
|
format("%d.%d", @major, @minor)
|
47
74
|
end
|
data/lib/webrick/log.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: false
|
1
2
|
#--
|
2
3
|
# log.rb -- Log Class
|
3
4
|
#
|
@@ -14,8 +15,27 @@ module WEBrick
|
|
14
15
|
# A generic logging class
|
15
16
|
|
16
17
|
class BasicLog
|
17
|
-
|
18
|
-
|
18
|
+
|
19
|
+
# Fatal log level which indicates a server crash
|
20
|
+
|
21
|
+
FATAL = 1
|
22
|
+
|
23
|
+
# Error log level which indicates a recoverable error
|
24
|
+
|
25
|
+
ERROR = 2
|
26
|
+
|
27
|
+
# Warning log level which indicates a possible problem
|
28
|
+
|
29
|
+
WARN = 3
|
30
|
+
|
31
|
+
# Information log level which indicates possibly useful information
|
32
|
+
|
33
|
+
INFO = 4
|
34
|
+
|
35
|
+
# Debugging error level for messages used in server development or
|
36
|
+
# debugging
|
37
|
+
|
38
|
+
DEBUG = 5
|
19
39
|
|
20
40
|
# log-level, messages above this level will be logged
|
21
41
|
attr_accessor :level
|
data/lib/webrick/server.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: false
|
1
2
|
#
|
2
3
|
# server.rb -- GenericServer Class
|
3
4
|
#
|
@@ -15,9 +16,19 @@ require 'webrick/log'
|
|
15
16
|
|
16
17
|
module WEBrick
|
17
18
|
|
19
|
+
##
|
20
|
+
# Server error exception
|
21
|
+
|
18
22
|
class ServerError < StandardError; end
|
19
23
|
|
24
|
+
##
|
25
|
+
# Base server class
|
26
|
+
|
20
27
|
class SimpleServer
|
28
|
+
|
29
|
+
##
|
30
|
+
# A SimpleServer only yields when you start it
|
31
|
+
|
21
32
|
def SimpleServer.start
|
22
33
|
yield
|
23
34
|
end
|
@@ -33,20 +44,47 @@ module WEBrick
|
|
33
44
|
# block, if given.
|
34
45
|
|
35
46
|
def Daemon.start
|
36
|
-
|
37
|
-
|
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")
|
47
|
+
Process.daemon
|
48
|
+
File.umask(0)
|
44
49
|
yield if block_given?
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
53
|
+
##
|
54
|
+
# Base TCP server class. You must subclass GenericServer and provide a #run
|
55
|
+
# method.
|
56
|
+
|
48
57
|
class GenericServer
|
49
|
-
|
58
|
+
|
59
|
+
##
|
60
|
+
# The server status. One of :Stop, :Running or :Shutdown
|
61
|
+
|
62
|
+
attr_reader :status
|
63
|
+
|
64
|
+
##
|
65
|
+
# The server configuration
|
66
|
+
|
67
|
+
attr_reader :config
|
68
|
+
|
69
|
+
##
|
70
|
+
# The server logger. This is independent from the HTTP access log.
|
71
|
+
|
72
|
+
attr_reader :logger
|
73
|
+
|
74
|
+
##
|
75
|
+
# Tokens control the number of outstanding clients. The
|
76
|
+
# <code>:MaxClients</code> configuration sets this.
|
77
|
+
|
78
|
+
attr_reader :tokens
|
79
|
+
|
80
|
+
##
|
81
|
+
# Sockets listening for connections.
|
82
|
+
|
83
|
+
attr_reader :listeners
|
84
|
+
|
85
|
+
##
|
86
|
+
# Creates a new generic server from +config+. The default configuration
|
87
|
+
# comes from +default+.
|
50
88
|
|
51
89
|
def initialize(config={}, default=Config::General)
|
52
90
|
@config = default.dup.update(config)
|
@@ -54,7 +92,7 @@ module WEBrick
|
|
54
92
|
@config[:Logger] ||= Log::new
|
55
93
|
@logger = @config[:Logger]
|
56
94
|
|
57
|
-
@tokens = SizedQueue.new(@config[:MaxClients])
|
95
|
+
@tokens = Thread::SizedQueue.new(@config[:MaxClients])
|
58
96
|
@config[:MaxClients].times{ @tokens.push(nil) }
|
59
97
|
|
60
98
|
webrickv = WEBrick::VERSION
|
@@ -63,6 +101,7 @@ module WEBrick
|
|
63
101
|
@logger.info("ruby #{rubyv}")
|
64
102
|
|
65
103
|
@listeners = []
|
104
|
+
@shutdown_pipe = nil
|
66
105
|
unless @config[:DoNotListen]
|
67
106
|
if @config[:Listen]
|
68
107
|
warn(":Listen option is deprecated; use GenericServer#listen")
|
@@ -74,108 +113,168 @@ module WEBrick
|
|
74
113
|
end
|
75
114
|
end
|
76
115
|
|
116
|
+
##
|
117
|
+
# Retrieves +key+ from the configuration
|
118
|
+
|
77
119
|
def [](key)
|
78
120
|
@config[key]
|
79
121
|
end
|
80
122
|
|
123
|
+
##
|
124
|
+
# Adds listeners from +address+ and +port+ to the server. See
|
125
|
+
# WEBrick::Utils::create_listeners for details.
|
126
|
+
|
81
127
|
def listen(address, port)
|
82
|
-
@listeners += Utils::create_listeners(address, port
|
128
|
+
@listeners += Utils::create_listeners(address, port)
|
83
129
|
end
|
84
130
|
|
131
|
+
##
|
132
|
+
# Starts the server and runs the +block+ for each connection. This method
|
133
|
+
# does not return until the server is stopped from a signal handler or
|
134
|
+
# another thread using #stop or #shutdown.
|
135
|
+
#
|
136
|
+
# If the block raises a subclass of StandardError the exception is logged
|
137
|
+
# and ignored. If an IOError or Errno::EBADF exception is raised the
|
138
|
+
# exception is ignored. If an Exception subclass is raised the exception
|
139
|
+
# is logged and re-raised which stops the server.
|
140
|
+
#
|
141
|
+
# To completely shut down a server call #shutdown from ensure:
|
142
|
+
#
|
143
|
+
# server = WEBrick::GenericServer.new
|
144
|
+
# # or WEBrick::HTTPServer.new
|
145
|
+
#
|
146
|
+
# begin
|
147
|
+
# server.start
|
148
|
+
# ensure
|
149
|
+
# server.shutdown
|
150
|
+
# end
|
151
|
+
|
85
152
|
def start(&block)
|
86
153
|
raise ServerError, "already started." if @status != :Stop
|
87
154
|
server_type = @config[:ServerType] || SimpleServer
|
88
155
|
|
156
|
+
setup_shutdown_pipe
|
157
|
+
|
89
158
|
server_type.start{
|
90
159
|
@logger.info \
|
91
160
|
"#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
|
92
161
|
call_callback(:StartCallback)
|
93
162
|
|
163
|
+
shutdown_pipe = @shutdown_pipe
|
164
|
+
|
94
165
|
thgroup = ThreadGroup.new
|
95
166
|
@status = :Running
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
if
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
@tokens.push(nil)
|
167
|
+
begin
|
168
|
+
while @status == :Running
|
169
|
+
begin
|
170
|
+
sp = shutdown_pipe[0]
|
171
|
+
if svrs = IO.select([sp, *@listeners], nil, nil, 2.0)
|
172
|
+
if svrs[0].include? sp
|
173
|
+
# swallow shutdown pipe
|
174
|
+
buf = String.new
|
175
|
+
nil while String ===
|
176
|
+
sp.read_nonblock([sp.nread, 8].max, buf, exception: false)
|
177
|
+
break
|
108
178
|
end
|
109
|
-
|
179
|
+
svrs[0].each{|svr|
|
180
|
+
@tokens.pop # blocks while no token is there.
|
181
|
+
if sock = accept_client(svr)
|
182
|
+
unless config[:DoNotReverseLookup].nil?
|
183
|
+
sock.do_not_reverse_lookup = !!config[:DoNotReverseLookup]
|
184
|
+
end
|
185
|
+
th = start_thread(sock, &block)
|
186
|
+
th[:WEBrickThread] = true
|
187
|
+
thgroup.add(th)
|
188
|
+
else
|
189
|
+
@tokens.push(nil)
|
190
|
+
end
|
191
|
+
}
|
192
|
+
end
|
193
|
+
rescue Errno::EBADF, Errno::ENOTSOCK, IOError => ex
|
194
|
+
# if the listening socket was closed in GenericServer#shutdown,
|
195
|
+
# IO::select raise it.
|
196
|
+
rescue StandardError => ex
|
197
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
198
|
+
@logger.error msg
|
199
|
+
rescue Exception => ex
|
200
|
+
@logger.fatal ex
|
201
|
+
raise
|
110
202
|
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
203
|
end
|
204
|
+
ensure
|
205
|
+
cleanup_shutdown_pipe(shutdown_pipe)
|
206
|
+
cleanup_listener
|
207
|
+
@status = :Shutdown
|
208
|
+
@logger.info "going to shutdown ..."
|
209
|
+
thgroup.list.each{|th| th.join if th[:WEBrickThread] }
|
210
|
+
call_callback(:StopCallback)
|
211
|
+
@logger.info "#{self.class}#start done."
|
212
|
+
@status = :Stop
|
118
213
|
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
214
|
}
|
126
215
|
end
|
127
216
|
|
217
|
+
##
|
218
|
+
# Stops the server from accepting new connections.
|
219
|
+
|
128
220
|
def stop
|
129
221
|
if @status == :Running
|
130
222
|
@status = :Shutdown
|
131
223
|
end
|
224
|
+
|
225
|
+
alarm_shutdown_pipe {|f| f.write_nonblock("\0")}
|
132
226
|
end
|
133
227
|
|
228
|
+
##
|
229
|
+
# Shuts down the server and all listening sockets. New listeners must be
|
230
|
+
# provided to restart the server.
|
231
|
+
|
134
232
|
def shutdown
|
135
233
|
stop
|
136
|
-
|
137
|
-
|
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
|
234
|
+
|
235
|
+
alarm_shutdown_pipe(&:close)
|
155
236
|
end
|
156
237
|
|
238
|
+
##
|
239
|
+
# You must subclass GenericServer and implement \#run which accepts a TCP
|
240
|
+
# client socket
|
241
|
+
|
157
242
|
def run(sock)
|
158
243
|
@logger.fatal "run() must be provided by user."
|
159
244
|
end
|
160
245
|
|
161
246
|
private
|
162
247
|
|
248
|
+
# :stopdoc:
|
249
|
+
|
250
|
+
##
|
251
|
+
# Accepts a TCP client socket from the TCP server socket +svr+ and returns
|
252
|
+
# the client socket.
|
253
|
+
|
163
254
|
def accept_client(svr)
|
164
255
|
sock = nil
|
165
256
|
begin
|
166
257
|
sock = svr.accept
|
167
258
|
sock.sync = true
|
168
259
|
Utils::set_non_blocking(sock)
|
169
|
-
Utils::set_close_on_exec(sock)
|
170
260
|
rescue Errno::ECONNRESET, Errno::ECONNABORTED,
|
171
|
-
Errno::EPROTO, Errno::EINVAL
|
172
|
-
rescue
|
261
|
+
Errno::EPROTO, Errno::EINVAL
|
262
|
+
rescue StandardError => ex
|
173
263
|
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
174
264
|
@logger.error msg
|
175
265
|
end
|
176
266
|
return sock
|
177
267
|
end
|
178
268
|
|
269
|
+
##
|
270
|
+
# Starts a server thread for the client socket +sock+ that runs the given
|
271
|
+
# +block+.
|
272
|
+
#
|
273
|
+
# Sets the socket to the <code>:WEBrickSocket</code> thread local variable
|
274
|
+
# in the thread.
|
275
|
+
#
|
276
|
+
# If any errors occur in the block they are logged and handled.
|
277
|
+
|
179
278
|
def start_thread(sock, &block)
|
180
279
|
Thread.start{
|
181
280
|
begin
|
@@ -209,10 +308,54 @@ module WEBrick
|
|
209
308
|
}
|
210
309
|
end
|
211
310
|
|
311
|
+
##
|
312
|
+
# Calls the callback +callback_name+ from the configuration with +args+
|
313
|
+
|
212
314
|
def call_callback(callback_name, *args)
|
213
|
-
|
214
|
-
|
315
|
+
@config[callback_name]&.call(*args)
|
316
|
+
end
|
317
|
+
|
318
|
+
def setup_shutdown_pipe
|
319
|
+
return @shutdown_pipe ||= IO.pipe
|
320
|
+
end
|
321
|
+
|
322
|
+
def cleanup_shutdown_pipe(shutdown_pipe)
|
323
|
+
@shutdown_pipe = nil
|
324
|
+
shutdown_pipe&.each(&:close)
|
325
|
+
end
|
326
|
+
|
327
|
+
def alarm_shutdown_pipe
|
328
|
+
_, pipe = @shutdown_pipe # another thread may modify @shutdown_pipe.
|
329
|
+
if pipe
|
330
|
+
if !pipe.closed?
|
331
|
+
begin
|
332
|
+
yield pipe
|
333
|
+
rescue IOError # closed by another thread.
|
334
|
+
end
|
335
|
+
end
|
215
336
|
end
|
216
337
|
end
|
338
|
+
|
339
|
+
def cleanup_listener
|
340
|
+
@listeners.each{|s|
|
341
|
+
if @logger.debug?
|
342
|
+
addr = s.addr
|
343
|
+
@logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
|
344
|
+
end
|
345
|
+
begin
|
346
|
+
s.shutdown
|
347
|
+
rescue Errno::ENOTCONN
|
348
|
+
# when `Errno::ENOTCONN: Socket is not connected' on some platforms,
|
349
|
+
# call #close instead of #shutdown.
|
350
|
+
# (ignore @config[:ShutdownSocketWithoutClose])
|
351
|
+
s.close
|
352
|
+
else
|
353
|
+
unless @config[:ShutdownSocketWithoutClose]
|
354
|
+
s.close
|
355
|
+
end
|
356
|
+
end
|
357
|
+
}
|
358
|
+
@listeners.clear
|
359
|
+
end
|
217
360
|
end # end of GenericServer
|
218
361
|
end
|