rubysl-webrick 1.0.0 → 2.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.
Files changed (39) hide show
  1. checksums.yaml +14 -6
  2. data/.travis.yml +5 -6
  3. data/lib/rubysl/webrick/version.rb +1 -1
  4. data/lib/rubysl/webrick/webrick.rb +199 -2
  5. data/lib/webrick/accesslog.rb +96 -5
  6. data/lib/webrick/cgi.rb +80 -29
  7. data/lib/webrick/compat.rb +20 -0
  8. data/lib/webrick/config.rb +59 -5
  9. data/lib/webrick/cookie.rb +66 -5
  10. data/lib/webrick/htmlutils.rb +4 -1
  11. data/lib/webrick/httpauth.rb +53 -3
  12. data/lib/webrick/httpauth/authenticator.rb +53 -16
  13. data/lib/webrick/httpauth/basicauth.rb +45 -2
  14. data/lib/webrick/httpauth/digestauth.rb +82 -17
  15. data/lib/webrick/httpauth/htdigest.rb +38 -1
  16. data/lib/webrick/httpauth/htgroup.rb +32 -0
  17. data/lib/webrick/httpauth/htpasswd.rb +40 -2
  18. data/lib/webrick/httpauth/userdb.rb +27 -4
  19. data/lib/webrick/httpproxy.rb +197 -112
  20. data/lib/webrick/httprequest.rb +268 -50
  21. data/lib/webrick/httpresponse.rb +170 -33
  22. data/lib/webrick/https.rb +26 -3
  23. data/lib/webrick/httpserver.rb +75 -7
  24. data/lib/webrick/httpservlet/abstract.rb +88 -6
  25. data/lib/webrick/httpservlet/cgi_runner.rb +5 -4
  26. data/lib/webrick/httpservlet/cgihandler.rb +37 -18
  27. data/lib/webrick/httpservlet/erbhandler.rb +40 -7
  28. data/lib/webrick/httpservlet/filehandler.rb +116 -28
  29. data/lib/webrick/httpservlet/prochandler.rb +17 -4
  30. data/lib/webrick/httpstatus.rb +86 -18
  31. data/lib/webrick/httputils.rb +131 -23
  32. data/lib/webrick/httpversion.rb +28 -2
  33. data/lib/webrick/log.rb +72 -5
  34. data/lib/webrick/server.rb +158 -33
  35. data/lib/webrick/ssl.rb +78 -9
  36. data/lib/webrick/utils.rb +151 -5
  37. data/lib/webrick/version.rb +5 -1
  38. data/rubysl-webrick.gemspec +0 -1
  39. metadata +12 -24
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # HTTPVersion.rb -- presentation of HTTP version
3
3
  #
4
4
  # Author: IPR -- Internet Programming with Ruby -- writers
@@ -8,15 +8,33 @@
8
8
  # $IPR: httpversion.rb,v 1.5 2002/09/21 12:23:37 gotoyuzo Exp $
9
9
 
10
10
  module WEBrick
11
+
12
+ ##
13
+ # Represents an HTTP protocol version
14
+
11
15
  class HTTPVersion
12
16
  include Comparable
13
17
 
14
- attr_accessor :major, :minor
18
+ ##
19
+ # The major protocol version number
20
+
21
+ attr_accessor :major
22
+
23
+ ##
24
+ # The minor protocol version number
25
+
26
+ attr_accessor :minor
27
+
28
+ ##
29
+ # Converts +version+ into an HTTPVersion
15
30
 
16
31
  def self.convert(version)
17
32
  version.is_a?(self) ? version : new(version)
18
33
  end
19
34
 
35
+ ##
36
+ # Creates a new HTTPVersion from +version+.
37
+
20
38
  def initialize(version)
21
39
  case version
22
40
  when HTTPVersion
@@ -32,6 +50,10 @@ module WEBrick
32
50
  end
33
51
  end
34
52
 
53
+ ##
54
+ # Compares this version with +other+ according to the HTTP specification
55
+ # rules.
56
+
35
57
  def <=>(other)
36
58
  unless other.is_a?(self.class)
37
59
  other = self.class.new(other)
@@ -42,6 +64,10 @@ module WEBrick
42
64
  return ret
43
65
  end
44
66
 
67
+ ##
68
+ # The HTTP version as show in the HTTP request and response. For example,
69
+ # "1.1"
70
+
45
71
  def to_s
46
72
  format("%d.%d", @major, @minor)
47
73
  end
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # log.rb -- Log Class
3
3
  #
4
4
  # Author: IPR -- Internet Programming with Ruby -- writers
@@ -9,12 +9,43 @@
9
9
  # $IPR: log.rb,v 1.26 2002/10/06 17:06:10 gotoyuzo Exp $
10
10
 
11
11
  module WEBrick
12
+
13
+ ##
14
+ # A generic logging class
15
+
12
16
  class BasicLog
13
- # log-level constant
14
- FATAL, ERROR, WARN, INFO, DEBUG = 1, 2, 3, 4, 5
15
17
 
18
+ # Fatal log level which indicates a server crash
19
+
20
+ FATAL = 1
21
+
22
+ # Error log level which indicates a recoverable error
23
+
24
+ ERROR = 2
25
+
26
+ # Warning log level which indicates a possible problem
27
+
28
+ WARN = 3
29
+
30
+ # Information log level which indicates possibly useful information
31
+
32
+ INFO = 4
33
+
34
+ # Debugging error level for messages used in server development or
35
+ # debugging
36
+
37
+ DEBUG = 5
38
+
39
+ # log-level, messages above this level will be logged
16
40
  attr_accessor :level
17
41
 
42
+ ##
43
+ # Initializes a new logger for +log_file+ that outputs messages at +level+
44
+ # or higher. +log_file+ can be a filename, an IO-like object that
45
+ # responds to #<< or nil which outputs to $stderr.
46
+ #
47
+ # If no level is given INFO is chosen by default
48
+
18
49
  def initialize(log_file=nil, level=nil)
19
50
  @level = level || INFO
20
51
  case log_file
@@ -29,11 +60,17 @@ module WEBrick
29
60
  end
30
61
  end
31
62
 
63
+ ##
64
+ # Closes the logger (also closes the log device associated to the logger)
32
65
  def close
33
66
  @log.close if @opened
34
67
  @log = nil
35
68
  end
36
69
 
70
+ ##
71
+ # Logs +data+ at +level+ if the given level is above the current log
72
+ # level.
73
+
37
74
  def log(level, data)
38
75
  if @log && level <= @level
39
76
  data += "\n" if /\n\Z/ !~ data
@@ -41,26 +78,45 @@ module WEBrick
41
78
  end
42
79
  end
43
80
 
81
+ ##
82
+ # Synonym for log(INFO, obj.to_s)
44
83
  def <<(obj)
45
84
  log(INFO, obj.to_s)
46
85
  end
47
86
 
87
+ # Shortcut for logging a FATAL message
48
88
  def fatal(msg) log(FATAL, "FATAL " << format(msg)); end
89
+ # Shortcut for logging an ERROR message
49
90
  def error(msg) log(ERROR, "ERROR " << format(msg)); end
91
+ # Shortcut for logging a WARN message
50
92
  def warn(msg) log(WARN, "WARN " << format(msg)); end
93
+ # Shortcut for logging an INFO message
51
94
  def info(msg) log(INFO, "INFO " << format(msg)); end
95
+ # Shortcut for logging a DEBUG message
52
96
  def debug(msg) log(DEBUG, "DEBUG " << format(msg)); end
53
97
 
98
+ # Will the logger output FATAL messages?
54
99
  def fatal?; @level >= FATAL; end
100
+ # Will the logger output ERROR messages?
55
101
  def error?; @level >= ERROR; end
102
+ # Will the logger output WARN messages?
56
103
  def warn?; @level >= WARN; end
104
+ # Will the logger output INFO messages?
57
105
  def info?; @level >= INFO; end
106
+ # Will the logger output DEBUG messages?
58
107
  def debug?; @level >= DEBUG; end
59
108
 
60
109
  private
61
110
 
111
+ ##
112
+ # Formats +arg+ for the logger
113
+ #
114
+ # * If +arg+ is an Exception, it will format the error message and
115
+ # the back trace.
116
+ # * If +arg+ responds to #to_str, it will return it.
117
+ # * Otherwise it will return +arg+.inspect.
62
118
  def format(arg)
63
- str = if arg.is_a?(Exception)
119
+ if arg.is_a?(Exception)
64
120
  "#{arg.class}: #{arg.message}\n\t" <<
65
121
  arg.backtrace.join("\n\t") << "\n"
66
122
  elsif arg.respond_to?(:to_str)
@@ -71,14 +127,25 @@ module WEBrick
71
127
  end
72
128
  end
73
129
 
130
+ ##
131
+ # A logging class that prepends a timestamp to each message.
132
+
74
133
  class Log < BasicLog
75
- attr_accessor :time_format
134
+ # Format of the timestamp which is applied to each logged line. The
135
+ # default is <tt>"[%Y-%m-%d %H:%M:%S]"</tt>
136
+ attr_accessor :time_format
76
137
 
138
+ ##
139
+ # Same as BasicLog#initialize
140
+ #
141
+ # You can set the timestamp format through #time_format
77
142
  def initialize(log_file=nil, level=nil)
78
143
  super(log_file, level)
79
144
  @time_format = "[%Y-%m-%d %H:%M:%S]"
80
145
  end
81
146
 
147
+ ##
148
+ # Same as BasicLog#log
82
149
  def log(level, data)
83
150
  tmp = Time.now.strftime(@time_format)
84
151
  tmp << " " << data
@@ -10,21 +10,38 @@
10
10
 
11
11
  require 'thread'
12
12
  require 'socket'
13
- require 'timeout'
14
13
  require 'webrick/config'
15
14
  require 'webrick/log'
16
15
 
17
16
  module WEBrick
18
17
 
18
+ ##
19
+ # Server error exception
20
+
19
21
  class ServerError < StandardError; end
20
22
 
23
+ ##
24
+ # Base server class
25
+
21
26
  class SimpleServer
27
+
28
+ ##
29
+ # A SimpleServer only yields when you start it
30
+
22
31
  def SimpleServer.start
23
32
  yield
24
33
  end
25
34
  end
26
35
 
36
+ ##
37
+ # A generic module for daemonizing a process
38
+
27
39
  class Daemon
40
+
41
+ ##
42
+ # Performs the standard operations for daemonizing a process. Runs a
43
+ # block, if given.
44
+
28
45
  def Daemon.start
29
46
  exit!(0) if fork
30
47
  Process::setsid
@@ -38,8 +55,41 @@ module WEBrick
38
55
  end
39
56
  end
40
57
 
58
+ ##
59
+ # Base TCP server class. You must subclass GenericServer and provide a #run
60
+ # method.
61
+
41
62
  class GenericServer
42
- attr_reader :status, :config, :logger, :tokens, :listeners
63
+
64
+ ##
65
+ # The server status. One of :Stop, :Running or :Shutdown
66
+
67
+ attr_reader :status
68
+
69
+ ##
70
+ # The server configuration
71
+
72
+ attr_reader :config
73
+
74
+ ##
75
+ # The server logger. This is independent from the HTTP access log.
76
+
77
+ attr_reader :logger
78
+
79
+ ##
80
+ # Tokens control the number of outstanding clients. The
81
+ # <code>:MaxClients</code> configuration sets this.
82
+
83
+ attr_reader :tokens
84
+
85
+ ##
86
+ # Sockets listening for connections.
87
+
88
+ attr_reader :listeners
89
+
90
+ ##
91
+ # Creates a new generic server from +config+. The default configuration
92
+ # comes from +default+.
43
93
 
44
94
  def initialize(config={}, default=Config::General)
45
95
  @config = default.dup.update(config)
@@ -67,14 +117,42 @@ module WEBrick
67
117
  end
68
118
  end
69
119
 
120
+ ##
121
+ # Retrieves +key+ from the configuration
122
+
70
123
  def [](key)
71
124
  @config[key]
72
125
  end
73
126
 
127
+ ##
128
+ # Adds listeners from +address+ and +port+ to the server. See
129
+ # WEBrick::Utils::create_listeners for details.
130
+
74
131
  def listen(address, port)
75
132
  @listeners += Utils::create_listeners(address, port, @logger)
76
133
  end
77
134
 
135
+ ##
136
+ # Starts the server and runs the +block+ for each connection. This method
137
+ # does not return until the server is stopped from a signal handler or
138
+ # another thread using #stop or #shutdown.
139
+ #
140
+ # If the block raises a subclass of StandardError the exception is logged
141
+ # and ignored. If an IOError or Errno::EBADF exception is raised the
142
+ # exception is ignored. If an Exception subclass is raised the exception
143
+ # is logged and re-raised which stops the server.
144
+ #
145
+ # To completely shut down a server call #shutdown from ensure:
146
+ #
147
+ # server = WEBrick::GenericServer.new
148
+ # # or WEBrick::HTTPServer.new
149
+ #
150
+ # begin
151
+ # server.start
152
+ # ensure
153
+ # server.shutdown
154
+ # end
155
+
78
156
  def start(&block)
79
157
  raise ServerError, "already started." if @status != :Stop
80
158
  server_type = @config[:ServerType] || SimpleServer
@@ -86,43 +164,58 @@ module WEBrick
86
164
 
87
165
  thgroup = ThreadGroup.new
88
166
  @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
- }
167
+ begin
168
+ while @status == :Running
169
+ begin
170
+ if svrs = IO.select(@listeners, nil, nil, 2.0)
171
+ svrs[0].each{|svr|
172
+ @tokens.pop # blocks while no token is there.
173
+ if sock = accept_client(svr)
174
+ sock.do_not_reverse_lookup = config[:DoNotReverseLookup]
175
+ th = start_thread(sock, &block)
176
+ th[:WEBrickThread] = true
177
+ thgroup.add(th)
178
+ else
179
+ @tokens.push(nil)
180
+ end
181
+ }
182
+ end
183
+ rescue Errno::EBADF, IOError => ex
184
+ # if the listening socket was closed in GenericServer#shutdown,
185
+ # IO::select raise it.
186
+ rescue StandardError => ex
187
+ msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
188
+ @logger.error msg
189
+ rescue Exception => ex
190
+ @logger.fatal ex
191
+ raise
102
192
  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
193
  end
110
- end
111
194
 
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
195
+ ensure
196
+ @status = :Shutdown
197
+ @logger.info "going to shutdown ..."
198
+ thgroup.list.each{|th| th.join if th[:WEBrickThread] }
199
+ call_callback(:StopCallback)
200
+ @logger.info "#{self.class}#start done."
201
+ @status = :Stop
202
+ end
117
203
  }
118
204
  end
119
205
 
206
+ ##
207
+ # Stops the server from accepting new connections.
208
+
120
209
  def stop
121
210
  if @status == :Running
122
211
  @status = :Shutdown
123
212
  end
124
213
  end
125
214
 
215
+ ##
216
+ # Shuts down the server and all listening sockets. New listeners must be
217
+ # provided to restart the server.
218
+
126
219
  def shutdown
127
220
  stop
128
221
  @listeners.each{|s|
@@ -130,17 +223,38 @@ module WEBrick
130
223
  addr = s.addr
131
224
  @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
132
225
  end
133
- s.close
226
+ begin
227
+ s.shutdown
228
+ rescue Errno::ENOTCONN
229
+ # when `Errno::ENOTCONN: Socket is not connected' on some platforms,
230
+ # call #close instead of #shutdown.
231
+ # (ignore @config[:ShutdownSocketWithoutClose])
232
+ s.close
233
+ else
234
+ unless @config[:ShutdownSocketWithoutClose]
235
+ s.close
236
+ end
237
+ end
134
238
  }
135
239
  @listeners.clear
136
240
  end
137
241
 
242
+ ##
243
+ # You must subclass GenericServer and implement \#run which accepts a TCP
244
+ # client socket
245
+
138
246
  def run(sock)
139
247
  @logger.fatal "run() must be provided by user."
140
248
  end
141
249
 
142
250
  private
143
251
 
252
+ # :stopdoc:
253
+
254
+ ##
255
+ # Accepts a TCP client socket from the TCP server socket +svr+ and returns
256
+ # the client socket.
257
+
144
258
  def accept_client(svr)
145
259
  sock = nil
146
260
  begin
@@ -148,16 +262,24 @@ module WEBrick
148
262
  sock.sync = true
149
263
  Utils::set_non_blocking(sock)
150
264
  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
265
+ rescue Errno::ECONNRESET, Errno::ECONNABORTED,
266
+ Errno::EPROTO, Errno::EINVAL => ex
267
+ rescue StandardError => ex
155
268
  msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
156
269
  @logger.error msg
157
270
  end
158
271
  return sock
159
272
  end
160
273
 
274
+ ##
275
+ # Starts a server thread for the client socket +sock+ that runs the given
276
+ # +block+.
277
+ #
278
+ # Sets the socket to the <code>:WEBrickSocket</code> thread local variable
279
+ # in the thread.
280
+ #
281
+ # If any errors occur in the block they are logged and handled.
282
+
161
283
  def start_thread(sock, &block)
162
284
  Thread.start{
163
285
  begin
@@ -186,11 +308,14 @@ module WEBrick
186
308
  else
187
309
  @logger.debug "close: <address unknown>"
188
310
  end
189
- sock.close
311
+ sock.close unless sock.closed?
190
312
  end
191
313
  }
192
314
  end
193
315
 
316
+ ##
317
+ # Calls the callback +callback_name+ from the configuration with +args+
318
+
194
319
  def call_callback(callback_name, *args)
195
320
  if cb = @config[callback_name]
196
321
  cb.call(*args)