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,264 @@
1
+ #
2
+ # httpserver.rb -- HTTPServer Class
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
6
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: httpserver.rb,v 1.63 2002/10/01 17:16:32 gotoyuzo Exp $
10
+
11
+ require 'webrick/server'
12
+ require 'webrick/httputils'
13
+ require 'webrick/httpstatus'
14
+ require 'webrick/httprequest'
15
+ require 'webrick/httpresponse'
16
+ require 'webrick/httpservlet'
17
+ require 'webrick/accesslog'
18
+
19
+ module WEBrick
20
+ class HTTPServerError < ServerError; end
21
+
22
+ ##
23
+ # An HTTP Server
24
+
25
+ class HTTPServer < ::WEBrick::GenericServer
26
+ ##
27
+ # Creates a new HTTP server according to +config+
28
+ #
29
+ # An HTTP server uses the following attributes:
30
+ #
31
+ # :AccessLog:: An array of access logs. See WEBrick::AccessLog
32
+ # :BindAddress:: Local address for the server to bind to
33
+ # :DocumentRoot:: Root path to serve files from
34
+ # :DocumentRootOptions:: Options for the default HTTPServlet::FileHandler
35
+ # :HTTPVersion:: The HTTP version of this server
36
+ # :Port:: Port to listen on
37
+ # :RequestCallback:: Called with a request and response before each
38
+ # request is serviced.
39
+ # :RequestTimeout:: Maximum time to wait between requests
40
+ # :ServerAlias:: Array of alternate names for this server for virtual
41
+ # hosting
42
+ # :ServerName:: Name for this server for virtual hosting
43
+
44
+ def initialize(config={}, default=Config::HTTP)
45
+ super(config, default)
46
+ @http_version = HTTPVersion::convert(@config[:HTTPVersion])
47
+
48
+ @mount_tab = MountTable.new
49
+ if @config[:DocumentRoot]
50
+ mount("/", HTTPServlet::FileHandler, @config[:DocumentRoot],
51
+ @config[:DocumentRootOptions])
52
+ end
53
+
54
+ unless @config[:AccessLog]
55
+ @config[:AccessLog] = [
56
+ [ $stderr, AccessLog::COMMON_LOG_FORMAT ],
57
+ [ $stderr, AccessLog::REFERER_LOG_FORMAT ]
58
+ ]
59
+ end
60
+
61
+ @virtual_hosts = Array.new
62
+ end
63
+
64
+ ##
65
+ # Processes requests on +sock+
66
+
67
+ def run(sock)
68
+ while true
69
+ res = HTTPResponse.new(@config)
70
+ req = HTTPRequest.new(@config)
71
+ server = self
72
+ begin
73
+ timeout = @config[:RequestTimeout]
74
+ while timeout > 0
75
+ break if IO.select([sock], nil, nil, 0.5)
76
+ timeout = 0 if @status != :Running
77
+ timeout -= 0.5
78
+ end
79
+ raise HTTPStatus::EOFError if timeout <= 0
80
+ raise HTTPStatus::EOFError if sock.eof?
81
+ req.parse(sock)
82
+ res.request_method = req.request_method
83
+ res.request_uri = req.request_uri
84
+ res.request_http_version = req.http_version
85
+ res.keep_alive = req.keep_alive?
86
+ server = lookup_server(req) || self
87
+ if callback = server[:RequestCallback]
88
+ callback.call(req, res)
89
+ elsif callback = server[:RequestHandler]
90
+ msg = ":RequestHandler is deprecated, please use :RequestCallback"
91
+ @logger.warn(msg)
92
+ callback.call(req, res)
93
+ end
94
+ server.service(req, res)
95
+ rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
96
+ res.set_error(ex)
97
+ rescue HTTPStatus::Error => ex
98
+ @logger.error(ex.message)
99
+ res.set_error(ex)
100
+ rescue HTTPStatus::Status => ex
101
+ res.status = ex.code
102
+ rescue StandardError => ex
103
+ @logger.error(ex)
104
+ res.set_error(ex, true)
105
+ ensure
106
+ if req.request_line
107
+ if req.keep_alive? && res.keep_alive?
108
+ req.fixup()
109
+ end
110
+ res.send_response(sock)
111
+ server.access_log(@config, req, res)
112
+ end
113
+ end
114
+ break if @http_version < "1.1"
115
+ break unless req.keep_alive?
116
+ break unless res.keep_alive?
117
+ end
118
+ end
119
+
120
+ ##
121
+ # Services +req+ and fills in +res+
122
+
123
+ def service(req, res)
124
+ if req.unparsed_uri == "*"
125
+ if req.request_method == "OPTIONS"
126
+ do_OPTIONS(req, res)
127
+ raise HTTPStatus::OK
128
+ end
129
+ raise HTTPStatus::NotFound, "`#{req.unparsed_uri}' not found."
130
+ end
131
+
132
+ servlet, options, script_name, path_info = search_servlet(req.path)
133
+ raise HTTPStatus::NotFound, "`#{req.path}' not found." unless servlet
134
+ req.script_name = script_name
135
+ req.path_info = path_info
136
+ si = servlet.get_instance(self, *options)
137
+ @logger.debug(format("%s is invoked.", si.class.name))
138
+ si.service(req, res)
139
+ end
140
+
141
+ def do_OPTIONS(req, res)
142
+ res["allow"] = "GET,HEAD,POST,OPTIONS"
143
+ end
144
+
145
+ ##
146
+ # Mounts +servlet+ on +dir+ passing +options+ to the servlet at creation
147
+ # time
148
+
149
+ def mount(dir, servlet, *options)
150
+ @logger.debug(sprintf("%s is mounted on %s.", servlet.inspect, dir))
151
+ @mount_tab[dir] = [ servlet, options ]
152
+ end
153
+
154
+ ##
155
+ # Mounts +proc+ or +block+ on +dir+ and calls it with a
156
+ # WEBrick::HTTPRequest and WEBrick::HTTPResponse
157
+
158
+ def mount_proc(dir, proc=nil, &block)
159
+ proc ||= block
160
+ raise HTTPServerError, "must pass a proc or block" unless proc
161
+ mount(dir, HTTPServlet::ProcHandler.new(proc))
162
+ end
163
+
164
+ ##
165
+ # Unmounts +dir+
166
+
167
+ def unmount(dir)
168
+ @logger.debug(sprintf("unmount %s.", dir))
169
+ @mount_tab.delete(dir)
170
+ end
171
+ alias umount unmount
172
+
173
+ ##
174
+ # Finds a servlet for +path+
175
+
176
+ def search_servlet(path)
177
+ script_name, path_info = @mount_tab.scan(path)
178
+ servlet, options = @mount_tab[script_name]
179
+ if servlet
180
+ [ servlet, options, script_name, path_info ]
181
+ end
182
+ end
183
+
184
+ ##
185
+ # Adds +server+ as a virtual host.
186
+
187
+ def virtual_host(server)
188
+ @virtual_hosts << server
189
+ @virtual_hosts = @virtual_hosts.sort_by{|s|
190
+ num = 0
191
+ num -= 4 if s[:BindAddress]
192
+ num -= 2 if s[:Port]
193
+ num -= 1 if s[:ServerName]
194
+ num
195
+ }
196
+ end
197
+
198
+ ##
199
+ # Finds the appropriate virtual host to handle +req+
200
+
201
+ def lookup_server(req)
202
+ @virtual_hosts.find{|s|
203
+ (s[:BindAddress].nil? || req.addr[3] == s[:BindAddress]) &&
204
+ (s[:Port].nil? || req.port == s[:Port]) &&
205
+ ((s[:ServerName].nil? || req.host == s[:ServerName]) ||
206
+ (!s[:ServerAlias].nil? && s[:ServerAlias].find{|h| h === req.host}))
207
+ }
208
+ end
209
+
210
+ def access_log(config, req, res)
211
+ param = AccessLog::setup_params(config, req, res)
212
+ @config[:AccessLog].each{|logger, fmt|
213
+ logger << AccessLog::format(fmt+"\n", param)
214
+ }
215
+ end
216
+
217
+ class MountTable
218
+ def initialize
219
+ @tab = Hash.new
220
+ compile
221
+ end
222
+
223
+ def [](dir)
224
+ dir = normalize(dir)
225
+ @tab[dir]
226
+ end
227
+
228
+ def []=(dir, val)
229
+ dir = normalize(dir)
230
+ @tab[dir] = val
231
+ compile
232
+ val
233
+ end
234
+
235
+ def delete(dir)
236
+ dir = normalize(dir)
237
+ res = @tab.delete(dir)
238
+ compile
239
+ res
240
+ end
241
+
242
+ def scan(path)
243
+ @scanner =~ path
244
+ [ $&, $' ]
245
+ end
246
+
247
+ private
248
+
249
+ def compile
250
+ k = @tab.keys
251
+ k.sort!
252
+ k.reverse!
253
+ k.collect!{|path| Regexp.escape(path) }
254
+ @scanner = Regexp.new("^(" + k.join("|") +")(?=/|$)")
255
+ end
256
+
257
+ def normalize(dir)
258
+ ret = dir ? dir.dup : ""
259
+ ret.sub!(%r|/+$|, "")
260
+ ret
261
+ end
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,22 @@
1
+ #
2
+ # httpservlet.rb -- HTTPServlet Utility File
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
6
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: httpservlet.rb,v 1.21 2003/02/23 12:24:46 gotoyuzo Exp $
10
+
11
+ require 'webrick/httpservlet/abstract'
12
+ require 'webrick/httpservlet/filehandler'
13
+ require 'webrick/httpservlet/cgihandler'
14
+ require 'webrick/httpservlet/erbhandler'
15
+ require 'webrick/httpservlet/prochandler'
16
+
17
+ module WEBrick
18
+ module HTTPServlet
19
+ FileHandler.add_handler("cgi", CGIHandler)
20
+ FileHandler.add_handler("rhtml", ERBHandler)
21
+ end
22
+ end
@@ -0,0 +1,153 @@
1
+ #
2
+ # httpservlet.rb -- HTTPServlet Module
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU Yuuzou
6
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $
10
+
11
+ require 'thread'
12
+
13
+ require 'webrick/htmlutils'
14
+ require 'webrick/httputils'
15
+ require 'webrick/httpstatus'
16
+
17
+ module WEBrick
18
+ module HTTPServlet
19
+ class HTTPServletError < StandardError; end
20
+
21
+ ##
22
+ # AbstractServlet allows HTTP server modules to be reused across multiple
23
+ # servers and allows encapsulation of functionality.
24
+ #
25
+ # By default a servlet will respond to GET, HEAD (through an alias to GET)
26
+ # and OPTIONS requests.
27
+ #
28
+ # By default a new servlet is initialized for every request. A servlet
29
+ # instance can be reused by overriding ::get_instance in the
30
+ # AbstractServlet subclass.
31
+ #
32
+ # == A Simple Servlet
33
+ #
34
+ # class Simple < WEBrick::HTTPServlet::AbstractServlet
35
+ # def do_GET request, response
36
+ # status, content_type, body = do_stuff_with request
37
+ #
38
+ # response.status = status
39
+ # response['Content-Type'] = content_type
40
+ # response.body = body
41
+ # end
42
+ #
43
+ # def do_stuff_with request
44
+ # return 200, 'text/plain', 'you got a page'
45
+ # end
46
+ # end
47
+ #
48
+ # This servlet can be mounted on a server at a given path:
49
+ #
50
+ # server.mount '/simple', Simple
51
+ #
52
+ # == Servlet Configuration
53
+ #
54
+ # Servlets can be configured via initialize. The first argument is the
55
+ # HTTP server the servlet is being initialized for.
56
+ #
57
+ # class Configureable < Simple
58
+ # def initialize server, color, size
59
+ # super server
60
+ # @color = color
61
+ # @size = size
62
+ # end
63
+ #
64
+ # def do_stuff_with request
65
+ # content = "<p " \
66
+ # %q{style="color: #{@color}; font-size: #{@size}"} \
67
+ # ">Hello, World!"
68
+ #
69
+ # return 200, "text/html", content
70
+ # end
71
+ # end
72
+ #
73
+ # This servlet must be provided two arguments at mount time:
74
+ #
75
+ # server.mount '/configurable', Configurable, 'red', '2em'
76
+
77
+ class AbstractServlet
78
+
79
+ ##
80
+ # Factory for servlet instances that will handle a request from +server+
81
+ # using +options+ from the mount point. By default a new servlet
82
+ # instance is created for every call.
83
+
84
+ def self.get_instance(server, *options)
85
+ self.new(server, *options)
86
+ end
87
+
88
+ ##
89
+ # Initializes a new servlet for +server+ using +options+ which are
90
+ # stored as-is in +@options+. +@logger+ is also provided.
91
+
92
+ def initialize(server, *options)
93
+ @server = @config = server
94
+ @logger = @server[:Logger]
95
+ @options = options
96
+ end
97
+
98
+ ##
99
+ # Dispatches to a +do_+ method based on +req+ if such a method is
100
+ # available. (+do_GET+ for a GET request). Raises a MethodNotAllowed
101
+ # exception if the method is not implemented.
102
+
103
+ def service(req, res)
104
+ method_name = "do_" + req.request_method.gsub(/-/, "_")
105
+ if respond_to?(method_name)
106
+ __send__(method_name, req, res)
107
+ else
108
+ raise HTTPStatus::MethodNotAllowed,
109
+ "unsupported method `#{req.request_method}'."
110
+ end
111
+ end
112
+
113
+ ##
114
+ # Raises a NotFound exception
115
+
116
+ def do_GET(req, res)
117
+ raise HTTPStatus::NotFound, "not found."
118
+ end
119
+
120
+ ##
121
+ # Dispatches to do_GET
122
+
123
+ def do_HEAD(req, res)
124
+ do_GET(req, res)
125
+ end
126
+
127
+ ##
128
+ # Returns the allowed HTTP request methods
129
+
130
+ def do_OPTIONS(req, res)
131
+ m = self.methods.grep(/\Ado_([A-Z]+)\z/) {$1}
132
+ m.sort!
133
+ res["allow"] = m.join(",")
134
+ end
135
+
136
+ private
137
+
138
+ ##
139
+ # Redirects to a path ending in /
140
+
141
+ def redirect_to_directory_uri(req, res)
142
+ if req.path[-1] != ?/
143
+ location = WEBrick::HTTPUtils.escape_path(req.path + "/")
144
+ if req.query_string && req.query_string.bytesize > 0
145
+ location << "?" << req.query_string
146
+ end
147
+ res.set_redirect(HTTPStatus::MovedPermanently, location)
148
+ end
149
+ end
150
+ end
151
+
152
+ end
153
+ end
@@ -0,0 +1,46 @@
1
+ #
2
+ # cgi_runner.rb -- CGI launcher.
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU
6
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: cgi_runner.rb,v 1.9 2002/09/25 11:33:15 gotoyuzo Exp $
10
+
11
+ def sysread(io, size)
12
+ buf = ""
13
+ while size > 0
14
+ tmp = io.sysread(size)
15
+ buf << tmp
16
+ size -= tmp.bytesize
17
+ end
18
+ return buf
19
+ end
20
+
21
+ STDIN.binmode
22
+
23
+ len = sysread(STDIN, 8).to_i
24
+ out = sysread(STDIN, len)
25
+ STDOUT.reopen(open(out, "w"))
26
+
27
+ len = sysread(STDIN, 8).to_i
28
+ err = sysread(STDIN, len)
29
+ STDERR.reopen(open(err, "w"))
30
+
31
+ len = sysread(STDIN, 8).to_i
32
+ dump = sysread(STDIN, len)
33
+ hash = Marshal.restore(dump)
34
+ ENV.keys.each{|name| ENV.delete(name) }
35
+ hash.each{|k, v| ENV[k] = v if v }
36
+
37
+ dir = File::dirname(ENV["SCRIPT_FILENAME"])
38
+ Dir::chdir dir
39
+
40
+ if ARGV[0]
41
+ argv = ARGV.dup
42
+ argv << ENV["SCRIPT_FILENAME"]
43
+ exec(*argv)
44
+ # NOTREACHED
45
+ end
46
+ exec ENV["SCRIPT_FILENAME"]