rubysl-webrick 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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)