webrick 1.3.1 → 1.6.1

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.

Potentially problematic release.


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

Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +63 -0
  5. data/Rakefile +10 -0
  6. data/bin/console +14 -0
  7. data/bin/setup +8 -0
  8. data/lib/webrick.rb +7 -7
  9. data/lib/webrick/accesslog.rb +12 -6
  10. data/lib/webrick/cgi.rb +58 -5
  11. data/lib/webrick/compat.rb +2 -1
  12. data/lib/webrick/config.rb +47 -10
  13. data/lib/webrick/cookie.rb +69 -7
  14. data/lib/webrick/htmlutils.rb +4 -2
  15. data/lib/webrick/httpauth.rb +6 -5
  16. data/lib/webrick/httpauth/authenticator.rb +13 -8
  17. data/lib/webrick/httpauth/basicauth.rb +16 -8
  18. data/lib/webrick/httpauth/digestauth.rb +35 -32
  19. data/lib/webrick/httpauth/htdigest.rb +12 -8
  20. data/lib/webrick/httpauth/htgroup.rb +10 -6
  21. data/lib/webrick/httpauth/htpasswd.rb +46 -9
  22. data/lib/webrick/httpauth/userdb.rb +1 -0
  23. data/lib/webrick/httpproxy.rb +93 -48
  24. data/lib/webrick/httprequest.rb +201 -31
  25. data/lib/webrick/httpresponse.rb +235 -70
  26. data/lib/webrick/https.rb +90 -2
  27. data/lib/webrick/httpserver.rb +45 -15
  28. data/lib/webrick/httpservlet.rb +6 -5
  29. data/lib/webrick/httpservlet/abstract.rb +5 -6
  30. data/lib/webrick/httpservlet/cgi_runner.rb +3 -2
  31. data/lib/webrick/httpservlet/cgihandler.rb +29 -11
  32. data/lib/webrick/httpservlet/erbhandler.rb +4 -3
  33. data/lib/webrick/httpservlet/filehandler.rb +136 -65
  34. data/lib/webrick/httpservlet/prochandler.rb +15 -1
  35. data/lib/webrick/httpstatus.rb +24 -14
  36. data/lib/webrick/httputils.rb +134 -17
  37. data/lib/webrick/httpversion.rb +28 -1
  38. data/lib/webrick/log.rb +25 -5
  39. data/lib/webrick/server.rb +234 -74
  40. data/lib/webrick/ssl.rb +100 -12
  41. data/lib/webrick/utils.rb +98 -69
  42. data/lib/webrick/version.rb +6 -1
  43. data/webrick.gemspec +76 -0
  44. metadata +73 -72
  45. data/README.txt +0 -21
  46. data/sample/webrick/demo-app.rb +0 -66
  47. data/sample/webrick/demo-multipart.cgi +0 -12
  48. data/sample/webrick/demo-servlet.rb +0 -6
  49. data/sample/webrick/demo-urlencoded.cgi +0 -12
  50. data/sample/webrick/hello.cgi +0 -11
  51. data/sample/webrick/hello.rb +0 -8
  52. data/sample/webrick/httpd.rb +0 -23
  53. data/sample/webrick/httpproxy.rb +0 -25
  54. data/sample/webrick/httpsd.rb +0 -33
  55. data/test/openssl/utils.rb +0 -313
  56. data/test/ruby/envutil.rb +0 -208
  57. data/test/webrick/test_cgi.rb +0 -134
  58. data/test/webrick/test_cookie.rb +0 -131
  59. data/test/webrick/test_filehandler.rb +0 -285
  60. data/test/webrick/test_httpauth.rb +0 -167
  61. data/test/webrick/test_httpproxy.rb +0 -282
  62. data/test/webrick/test_httprequest.rb +0 -411
  63. data/test/webrick/test_httpresponse.rb +0 -49
  64. data/test/webrick/test_httpserver.rb +0 -305
  65. data/test/webrick/test_httputils.rb +0 -96
  66. data/test/webrick/test_httpversion.rb +0 -40
  67. data/test/webrick/test_server.rb +0 -67
  68. data/test/webrick/test_utils.rb +0 -64
  69. data/test/webrick/utils.rb +0 -58
  70. data/test/webrick/webrick.cgi +0 -36
  71. data/test/webrick/webrick_long_filename.cgi +0 -36
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # cookie.rb -- Cookie class
3
4
  #
@@ -9,17 +10,59 @@
9
10
  # $IPR: cookie.rb,v 1.16 2002/09/21 12:23:35 gotoyuzo Exp $
10
11
 
11
12
  require 'time'
12
- require 'webrick/httputils'
13
+ require_relative 'httputils'
13
14
 
14
15
  module WEBrick
16
+
17
+ ##
18
+ # Processes HTTP cookies
19
+
15
20
  class Cookie
16
21
 
22
+ ##
23
+ # The cookie name
24
+
17
25
  attr_reader :name
18
- attr_accessor :value, :version
19
- attr_accessor :domain, :path, :secure
20
- attr_accessor :comment, :max_age
26
+
27
+ ##
28
+ # The cookie value
29
+
30
+ attr_accessor :value
31
+
32
+ ##
33
+ # The cookie version
34
+
35
+ attr_accessor :version
36
+
37
+ ##
38
+ # The cookie domain
39
+ attr_accessor :domain
40
+
41
+ ##
42
+ # The cookie path
43
+
44
+ attr_accessor :path
45
+
46
+ ##
47
+ # Is this a secure cookie?
48
+
49
+ attr_accessor :secure
50
+
51
+ ##
52
+ # The cookie comment
53
+
54
+ attr_accessor :comment
55
+
56
+ ##
57
+ # The maximum age of the cookie
58
+
59
+ attr_accessor :max_age
60
+
21
61
  #attr_accessor :comment_url, :discard, :port
22
62
 
63
+ ##
64
+ # Creates a new cookie with the given +name+ and +value+
65
+
23
66
  def initialize(name, value)
24
67
  @name = name
25
68
  @value = value
@@ -29,14 +72,25 @@ module WEBrick
29
72
  @expires = @comment_url = @discard = @port = nil
30
73
  end
31
74
 
75
+ ##
76
+ # Sets the cookie expiration to the time +t+. The expiration time may be
77
+ # a false value to disable expiration or a Time or HTTP format time string
78
+ # to set the expiration date.
79
+
32
80
  def expires=(t)
33
81
  @expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s)
34
82
  end
35
83
 
84
+ ##
85
+ # Retrieves the expiration time as a Time
86
+
36
87
  def expires
37
88
  @expires && Time.parse(@expires)
38
89
  end
39
90
 
91
+ ##
92
+ # The cookie string suitable for use in an HTTP header
93
+
40
94
  def to_s
41
95
  ret = ""
42
96
  ret << @name << "=" << @value
@@ -50,14 +104,16 @@ module WEBrick
50
104
  ret
51
105
  end
52
106
 
53
- # Cookie::parse()
54
- # It parses Cookie field sent from the user agent.
107
+ ##
108
+ # Parses a Cookie field sent from the user-agent. Returns an array of
109
+ # cookies.
110
+
55
111
  def self.parse(str)
56
112
  if str
57
113
  ret = []
58
114
  cookie = nil
59
115
  ver = 0
60
- str.split(/[;,]\s+/).each{|x|
116
+ str.split(/;\s+/).each{|x|
61
117
  key, val = x.split(/=/,2)
62
118
  val = val ? HTTPUtils::dequote(val) : ""
63
119
  case key
@@ -76,6 +132,9 @@ module WEBrick
76
132
  end
77
133
  end
78
134
 
135
+ ##
136
+ # Parses the cookie in +str+
137
+
79
138
  def self.parse_set_cookie(str)
80
139
  cookie_elem = str.split(/;/)
81
140
  first_elem = cookie_elem.shift
@@ -101,6 +160,9 @@ module WEBrick
101
160
  return cookie
102
161
  end
103
162
 
163
+ ##
164
+ # Parses the cookies in +str+
165
+
104
166
  def self.parse_set_cookies(str)
105
167
  return str.split(/,(?=[^;,]*=)|,$/).collect{|c|
106
168
  parse_set_cookie(c)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #--
2
3
  # htmlutils.rb -- HTMLUtils Module
3
4
  #
@@ -15,12 +16,13 @@ module WEBrick
15
16
  # Escapes &, ", > and < in +string+
16
17
 
17
18
  def escape(string)
18
- str = string ? string.dup : ""
19
+ return "" unless string
20
+ str = string.b
19
21
  str.gsub!(/&/n, '&amp;')
20
22
  str.gsub!(/\"/n, '&quot;')
21
23
  str.gsub!(/>/n, '&gt;')
22
24
  str.gsub!(/</n, '&lt;')
23
- str
25
+ str.force_encoding(string.encoding)
24
26
  end
25
27
  module_function :escape
26
28
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # httpauth.rb -- HTTP access authentication
3
4
  #
@@ -8,11 +9,11 @@
8
9
  #
9
10
  # $IPR: httpauth.rb,v 1.14 2003/07/22 19:20:42 gotoyuzo Exp $
10
11
 
11
- require 'webrick/httpauth/basicauth'
12
- require 'webrick/httpauth/digestauth'
13
- require 'webrick/httpauth/htpasswd'
14
- require 'webrick/httpauth/htdigest'
15
- require 'webrick/httpauth/htgroup'
12
+ require_relative 'httpauth/basicauth'
13
+ require_relative 'httpauth/digestauth'
14
+ require_relative 'httpauth/htpasswd'
15
+ require_relative 'httpauth/htdigest'
16
+ require_relative 'httpauth/htgroup'
16
17
 
17
18
  module WEBrick
18
19
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #--
2
3
  # httpauth/authenticator.rb -- Authenticator mix-in module.
3
4
  #
@@ -16,10 +17,10 @@ module WEBrick
16
17
 
17
18
  module Authenticator
18
19
 
19
- RequestField = "Authorization"
20
- ResponseField = "WWW-Authenticate"
21
- ResponseInfoField = "Authentication-Info"
22
- AuthException = HTTPStatus::Unauthorized
20
+ RequestField = "Authorization" # :nodoc:
21
+ ResponseField = "WWW-Authenticate" # :nodoc:
22
+ ResponseInfoField = "Authentication-Info" # :nodoc:
23
+ AuthException = HTTPStatus::Unauthorized # :nodoc:
23
24
 
24
25
  ##
25
26
  # Method of authentication, must be overridden by the including class
@@ -43,6 +44,8 @@ module WEBrick
43
44
 
44
45
  private
45
46
 
47
+ # :stopdoc:
48
+
46
49
  ##
47
50
  # Initializes the authenticator from +config+
48
51
 
@@ -96,6 +99,8 @@ module WEBrick
96
99
  log(:info, fmt, *args)
97
100
  end
98
101
  end
102
+
103
+ # :startdoc:
99
104
  end
100
105
 
101
106
  ##
@@ -103,10 +108,10 @@ module WEBrick
103
108
  # authentication schemes for proxies.
104
109
 
105
110
  module ProxyAuthenticator
106
- RequestField = "Proxy-Authorization"
107
- ResponseField = "Proxy-Authenticate"
108
- InfoField = "Proxy-Authentication-Info"
109
- AuthException = HTTPStatus::ProxyAuthenticationRequired
111
+ RequestField = "Proxy-Authorization" # :nodoc:
112
+ ResponseField = "Proxy-Authenticate" # :nodoc:
113
+ InfoField = "Proxy-Authentication-Info" # :nodoc:
114
+ AuthException = HTTPStatus::ProxyAuthenticationRequired # :nodoc:
110
115
  end
111
116
  end
112
117
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # httpauth/basicauth.rb -- HTTP basic access authentication
3
4
  #
@@ -7,9 +8,9 @@
7
8
  #
8
9
  # $IPR: basicauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $
9
10
 
10
- require 'webrick/config'
11
- require 'webrick/httpstatus'
12
- require 'webrick/httpauth/authenticator'
11
+ require_relative '../config'
12
+ require_relative '../httpstatus'
13
+ require_relative 'authenticator'
13
14
 
14
15
  module WEBrick
15
16
  module HTTPAuth
@@ -23,7 +24,7 @@ module WEBrick
23
24
  #
24
25
  # config = { :Realm => 'BasicAuth example realm' }
25
26
  #
26
- # htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file'
27
+ # htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file', password_hash: :bcrypt
27
28
  # htpasswd.set_passwd config[:Realm], 'username', 'password'
28
29
  # htpasswd.flush
29
30
  #
@@ -34,7 +35,7 @@ module WEBrick
34
35
  class BasicAuth
35
36
  include Authenticator
36
37
 
37
- AuthScheme = "Basic"
38
+ AuthScheme = "Basic" # :nodoc:
38
39
 
39
40
  ##
40
41
  # Used by UserDB to create a basic password entry
@@ -80,7 +81,15 @@ module WEBrick
80
81
  error("%s: the user is not allowed.", userid)
81
82
  challenge(req, res)
82
83
  end
83
- if password.crypt(encpass) != encpass
84
+
85
+ case encpass
86
+ when /\A\$2[aby]\$/
87
+ password_matches = BCrypt::Password.new(encpass.sub(/\A\$2[aby]\$/, '$2a$')) == password
88
+ else
89
+ password_matches = password.crypt(encpass) == encpass
90
+ end
91
+
92
+ unless password_matches
84
93
  error("%s: password unmatch.", userid)
85
94
  challenge(req, res)
86
95
  end
@@ -89,8 +98,7 @@ module WEBrick
89
98
  end
90
99
 
91
100
  ##
92
- # Returns a challenge response which asks for for authentication
93
- # information
101
+ # Returns a challenge response which asks for authentication information
94
102
 
95
103
  def challenge(req, res)
96
104
  res[@response_field] = "#{@auth_scheme} realm=\"#{@realm}\""
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # httpauth/digestauth.rb -- HTTP digest access authentication
3
4
  #
@@ -11,9 +12,9 @@
11
12
  #
12
13
  # $IPR: digestauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $
13
14
 
14
- require 'webrick/config'
15
- require 'webrick/httpstatus'
16
- require 'webrick/httpauth/authenticator'
15
+ require_relative '../config'
16
+ require_relative '../httpstatus'
17
+ require_relative 'authenticator'
17
18
  require 'digest/md5'
18
19
  require 'digest/sha1'
19
20
 
@@ -45,9 +46,22 @@ module WEBrick
45
46
  class DigestAuth
46
47
  include Authenticator
47
48
 
48
- AuthScheme = "Digest"
49
- OpaqueInfo = Struct.new(:time, :nonce, :nc)
50
- attr_reader :algorithm, :qop
49
+ AuthScheme = "Digest" # :nodoc:
50
+
51
+ ##
52
+ # Struct containing the opaque portion of the digest authentication
53
+
54
+ OpaqueInfo = Struct.new(:time, :nonce, :nc) # :nodoc:
55
+
56
+ ##
57
+ # Digest authentication algorithm
58
+
59
+ attr_reader :algorithm
60
+
61
+ ##
62
+ # Quality of protection. RFC 2617 defines "auth" and "auth-int"
63
+
64
+ attr_reader :qop
51
65
 
52
66
  ##
53
67
  # Used by UserDB to create a digest password entry
@@ -97,7 +111,7 @@ module WEBrick
97
111
  @instance_key = hexdigest(self.__id__, Time.now.to_i, Process.pid)
98
112
  @opaques = {}
99
113
  @last_nonce_expire = Time.now
100
- @mutex = Mutex.new
114
+ @mutex = Thread::Mutex.new
101
115
  end
102
116
 
103
117
  ##
@@ -115,8 +129,7 @@ module WEBrick
115
129
  end
116
130
 
117
131
  ##
118
- # Returns a challenge response which asks for for authentication
119
- # information
132
+ # Returns a challenge response which asks for authentication information
120
133
 
121
134
  def challenge(req, res, stale=false)
122
135
  nonce = generate_next_nonce(req)
@@ -142,6 +155,8 @@ module WEBrick
142
155
 
143
156
  private
144
157
 
158
+ # :stopdoc:
159
+
145
160
  MustParams = ['username','realm','nonce','uri','response']
146
161
  MustParamsAuth = ['cnonce','nc']
147
162
 
@@ -189,7 +204,7 @@ module WEBrick
189
204
 
190
205
  password = @userdb.get_passwd(@realm, auth_req['username'], @reload_db)
191
206
  unless password
192
- error('%s: the user is not allowd.', auth_req['username'])
207
+ error('%s: the user is not allowed.', auth_req['username'])
193
208
  return false
194
209
  end
195
210
 
@@ -220,9 +235,11 @@ module WEBrick
220
235
  ha2 = hexdigest(req.request_method, auth_req['uri'])
221
236
  ha2_res = hexdigest("", auth_req['uri'])
222
237
  elsif auth_req['qop'] == "auth-int"
223
- ha2 = hexdigest(req.request_method, auth_req['uri'],
224
- hexdigest(req.body))
225
- ha2_res = hexdigest("", auth_req['uri'], hexdigest(res.body))
238
+ body_digest = @h.new
239
+ req.body { |chunk| body_digest.update(chunk) }
240
+ body_digest = body_digest.hexdigest
241
+ ha2 = hexdigest(req.request_method, auth_req['uri'], body_digest)
242
+ ha2_res = hexdigest("", auth_req['uri'], body_digest)
226
243
  end
227
244
 
228
245
  if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int"
@@ -273,23 +290,8 @@ module WEBrick
273
290
 
274
291
  def split_param_value(string)
275
292
  ret = {}
276
- while string.bytesize != 0
277
- case string
278
- when /^\s*([\w\-\.\*\%\!]+)=\s*\"((\\.|[^\"])*)\"\s*,?/
279
- key = $1
280
- matched = $2
281
- string = $'
282
- ret[key] = matched.gsub(/\\(.)/, "\\1")
283
- when /^\s*([\w\-\.\*\%\!]+)=\s*([^,\"]*),?/
284
- key = $1
285
- matched = $2
286
- string = $'
287
- ret[key] = matched.clone
288
- when /^s*^,/
289
- string = $'
290
- else
291
- break
292
- end
293
+ string.scan(/\G\s*([\w\-.*%!]+)=\s*(?:\"((?>\\.|[^\"])*)\"|([^,\"]*))\s*,?/) do
294
+ ret[$1] = $3 || $2.gsub(/\\(.)/, "\\1")
293
295
  end
294
296
  ret
295
297
  end
@@ -297,7 +299,7 @@ module WEBrick
297
299
  def generate_next_nonce(req)
298
300
  now = "%012d" % req.request_time.to_i
299
301
  pk = hexdigest(now, @instance_key)[0,32]
300
- nonce = [now + ":" + pk].pack("m*").chop # it has 60 length of chars.
302
+ nonce = [now + ":" + pk].pack("m0") # it has 60 length of chars.
301
303
  nonce
302
304
  end
303
305
 
@@ -375,6 +377,7 @@ module WEBrick
375
377
  @h.hexdigest(args.join(":"))
376
378
  end
377
379
 
380
+ # :startdoc:
378
381
  end
379
382
 
380
383
  ##
@@ -384,7 +387,7 @@ module WEBrick
384
387
  include ProxyAuthenticator
385
388
 
386
389
  private
387
- def check_uri(req, auth_req)
390
+ def check_uri(req, auth_req) # :nodoc:
388
391
  return true
389
392
  end
390
393
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # httpauth/htdigest.rb -- Apache compatible htdigest file
3
4
  #
@@ -7,8 +8,8 @@
7
8
  #
8
9
  # $IPR: htdigest.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $
9
10
 
10
- require 'webrick/httpauth/userdb'
11
- require 'webrick/httpauth/digestauth'
11
+ require_relative 'userdb'
12
+ require_relative 'digestauth'
12
13
  require 'tempfile'
13
14
 
14
15
  module WEBrick
@@ -37,9 +38,9 @@ module WEBrick
37
38
  @path = path
38
39
  @mtime = Time.at(0)
39
40
  @digest = Hash.new
40
- @mutex = Mutex::new
41
+ @mutex = Thread::Mutex::new
41
42
  @auth_type = DigestAuth
42
- open(@path,"a").close unless File::exist?(@path)
43
+ File.open(@path,"a").close unless File.exist?(@path)
43
44
  reload
44
45
  end
45
46
 
@@ -50,7 +51,7 @@ module WEBrick
50
51
  mtime = File::mtime(@path)
51
52
  if mtime > @mtime
52
53
  @digest.clear
53
- open(@path){|io|
54
+ File.open(@path){|io|
54
55
  while line = io.gets
55
56
  line.chomp!
56
57
  user, realm, pass = line.split(/:/, 3)
@@ -70,13 +71,16 @@ module WEBrick
70
71
 
71
72
  def flush(output=nil)
72
73
  output ||= @path
73
- tmp = Tempfile.new("htpasswd", File::dirname(output))
74
+ tmp = Tempfile.create("htpasswd", File::dirname(output))
75
+ renamed = false
74
76
  begin
75
77
  each{|item| tmp.puts(item.join(":")) }
76
78
  tmp.close
77
79
  File::rename(tmp.path, output)
78
- rescue
79
- tmp.close(true)
80
+ renamed = true
81
+ ensure
82
+ tmp.close
83
+ File.unlink(tmp.path) if !renamed
80
84
  end
81
85
  end
82
86