webrick 1.3.1 → 1.4.3

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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/lib/webrick.rb +6 -6
  3. data/lib/webrick/accesslog.rb +9 -1
  4. data/lib/webrick/cgi.rb +58 -5
  5. data/lib/webrick/compat.rb +2 -1
  6. data/lib/webrick/config.rb +47 -10
  7. data/lib/webrick/cookie.rb +69 -7
  8. data/lib/webrick/htmlutils.rb +4 -2
  9. data/lib/webrick/httpauth.rb +6 -5
  10. data/lib/webrick/httpauth/authenticator.rb +13 -8
  11. data/lib/webrick/httpauth/basicauth.rb +16 -8
  12. data/lib/webrick/httpauth/digestauth.rb +35 -32
  13. data/lib/webrick/httpauth/htdigest.rb +12 -8
  14. data/lib/webrick/httpauth/htgroup.rb +10 -6
  15. data/lib/webrick/httpauth/htpasswd.rb +46 -9
  16. data/lib/webrick/httpauth/userdb.rb +1 -0
  17. data/lib/webrick/httpproxy.rb +93 -48
  18. data/lib/webrick/httprequest.rb +192 -27
  19. data/lib/webrick/httpresponse.rb +182 -62
  20. data/lib/webrick/https.rb +90 -2
  21. data/lib/webrick/httpserver.rb +45 -15
  22. data/lib/webrick/httpservlet.rb +6 -5
  23. data/lib/webrick/httpservlet/abstract.rb +5 -6
  24. data/lib/webrick/httpservlet/cgi_runner.rb +3 -2
  25. data/lib/webrick/httpservlet/cgihandler.rb +22 -10
  26. data/lib/webrick/httpservlet/erbhandler.rb +4 -3
  27. data/lib/webrick/httpservlet/filehandler.rb +136 -65
  28. data/lib/webrick/httpservlet/prochandler.rb +15 -1
  29. data/lib/webrick/httpstatus.rb +24 -14
  30. data/lib/webrick/httputils.rb +132 -13
  31. data/lib/webrick/httpversion.rb +28 -1
  32. data/lib/webrick/log.rb +25 -5
  33. data/lib/webrick/server.rb +234 -74
  34. data/lib/webrick/ssl.rb +100 -12
  35. data/lib/webrick/utils.rb +98 -69
  36. data/lib/webrick/version.rb +6 -1
  37. metadata +66 -72
  38. data/README.txt +0 -21
  39. data/sample/webrick/demo-app.rb +0 -66
  40. data/sample/webrick/demo-multipart.cgi +0 -12
  41. data/sample/webrick/demo-servlet.rb +0 -6
  42. data/sample/webrick/demo-urlencoded.cgi +0 -12
  43. data/sample/webrick/hello.cgi +0 -11
  44. data/sample/webrick/hello.rb +0 -8
  45. data/sample/webrick/httpd.rb +0 -23
  46. data/sample/webrick/httpproxy.rb +0 -25
  47. data/sample/webrick/httpsd.rb +0 -33
  48. data/test/openssl/utils.rb +0 -313
  49. data/test/ruby/envutil.rb +0 -208
  50. data/test/webrick/test_cgi.rb +0 -134
  51. data/test/webrick/test_cookie.rb +0 -131
  52. data/test/webrick/test_filehandler.rb +0 -285
  53. data/test/webrick/test_httpauth.rb +0 -167
  54. data/test/webrick/test_httpproxy.rb +0 -282
  55. data/test/webrick/test_httprequest.rb +0 -411
  56. data/test/webrick/test_httpresponse.rb +0 -49
  57. data/test/webrick/test_httpserver.rb +0 -305
  58. data/test/webrick/test_httputils.rb +0 -96
  59. data/test/webrick/test_httpversion.rb +0 -40
  60. data/test/webrick/test_server.rb +0 -67
  61. data/test/webrick/test_utils.rb +0 -64
  62. data/test/webrick/utils.rb +0 -58
  63. data/test/webrick/webrick.cgi +0 -36
  64. data/test/webrick/webrick_long_filename.cgi +0 -36
@@ -1,285 +0,0 @@
1
- require "test/unit"
2
- require_relative "utils.rb"
3
- require "webrick"
4
- require "stringio"
5
-
6
- class WEBrick::TestFileHandler < Test::Unit::TestCase
7
- def default_file_handler(filename)
8
- klass = WEBrick::HTTPServlet::DefaultFileHandler
9
- klass.new(WEBrick::Config::HTTP, filename)
10
- end
11
-
12
- def windows?
13
- File.directory?("\\")
14
- end
15
-
16
- def get_res_body(res)
17
- if defined? res.body.read
18
- res.body.read
19
- else
20
- res.body
21
- end
22
- end
23
-
24
- def make_range_request(range_spec)
25
- msg = <<-END_OF_REQUEST
26
- GET / HTTP/1.0
27
- Range: #{range_spec}
28
-
29
- END_OF_REQUEST
30
- return StringIO.new(msg.gsub(/^ {6}/, ""))
31
- end
32
-
33
- def make_range_response(file, range_spec)
34
- req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
35
- req.parse(make_range_request(range_spec))
36
- res = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
37
- size = File.size(file)
38
- handler = default_file_handler(file)
39
- handler.make_partial_content(req, res, file, size)
40
- return res
41
- end
42
-
43
- def test_make_partial_content
44
- filename = __FILE__
45
- filesize = File.size(filename)
46
-
47
- res = make_range_response(filename, "bytes=#{filesize-100}-")
48
- assert_match(%r{^text/plain}, res["content-type"])
49
- assert_equal(get_res_body(res).size, 100)
50
-
51
- res = make_range_response(filename, "bytes=-100")
52
- assert_match(%r{^text/plain}, res["content-type"])
53
- assert_equal(get_res_body(res).size, 100)
54
-
55
- res = make_range_response(filename, "bytes=0-99")
56
- assert_match(%r{^text/plain}, res["content-type"])
57
- assert_equal(get_res_body(res).size, 100)
58
-
59
- res = make_range_response(filename, "bytes=100-199")
60
- assert_match(%r{^text/plain}, res["content-type"])
61
- assert_equal(get_res_body(res).size, 100)
62
-
63
- res = make_range_response(filename, "bytes=0-0")
64
- assert_match(%r{^text/plain}, res["content-type"])
65
- assert_equal(get_res_body(res).size, 1)
66
-
67
- res = make_range_response(filename, "bytes=-1")
68
- assert_match(%r{^text/plain}, res["content-type"])
69
- assert_equal(get_res_body(res).size, 1)
70
-
71
- res = make_range_response(filename, "bytes=0-0, -2")
72
- assert_match(%r{^multipart/byteranges}, res["content-type"])
73
- end
74
-
75
- def test_filehandler
76
- config = { :DocumentRoot => File.dirname(__FILE__), }
77
- this_file = File.basename(__FILE__)
78
- filesize = File.size(__FILE__)
79
- this_data = File.open(__FILE__, "rb") {|f| f.read}
80
- range = nil
81
- bug2593 = '[ruby-dev:40030]'
82
-
83
- TestWEBrick.start_httpserver(config) do |server, addr, port, log|
84
- http = Net::HTTP.new(addr, port)
85
- req = Net::HTTP::Get.new("/")
86
- http.request(req){|res|
87
- assert_equal("200", res.code, log.call)
88
- assert_equal("text/html", res.content_type, log.call)
89
- assert_match(/HREF="#{this_file}"/, res.body, log.call)
90
- }
91
- req = Net::HTTP::Get.new("/#{this_file}")
92
- http.request(req){|res|
93
- assert_equal("200", res.code, log.call)
94
- assert_equal("text/plain", res.content_type, log.call)
95
- assert_equal(File.read(__FILE__), res.body, log.call)
96
- }
97
-
98
- req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=#{filesize-100}-")
99
- http.request(req){|res|
100
- assert_equal("206", res.code, log.call)
101
- assert_equal("text/plain", res.content_type, log.call)
102
- assert_nothing_raised(bug2593) {range = res.content_range}
103
- assert_equal((filesize-100)..(filesize-1), range, log.call)
104
- assert_equal(this_data[-100..-1], res.body, log.call)
105
- }
106
-
107
- req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=-100")
108
- http.request(req){|res|
109
- assert_equal("206", res.code, log.call)
110
- assert_equal("text/plain", res.content_type, log.call)
111
- assert_nothing_raised(bug2593) {range = res.content_range}
112
- assert_equal((filesize-100)..(filesize-1), range, log.call)
113
- assert_equal(this_data[-100..-1], res.body, log.call)
114
- }
115
-
116
- req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-99")
117
- http.request(req){|res|
118
- assert_equal("206", res.code, log.call)
119
- assert_equal("text/plain", res.content_type, log.call)
120
- assert_nothing_raised(bug2593) {range = res.content_range}
121
- assert_equal(0..99, range, log.call)
122
- assert_equal(this_data[0..99], res.body, log.call)
123
- }
124
-
125
- req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=100-199")
126
- http.request(req){|res|
127
- assert_equal("206", res.code, log.call)
128
- assert_equal("text/plain", res.content_type, log.call)
129
- assert_nothing_raised(bug2593) {range = res.content_range}
130
- assert_equal(100..199, range, log.call)
131
- assert_equal(this_data[100..199], res.body, log.call)
132
- }
133
-
134
- req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-0")
135
- http.request(req){|res|
136
- assert_equal("206", res.code, log.call)
137
- assert_equal("text/plain", res.content_type, log.call)
138
- assert_nothing_raised(bug2593) {range = res.content_range}
139
- assert_equal(0..0, range, log.call)
140
- assert_equal(this_data[0..0], res.body, log.call)
141
- }
142
-
143
- req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=-1")
144
- http.request(req){|res|
145
- assert_equal("206", res.code, log.call)
146
- assert_equal("text/plain", res.content_type, log.call)
147
- assert_nothing_raised(bug2593) {range = res.content_range}
148
- assert_equal((filesize-1)..(filesize-1), range, log.call)
149
- assert_equal(this_data[-1, 1], res.body, log.call)
150
- }
151
-
152
- req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-0, -2")
153
- http.request(req){|res|
154
- assert_equal("206", res.code, log.call)
155
- assert_equal("multipart/byteranges", res.content_type, log.call)
156
- }
157
-
158
- end
159
- end
160
-
161
- def test_non_disclosure_name
162
- config = { :DocumentRoot => File.dirname(__FILE__), }
163
- this_file = File.basename(__FILE__)
164
- TestWEBrick.start_httpserver(config) do |server, addr, port, log|
165
- http = Net::HTTP.new(addr, port)
166
- doc_root_opts = server[:DocumentRootOptions]
167
- doc_root_opts[:NondisclosureName] = %w(.ht* *~ test_*)
168
- req = Net::HTTP::Get.new("/")
169
- http.request(req){|res|
170
- assert_equal("200", res.code, log.call)
171
- assert_equal("text/html", res.content_type, log.call)
172
- assert_no_match(/HREF="#{File.basename(__FILE__)}"/, res.body)
173
- }
174
- req = Net::HTTP::Get.new("/#{this_file}")
175
- http.request(req){|res|
176
- assert_equal("404", res.code, log.call)
177
- }
178
- doc_root_opts[:NondisclosureName] = %w(.ht* *~ TEST_*)
179
- http.request(req){|res|
180
- assert_equal("404", res.code, log.call)
181
- }
182
- end
183
- end
184
-
185
- def test_directory_traversal
186
- config = { :DocumentRoot => File.dirname(__FILE__), }
187
- this_file = File.basename(__FILE__)
188
- TestWEBrick.start_httpserver(config) do |server, addr, port, log|
189
- http = Net::HTTP.new(addr, port)
190
- req = Net::HTTP::Get.new("/../../")
191
- http.request(req){|res| assert_equal("400", res.code, log.call) }
192
- req = Net::HTTP::Get.new("/..%5c../#{File.basename(__FILE__)}")
193
- http.request(req){|res| assert_equal(windows? ? "200" : "404", res.code, log.call) }
194
- req = Net::HTTP::Get.new("/..%5c..%5cruby.c")
195
- http.request(req){|res| assert_equal("404", res.code, log.call) }
196
- end
197
- end
198
-
199
- def test_unwise_in_path
200
- if windows?
201
- config = { :DocumentRoot => File.dirname(__FILE__), }
202
- this_file = File.basename(__FILE__)
203
- TestWEBrick.start_httpserver(config) do |server, addr, port, log|
204
- http = Net::HTTP.new(addr, port)
205
- req = Net::HTTP::Get.new("/..%5c..")
206
- http.request(req){|res| assert_equal("301", res.code, log.call) }
207
- end
208
- end
209
- end
210
-
211
- def test_short_filename
212
- config = {
213
- :CGIInterpreter => TestWEBrick::RubyBin,
214
- :DocumentRoot => File.dirname(__FILE__),
215
- :CGIPathEnv => ENV['PATH'],
216
- }
217
- TestWEBrick.start_httpserver(config) do |server, addr, port, log|
218
- http = Net::HTTP.new(addr, port)
219
- if windows?
220
- fname = nil
221
- Dir.chdir(config[:DocumentRoot]) do
222
- fname = IO.popen("dir /x webrick_long_filename.cgi", "r").read.match(/\s(w.+?cgi)\s/i)[1].downcase
223
- end
224
- else
225
- fname = "webric~1.cgi"
226
- end
227
- req = Net::HTTP::Get.new("/#{fname}/test")
228
- http.request(req) do |res|
229
- if windows?
230
- assert_equal("200", res.code, log.call)
231
- assert_equal("/test", res.body, log.call)
232
- else
233
- assert_equal("404", res.code, log.call)
234
- end
235
- end
236
-
237
- req = Net::HTTP::Get.new("/.htaccess")
238
- http.request(req) {|res| assert_equal("404", res.code, log.call) }
239
- req = Net::HTTP::Get.new("/htacce~1")
240
- http.request(req) {|res| assert_equal("404", res.code, log.call) }
241
- req = Net::HTTP::Get.new("/HTACCE~1")
242
- http.request(req) {|res| assert_equal("404", res.code, log.call) }
243
- end
244
- end
245
-
246
- def test_script_disclosure
247
- config = {
248
- :CGIInterpreter => TestWEBrick::RubyBin,
249
- :DocumentRoot => File.dirname(__FILE__),
250
- :CGIPathEnv => ENV['PATH'],
251
- :RequestCallback => Proc.new{|req, res|
252
- def req.meta_vars
253
- meta = super
254
- meta["RUBYLIB"] = $:.join(File::PATH_SEPARATOR)
255
- meta[RbConfig::CONFIG['LIBPATHENV']] = ENV[RbConfig::CONFIG['LIBPATHENV']] if RbConfig::CONFIG['LIBPATHENV']
256
- return meta
257
- end
258
- },
259
- }
260
- TestWEBrick.start_httpserver(config) do |server, addr, port, log|
261
- http = Net::HTTP.new(addr, port)
262
-
263
- req = Net::HTTP::Get.new("/webrick.cgi/test")
264
- http.request(req) do |res|
265
- assert_equal("200", res.code, log.call)
266
- assert_equal("/test", res.body, log.call)
267
- end
268
-
269
- response_assertion = Proc.new do |res|
270
- if windows?
271
- assert_equal("200", res.code, log.call)
272
- assert_equal("/test", res.body, log.call)
273
- else
274
- assert_equal("404", res.code, log.call)
275
- end
276
- end
277
- req = Net::HTTP::Get.new("/webrick.cgi%20/test")
278
- http.request(req, &response_assertion)
279
- req = Net::HTTP::Get.new("/webrick.cgi./test")
280
- http.request(req, &response_assertion)
281
- req = Net::HTTP::Get.new("/webrick.cgi::$DATA/test")
282
- http.request(req, &response_assertion)
283
- end
284
- end
285
- end
@@ -1,167 +0,0 @@
1
- require "test/unit"
2
- require "net/http"
3
- require "tempfile"
4
- require "webrick"
5
- require "webrick/httpauth/basicauth"
6
- require_relative "utils"
7
-
8
- class TestWEBrickHTTPAuth < Test::Unit::TestCase
9
- def test_basic_auth
10
- TestWEBrick.start_httpserver{|server, addr, port, log|
11
- realm = "WEBrick's realm"
12
- path = "/basic_auth"
13
-
14
- server.mount_proc(path){|req, res|
15
- WEBrick::HTTPAuth.basic_auth(req, res, realm){|user, pass|
16
- user == "webrick" && pass == "supersecretpassword"
17
- }
18
- res.body = "hoge"
19
- }
20
- http = Net::HTTP.new(addr, port)
21
- g = Net::HTTP::Get.new(path)
22
- g.basic_auth("webrick", "supersecretpassword")
23
- http.request(g){|res| assert_equal("hoge", res.body, log.call)}
24
- g.basic_auth("webrick", "not super")
25
- http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
26
- }
27
- end
28
-
29
- def test_basic_auth2
30
- TestWEBrick.start_httpserver{|server, addr, port, log|
31
- realm = "WEBrick's realm"
32
- path = "/basic_auth2"
33
-
34
- tmpfile = Tempfile.new("test_webrick_auth")
35
- tmpfile.close
36
- tmp_pass = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
37
- tmp_pass.set_passwd(realm, "webrick", "supersecretpassword")
38
- tmp_pass.set_passwd(realm, "foo", "supersecretpassword")
39
- tmp_pass.flush
40
-
41
- htpasswd = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
42
- users = []
43
- htpasswd.each{|user, pass| users << user }
44
- assert_equal(2, users.size, log.call)
45
- assert(users.member?("webrick"), log.call)
46
- assert(users.member?("foo"), log.call)
47
-
48
- server.mount_proc(path){|req, res|
49
- auth = WEBrick::HTTPAuth::BasicAuth.new(
50
- :Realm => realm, :UserDB => htpasswd,
51
- :Logger => server.logger
52
- )
53
- auth.authenticate(req, res)
54
- res.body = "hoge"
55
- }
56
- http = Net::HTTP.new(addr, port)
57
- g = Net::HTTP::Get.new(path)
58
- g.basic_auth("webrick", "supersecretpassword")
59
- http.request(g){|res| assert_equal("hoge", res.body, log.call)}
60
- g.basic_auth("webrick", "not super")
61
- http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
62
- }
63
- end
64
-
65
- def test_basic_auth3
66
- tmpfile = Tempfile.new("test_webrick_auth")
67
- tmpfile.puts("webrick:{SHA}GJYFRpBbdchp595jlh3Bhfmgp8k=")
68
- tmpfile.flush
69
- assert_raise(NotImplementedError){
70
- WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
71
- }
72
- tmpfile.close(true)
73
-
74
- tmpfile = Tempfile.new("test_webrick_auth")
75
- tmpfile.puts("webrick:$apr1$IOVMD/..$rmnOSPXr0.wwrLPZHBQZy0")
76
- tmpfile.flush
77
- assert_raise(NotImplementedError){
78
- WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
79
- }
80
- tmpfile.close(true)
81
- end
82
-
83
- DIGESTRES_ = /
84
- ([a-zA-z\-]+)
85
- [\s\t]*(?:\r\n[\s\t]*)*
86
- =
87
- [\s\t]*(?:\r\n[\s\t]*)*
88
- (?:
89
- "((?:[^"]+|\\[\x00-\x7F])*)" |
90
- ([!\#$%&'*+\-.0-9A-Z^_`a-z|~]+)
91
- )/x
92
-
93
- def test_digest_auth
94
- TestWEBrick.start_httpserver{|server, addr, port, log|
95
- realm = "WEBrick's realm"
96
- path = "/digest_auth"
97
-
98
- tmpfile = Tempfile.new("test_webrick_auth")
99
- tmpfile.close
100
- tmp_pass = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
101
- tmp_pass.set_passwd(realm, "webrick", "supersecretpassword")
102
- tmp_pass.set_passwd(realm, "foo", "supersecretpassword")
103
- tmp_pass.flush
104
-
105
- htdigest = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
106
- users = []
107
- htdigest.each{|user, pass| users << user }
108
- assert_equal(2, users.size, log.call)
109
- assert(users.member?("webrick"), log.call)
110
- assert(users.member?("foo"), log.call)
111
-
112
- auth = WEBrick::HTTPAuth::DigestAuth.new(
113
- :Realm => realm, :UserDB => htdigest,
114
- :Algorithm => 'MD5',
115
- :Logger => server.logger
116
- )
117
- server.mount_proc(path){|req, res|
118
- auth.authenticate(req, res)
119
- res.body = "hoge"
120
- }
121
-
122
- Net::HTTP.start(addr, port) do |http|
123
- g = Net::HTTP::Get.new(path)
124
- params = {}
125
- http.request(g) do |res|
126
- assert_equal('401', res.code, log.call)
127
- res["www-authenticate"].scan(DIGESTRES_) do |key, quoted, token|
128
- params[key.downcase] = token || quoted.delete('\\')
129
- end
130
- params['uri'] = "http://#{addr}:#{port}#{path}"
131
- end
132
-
133
- g['Authorization'] = credentials_for_request('webrick', "supersecretpassword", params)
134
- http.request(g){|res| assert_equal("hoge", res.body, log.call)}
135
-
136
- params['algorithm'].downcase! #4936
137
- g['Authorization'] = credentials_for_request('webrick', "supersecretpassword", params)
138
- http.request(g){|res| assert_equal("hoge", res.body, log.call)}
139
-
140
- g['Authorization'] = credentials_for_request('webrick', "not super", params)
141
- http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
142
- end
143
- }
144
- end
145
-
146
- private
147
- def credentials_for_request(user, password, params)
148
- cnonce = "hoge"
149
- nonce_count = 1
150
- ha1 = "#{user}:#{params['realm']}:#{password}"
151
- ha2 = "GET:#{params['uri']}"
152
- request_digest =
153
- "#{Digest::MD5.hexdigest(ha1)}:" \
154
- "#{params['nonce']}:#{'%08x' % nonce_count}:#{cnonce}:#{params['qop']}:" \
155
- "#{Digest::MD5.hexdigest(ha2)}"
156
- "Digest username=\"#{user}\"" \
157
- ", realm=\"#{params['realm']}\"" \
158
- ", nonce=\"#{params['nonce']}\"" \
159
- ", uri=\"#{params['uri']}\"" \
160
- ", qop=#{params['qop']}" \
161
- ", nc=#{'%08x' % nonce_count}" \
162
- ", cnonce=\"#{cnonce}\"" \
163
- ", response=\"#{Digest::MD5.hexdigest(request_digest)}\"" \
164
- ", opaque=\"#{params['opaque']}\"" \
165
- ", algorithm=#{params['algorithm']}"
166
- end
167
- end