webrick 1.3.1

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 (63) hide show
  1. data/README.txt +21 -0
  2. data/lib/webrick.rb +227 -0
  3. data/lib/webrick/accesslog.rb +151 -0
  4. data/lib/webrick/cgi.rb +260 -0
  5. data/lib/webrick/compat.rb +35 -0
  6. data/lib/webrick/config.rb +121 -0
  7. data/lib/webrick/cookie.rb +110 -0
  8. data/lib/webrick/htmlutils.rb +28 -0
  9. data/lib/webrick/httpauth.rb +95 -0
  10. data/lib/webrick/httpauth/authenticator.rb +112 -0
  11. data/lib/webrick/httpauth/basicauth.rb +108 -0
  12. data/lib/webrick/httpauth/digestauth.rb +392 -0
  13. data/lib/webrick/httpauth/htdigest.rb +128 -0
  14. data/lib/webrick/httpauth/htgroup.rb +93 -0
  15. data/lib/webrick/httpauth/htpasswd.rb +121 -0
  16. data/lib/webrick/httpauth/userdb.rb +52 -0
  17. data/lib/webrick/httpproxy.rb +305 -0
  18. data/lib/webrick/httprequest.rb +461 -0
  19. data/lib/webrick/httpresponse.rb +399 -0
  20. data/lib/webrick/https.rb +64 -0
  21. data/lib/webrick/httpserver.rb +264 -0
  22. data/lib/webrick/httpservlet.rb +22 -0
  23. data/lib/webrick/httpservlet/abstract.rb +153 -0
  24. data/lib/webrick/httpservlet/cgi_runner.rb +46 -0
  25. data/lib/webrick/httpservlet/cgihandler.rb +108 -0
  26. data/lib/webrick/httpservlet/erbhandler.rb +87 -0
  27. data/lib/webrick/httpservlet/filehandler.rb +470 -0
  28. data/lib/webrick/httpservlet/prochandler.rb +33 -0
  29. data/lib/webrick/httpstatus.rb +184 -0
  30. data/lib/webrick/httputils.rb +394 -0
  31. data/lib/webrick/httpversion.rb +49 -0
  32. data/lib/webrick/log.rb +136 -0
  33. data/lib/webrick/server.rb +218 -0
  34. data/lib/webrick/ssl.rb +127 -0
  35. data/lib/webrick/utils.rb +241 -0
  36. data/lib/webrick/version.rb +13 -0
  37. data/sample/webrick/demo-app.rb +66 -0
  38. data/sample/webrick/demo-multipart.cgi +12 -0
  39. data/sample/webrick/demo-servlet.rb +6 -0
  40. data/sample/webrick/demo-urlencoded.cgi +12 -0
  41. data/sample/webrick/hello.cgi +11 -0
  42. data/sample/webrick/hello.rb +8 -0
  43. data/sample/webrick/httpd.rb +23 -0
  44. data/sample/webrick/httpproxy.rb +25 -0
  45. data/sample/webrick/httpsd.rb +33 -0
  46. data/test/openssl/utils.rb +313 -0
  47. data/test/ruby/envutil.rb +208 -0
  48. data/test/webrick/test_cgi.rb +134 -0
  49. data/test/webrick/test_cookie.rb +131 -0
  50. data/test/webrick/test_filehandler.rb +285 -0
  51. data/test/webrick/test_httpauth.rb +167 -0
  52. data/test/webrick/test_httpproxy.rb +282 -0
  53. data/test/webrick/test_httprequest.rb +411 -0
  54. data/test/webrick/test_httpresponse.rb +49 -0
  55. data/test/webrick/test_httpserver.rb +305 -0
  56. data/test/webrick/test_httputils.rb +96 -0
  57. data/test/webrick/test_httpversion.rb +40 -0
  58. data/test/webrick/test_server.rb +67 -0
  59. data/test/webrick/test_utils.rb +64 -0
  60. data/test/webrick/utils.rb +58 -0
  61. data/test/webrick/webrick.cgi +36 -0
  62. data/test/webrick/webrick_long_filename.cgi +36 -0
  63. metadata +106 -0
@@ -0,0 +1,241 @@
1
+ #
2
+ # utils.rb -- Miscellaneous utilities
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
6
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: utils.rb,v 1.10 2003/02/16 22:22:54 gotoyuzo Exp $
10
+
11
+ require 'socket'
12
+ require 'fcntl'
13
+ begin
14
+ require 'etc'
15
+ rescue LoadError
16
+ nil
17
+ end
18
+
19
+ module WEBrick
20
+ module Utils
21
+ ##
22
+ # Sets IO operations on +io+ to be non-blocking
23
+ def set_non_blocking(io)
24
+ flag = File::NONBLOCK
25
+ if defined?(Fcntl::F_GETFL)
26
+ flag |= io.fcntl(Fcntl::F_GETFL)
27
+ end
28
+ io.fcntl(Fcntl::F_SETFL, flag)
29
+ end
30
+ module_function :set_non_blocking
31
+
32
+ ##
33
+ # Sets the close on exec flag for +io+
34
+ def set_close_on_exec(io)
35
+ if defined?(Fcntl::FD_CLOEXEC)
36
+ io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
37
+ end
38
+ end
39
+ module_function :set_close_on_exec
40
+
41
+ ##
42
+ # Changes the process's uid and gid to the ones of +user+
43
+ def su(user)
44
+ if defined?(Etc)
45
+ pw = Etc.getpwnam(user)
46
+ Process::initgroups(user, pw.gid)
47
+ Process::Sys::setgid(pw.gid)
48
+ Process::Sys::setuid(pw.uid)
49
+ else
50
+ warn("WEBrick::Utils::su doesn't work on this platform")
51
+ end
52
+ end
53
+ module_function :su
54
+
55
+ ##
56
+ # The server hostname
57
+ def getservername
58
+ host = Socket::gethostname
59
+ begin
60
+ Socket::gethostbyname(host)[0]
61
+ rescue
62
+ host
63
+ end
64
+ end
65
+ module_function :getservername
66
+
67
+ ##
68
+ # Creates TCP server sockets bound to +address+:+port+ and returns them.
69
+ #
70
+ # It will create IPV4 and IPV6 sockets on all interfaces.
71
+ def create_listeners(address, port, logger=nil)
72
+ unless port
73
+ raise ArgumentError, "must specify port"
74
+ end
75
+ res = Socket::getaddrinfo(address, port,
76
+ Socket::AF_UNSPEC, # address family
77
+ Socket::SOCK_STREAM, # socket type
78
+ 0, # protocol
79
+ Socket::AI_PASSIVE) # flag
80
+ last_error = nil
81
+ sockets = []
82
+ res.each{|ai|
83
+ begin
84
+ logger.debug("TCPServer.new(#{ai[3]}, #{port})") if logger
85
+ sock = TCPServer.new(ai[3], port)
86
+ port = sock.addr[1] if port == 0
87
+ Utils::set_close_on_exec(sock)
88
+ sockets << sock
89
+ rescue => ex
90
+ logger.warn("TCPServer Error: #{ex}") if logger
91
+ last_error = ex
92
+ end
93
+ }
94
+ raise last_error if sockets.empty?
95
+ return sockets
96
+ end
97
+ module_function :create_listeners
98
+
99
+ ##
100
+ # Characters used to generate random strings
101
+ RAND_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
102
+ "0123456789" +
103
+ "abcdefghijklmnopqrstuvwxyz"
104
+
105
+ ##
106
+ # Generates a random string of length +len+
107
+ def random_string(len)
108
+ rand_max = RAND_CHARS.bytesize
109
+ ret = ""
110
+ len.times{ ret << RAND_CHARS[rand(rand_max)] }
111
+ ret
112
+ end
113
+ module_function :random_string
114
+
115
+ ###########
116
+
117
+ require "thread"
118
+ require "timeout"
119
+ require "singleton"
120
+
121
+ ##
122
+ # Class used to manage timeout handlers across multiple threads.
123
+ #
124
+ # Timeout handlers should be managed by using the class methods which are
125
+ # synchronized.
126
+ #
127
+ # id = TimeoutHandler.register(10, Timeout::Error)
128
+ # begin
129
+ # sleep 20
130
+ # puts 'foo'
131
+ # ensure
132
+ # TimeoutHandler.cancel(id)
133
+ # end
134
+ #
135
+ # will raise Timeout::Error
136
+ #
137
+ # id = TimeoutHandler.register(10, Timeout::Error)
138
+ # begin
139
+ # sleep 5
140
+ # puts 'foo'
141
+ # ensure
142
+ # TimeoutHandler.cancel(id)
143
+ # end
144
+ #
145
+ # will print 'foo'
146
+ #
147
+ class TimeoutHandler
148
+ include Singleton
149
+
150
+ ##
151
+ # Mutex used to synchronize access across threads
152
+ TimeoutMutex = Mutex.new # :nodoc:
153
+
154
+ ##
155
+ # Registers a new timeout handler
156
+ #
157
+ # +time+:: Timeout in seconds
158
+ # +exception+:: Exception to raise when timeout elapsed
159
+ def TimeoutHandler.register(seconds, exception)
160
+ TimeoutMutex.synchronize{
161
+ instance.register(Thread.current, Time.now + seconds, exception)
162
+ }
163
+ end
164
+
165
+ ##
166
+ # Cancels the timeout handler +id+
167
+ def TimeoutHandler.cancel(id)
168
+ TimeoutMutex.synchronize{
169
+ instance.cancel(Thread.current, id)
170
+ }
171
+ end
172
+
173
+ def initialize
174
+ @timeout_info = Hash.new
175
+ Thread.start{
176
+ while true
177
+ now = Time.now
178
+ @timeout_info.each{|thread, ary|
179
+ ary.dup.each{|info|
180
+ time, exception = *info
181
+ interrupt(thread, info.object_id, exception) if time < now
182
+ }
183
+ }
184
+ sleep 0.5
185
+ end
186
+ }
187
+ end
188
+
189
+ ##
190
+ # Interrupts the timeout handler +id+ and raises +exception+
191
+ def interrupt(thread, id, exception)
192
+ TimeoutMutex.synchronize{
193
+ if cancel(thread, id) && thread.alive?
194
+ thread.raise(exception, "execution timeout")
195
+ end
196
+ }
197
+ end
198
+
199
+ ##
200
+ # Registers a new timeout handler
201
+ #
202
+ # +time+:: Timeout in seconds
203
+ # +exception+:: Exception to raise when timeout elapsed
204
+ def register(thread, time, exception)
205
+ @timeout_info[thread] ||= Array.new
206
+ @timeout_info[thread] << [time, exception]
207
+ return @timeout_info[thread].last.object_id
208
+ end
209
+
210
+ ##
211
+ # Cancels the timeout handler +id+
212
+ def cancel(thread, id)
213
+ if ary = @timeout_info[thread]
214
+ ary.delete_if{|info| info.object_id == id }
215
+ if ary.empty?
216
+ @timeout_info.delete(thread)
217
+ end
218
+ return true
219
+ end
220
+ return false
221
+ end
222
+ end
223
+
224
+ ##
225
+ # Executes the passed block and raises +exception+ if execution takes more
226
+ # than +seconds+.
227
+ #
228
+ # If +seconds+ is zero or nil, simply executes the block
229
+ def timeout(seconds, exception=Timeout::Error)
230
+ return yield if seconds.nil? or seconds.zero?
231
+ # raise ThreadError, "timeout within critical session" if Thread.critical
232
+ id = TimeoutHandler.register(seconds, exception)
233
+ begin
234
+ yield(seconds)
235
+ ensure
236
+ TimeoutHandler.cancel(id)
237
+ end
238
+ end
239
+ module_function :timeout
240
+ end
241
+ end
@@ -0,0 +1,13 @@
1
+ #--
2
+ # version.rb -- version and release date
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU
6
+ # Copyright (c) 2003 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: version.rb,v 1.74 2003/07/22 19:20:43 gotoyuzo Exp $
10
+
11
+ module WEBrick
12
+ VERSION = "1.3.1"
13
+ end
@@ -0,0 +1,66 @@
1
+ require "pp"
2
+
3
+ module DemoApplication
4
+ def initialize(config, enctype)
5
+ super
6
+ @enctype = enctype
7
+ end
8
+
9
+ def do_GET(req, res)
10
+ if req.path_info != "/"
11
+ res.set_redirect(WEBrick::HTTPStatus::Found, req.script_name + "/")
12
+ end
13
+ res.body =<<-_end_of_html_
14
+ <HTML>
15
+ <FORM method="POST" enctype=#{@enctype}>
16
+ text: <INPUT type="text" name="text"><BR>
17
+ file: <INPUT type="file" name="file"><BR>
18
+ check:
19
+ <INPUT type="checkbox" name="check" value="a">a,
20
+ <INPUT type="checkbox" name="check" value="b">b,
21
+ <INPUT type="checkbox" name="check" value="c">c,
22
+ <BR>
23
+ <INPUT type="submit">
24
+ </FORM>
25
+ </HTML>
26
+ _end_of_html_
27
+ res['content-type'] = 'text/html; charset=iso-8859-1'
28
+ end
29
+
30
+ def do_POST(req, res)
31
+ if req["content-length"].to_i > 1024*10
32
+ raise WEBrick::HTTPStatus::Forbidden, "file size too large"
33
+ end
34
+ res.body =<<-_end_of_html_
35
+ <HTML>
36
+ <H2>Query Parameters</H2>
37
+ #{display_query(req.query)}
38
+ <A href="#{req.path}">return</A>
39
+ <H2>Request</H2>
40
+ <PRE>#{WEBrick::HTMLUtils::escape(PP::pp(req, "", 80))}</PRE>
41
+ <H2>Response</H2>
42
+ <PRE>#{WEBrick::HTMLUtils::escape(PP::pp(res, "", 80))}</PRE>
43
+ </HTML>
44
+ _end_of_html_
45
+ res['content-type'] = 'text/html; charset=iso-8859-1'
46
+ end
47
+
48
+ private
49
+
50
+ def display_query(q)
51
+ ret = ""
52
+ q.each{|key, val|
53
+ ret << "<H3>#{WEBrick::HTMLUtils::escape(key)}</H3>"
54
+ ret << "<TABLE border=1>"
55
+ ret << make_tr("val", val.inspect)
56
+ ret << make_tr("val.to_a", val.to_a.inspect)
57
+ ret << make_tr("val.to_ary", val.to_ary.inspect)
58
+ ret << "</TABLE>"
59
+ }
60
+ ret
61
+ end
62
+
63
+ def make_tr(arg0, arg1)
64
+ "<TR><TD>#{arg0}</TD><TD>#{WEBrick::HTMLUtils::escape(arg1)}</TD></TR>"
65
+ end
66
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ require "webrick/cgi"
3
+ require "webrick/https" # should load if it runs on HTTPS server
4
+ require "./demo-app"
5
+
6
+ class DemoCGI < WEBrick::CGI
7
+ include DemoApplication
8
+ end
9
+
10
+ config = { :NPH => false }
11
+ cgi = DemoCGI.new(config, "multipart/form-data")
12
+ cgi.start
@@ -0,0 +1,6 @@
1
+ require "webrick"
2
+ require "./demo-app"
3
+
4
+ class DemoServlet < WEBrick::HTTPServlet::AbstractServlet
5
+ include DemoApplication
6
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ require "webrick/cgi"
3
+ require "webrick/https" # should load if it runs on HTTPS server
4
+ require "./demo-app"
5
+
6
+ class DemoCGI < WEBrick::CGI
7
+ include DemoApplication
8
+ end
9
+
10
+ config = { :NPH => false }
11
+ cgi = DemoCGI.new(config, "application/x-www-form-urlencoded")
12
+ cgi.start
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ require "webrick/cgi"
3
+
4
+ class HelloCGI < WEBrick::CGI
5
+ def do_GET(req, res)
6
+ res["content-type"] = "text/plain"
7
+ res.body = "Hello, world.\n"
8
+ end
9
+ end
10
+
11
+ HelloCGI.new.start
@@ -0,0 +1,8 @@
1
+ require "webrick"
2
+
3
+ class HelloServlet < WEBrick::HTTPServlet::AbstractServlet
4
+ def do_GET(req, res)
5
+ res["content-type"] = "text/plain"
6
+ res.body = "Hello, world.\n"
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ require "webrick"
2
+
3
+ httpd = WEBrick::HTTPServer.new(
4
+ :DocumentRoot => File::dirname(__FILE__),
5
+ :Port => 10080,
6
+ :Logger => WEBrick::Log.new($stderr, WEBrick::Log::DEBUG),
7
+ :AccessLog => [
8
+ [ $stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
9
+ [ $stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT ],
10
+ [ $stderr, WEBrick::AccessLog::AGENT_LOG_FORMAT ],
11
+ ],
12
+ :CGIPathEnv => ENV["PATH"] # PATH environment variable for CGI.
13
+ )
14
+
15
+ require "./hello"
16
+ httpd.mount("/hello", HelloServlet)
17
+
18
+ require "./demo-servlet"
19
+ httpd.mount("/urlencoded", DemoServlet, "application/x-www-form-urlencoded")
20
+ httpd.mount("/multipart", DemoServlet, "multipart/form-data")
21
+
22
+ trap(:INT){ httpd.shutdown }
23
+ httpd.start
@@ -0,0 +1,25 @@
1
+ require "webrick"
2
+ require "webrick/httpproxy"
3
+
4
+ # The :ProxyContentHandler proc will be invoked before sending a response to
5
+ # the User-Agent. You can inspect the pair of request and response messages
6
+ # (or edit the response message if necessary).
7
+
8
+ pch = Proc.new{|req, res|
9
+ p [ req.request_line, res.status_line ]
10
+ }
11
+
12
+ def upstream_proxy
13
+ if prx = ENV["http_proxy"]
14
+ return URI.parse(prx)
15
+ end
16
+ return nil
17
+ end
18
+
19
+ httpd = WEBrick::HTTPProxyServer.new(
20
+ :Port => 10080,
21
+ :ProxyContentHandler => pch,
22
+ :ProxyURI => upstream_proxy
23
+ )
24
+ Signal.trap(:INT){ httpd.shutdown }
25
+ httpd.start
@@ -0,0 +1,33 @@
1
+ require "webrick"
2
+ require "webrick/https"
3
+
4
+ hostname = WEBrick::Utils::getservername
5
+ subject = [["O", "ruby-lang.org"], ["OU", "sample"], ["CN", hostname]]
6
+ comment = "Comment for self-signed certificate"
7
+
8
+ httpd = WEBrick::HTTPServer.new(
9
+ :DocumentRoot => File::dirname(__FILE__),
10
+ :Port => 10443,
11
+ :SSLEnable => true,
12
+
13
+ # Specify key pair and server certificate.
14
+ # :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read("server.key")),
15
+ # :SSLCertificate => OpenSSL::X509::Certificate.new(File.read("server.crt")),
16
+
17
+ # specify the following SSL options if you want to use auto
18
+ # generated self-signed certificate.
19
+ :SSLCertName => subject,
20
+ :SSLComment => comment,
21
+
22
+ :CGIPathEnv => ENV["PATH"] # PATH environment variable for CGI.
23
+ )
24
+
25
+ require "./hello"
26
+ httpd.mount("/hello", HelloServlet)
27
+
28
+ require "./demo-servlet"
29
+ httpd.mount("/urlencoded", DemoServlet, "application/x-www-form-urlencoded")
30
+ httpd.mount("/multipart", DemoServlet, "multipart/form-data")
31
+
32
+ trap(:INT){ httpd.shutdown }
33
+ httpd.start