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,399 @@
1
+ #
2
+ # httpresponse.rb -- HTTPResponse 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: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $
10
+
11
+ require 'time'
12
+ require 'webrick/httpversion'
13
+ require 'webrick/htmlutils'
14
+ require 'webrick/httputils'
15
+ require 'webrick/httpstatus'
16
+
17
+ module WEBrick
18
+ ##
19
+ # An HTTP response.
20
+
21
+ class HTTPResponse
22
+ attr_reader :http_version, :status, :header
23
+ attr_reader :cookies
24
+ attr_accessor :reason_phrase
25
+
26
+ ##
27
+ # Body may be a String or IO subclass.
28
+
29
+ attr_accessor :body
30
+
31
+ attr_accessor :request_method, :request_uri, :request_http_version
32
+ attr_accessor :filename
33
+ attr_accessor :keep_alive
34
+ attr_reader :config, :sent_size
35
+
36
+ ##
37
+ # Creates a new HTTP response object
38
+
39
+ def initialize(config)
40
+ @config = config
41
+ @buffer_size = config[:OutputBufferSize]
42
+ @logger = config[:Logger]
43
+ @header = Hash.new
44
+ @status = HTTPStatus::RC_OK
45
+ @reason_phrase = nil
46
+ @http_version = HTTPVersion::convert(@config[:HTTPVersion])
47
+ @body = ''
48
+ @keep_alive = true
49
+ @cookies = []
50
+ @request_method = nil
51
+ @request_uri = nil
52
+ @request_http_version = @http_version # temporary
53
+ @chunked = false
54
+ @filename = nil
55
+ @sent_size = 0
56
+ end
57
+
58
+ ##
59
+ # The response's HTTP status line
60
+
61
+ def status_line
62
+ "HTTP/#@http_version #@status #@reason_phrase #{CRLF}"
63
+ end
64
+
65
+ ##
66
+ # Sets the response's status to the +status+ code
67
+
68
+ def status=(status)
69
+ @status = status
70
+ @reason_phrase = HTTPStatus::reason_phrase(status)
71
+ end
72
+
73
+ ##
74
+ # Retrieves the response header +field+
75
+
76
+ def [](field)
77
+ @header[field.downcase]
78
+ end
79
+
80
+ ##
81
+ # Sets the response header +field+ to +value+
82
+
83
+ def []=(field, value)
84
+ @header[field.downcase] = value.to_s
85
+ end
86
+
87
+ ##
88
+ # The content-length header
89
+
90
+ def content_length
91
+ if len = self['content-length']
92
+ return Integer(len)
93
+ end
94
+ end
95
+
96
+ ##
97
+ # Sets the content-length header to +len+
98
+
99
+ def content_length=(len)
100
+ self['content-length'] = len.to_s
101
+ end
102
+
103
+ ##
104
+ # The content-type header
105
+
106
+ def content_type
107
+ self['content-type']
108
+ end
109
+
110
+ ##
111
+ # Sets the content-type header to +type+
112
+
113
+ def content_type=(type)
114
+ self['content-type'] = type
115
+ end
116
+
117
+ ##
118
+ # Iterates over each header in the resopnse
119
+
120
+ def each
121
+ @header.each{|field, value| yield(field, value) }
122
+ end
123
+
124
+ ##
125
+ # Will this response body be returned using chunked transfer-encoding?
126
+
127
+ def chunked?
128
+ @chunked
129
+ end
130
+
131
+ ##
132
+ # Enables chunked transfer encoding.
133
+
134
+ def chunked=(val)
135
+ @chunked = val ? true : false
136
+ end
137
+
138
+ ##
139
+ # Will this response's connection be kept alive?
140
+
141
+ def keep_alive?
142
+ @keep_alive
143
+ end
144
+
145
+ ##
146
+ # Sends the response on +socket+
147
+
148
+ def send_response(socket)
149
+ begin
150
+ setup_header()
151
+ send_header(socket)
152
+ send_body(socket)
153
+ rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex
154
+ @logger.debug(ex)
155
+ @keep_alive = false
156
+ rescue Exception => ex
157
+ @logger.error(ex)
158
+ @keep_alive = false
159
+ end
160
+ end
161
+
162
+ ##
163
+ # Sets up the headers for sending
164
+
165
+ def setup_header()
166
+ @reason_phrase ||= HTTPStatus::reason_phrase(@status)
167
+ @header['server'] ||= @config[:ServerSoftware]
168
+ @header['date'] ||= Time.now.httpdate
169
+
170
+ # HTTP/0.9 features
171
+ if @request_http_version < "1.0"
172
+ @http_version = HTTPVersion.new("0.9")
173
+ @keep_alive = false
174
+ end
175
+
176
+ # HTTP/1.0 features
177
+ if @request_http_version < "1.1"
178
+ if chunked?
179
+ @chunked = false
180
+ ver = @request_http_version.to_s
181
+ msg = "chunked is set for an HTTP/#{ver} request. (ignored)"
182
+ @logger.warn(msg)
183
+ end
184
+ end
185
+
186
+ # Determine the message length (RFC2616 -- 4.4 Message Length)
187
+ if @status == 304 || @status == 204 || HTTPStatus::info?(@status)
188
+ @header.delete('content-length')
189
+ @body = ""
190
+ elsif chunked?
191
+ @header["transfer-encoding"] = "chunked"
192
+ @header.delete('content-length')
193
+ elsif %r{^multipart/byteranges} =~ @header['content-type']
194
+ @header.delete('content-length')
195
+ elsif @header['content-length'].nil?
196
+ unless @body.is_a?(IO)
197
+ @header['content-length'] = @body ? @body.bytesize : 0
198
+ end
199
+ end
200
+
201
+ # Keep-Alive connection.
202
+ if @header['connection'] == "close"
203
+ @keep_alive = false
204
+ elsif keep_alive?
205
+ if chunked? || @header['content-length'] || @status == 304 || @status == 204 || HTTPStatus.info?(@status)
206
+ @header['connection'] = "Keep-Alive"
207
+ else
208
+ msg = "Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true"
209
+ @logger.warn(msg)
210
+ @header['connection'] = "close"
211
+ @keep_alive = false
212
+ end
213
+ else
214
+ @header['connection'] = "close"
215
+ end
216
+
217
+ # Location is a single absoluteURI.
218
+ if location = @header['location']
219
+ if @request_uri
220
+ @header['location'] = @request_uri.merge(location)
221
+ end
222
+ end
223
+ end
224
+
225
+ ##
226
+ # Sends the headers on +socket+
227
+
228
+ def send_header(socket)
229
+ if @http_version.major > 0
230
+ data = status_line()
231
+ @header.each{|key, value|
232
+ tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }
233
+ data << "#{tmp}: #{value}" << CRLF
234
+ }
235
+ @cookies.each{|cookie|
236
+ data << "Set-Cookie: " << cookie.to_s << CRLF
237
+ }
238
+ data << CRLF
239
+ _write_data(socket, data)
240
+ end
241
+ end
242
+
243
+ ##
244
+ # Sends the body on +socket+
245
+
246
+ def send_body(socket)
247
+ case @body
248
+ when IO then send_body_io(socket)
249
+ else send_body_string(socket)
250
+ end
251
+ end
252
+
253
+ def to_s # :nodoc:
254
+ ret = ""
255
+ send_response(ret)
256
+ ret
257
+ end
258
+
259
+ ##
260
+ # Redirects to +url+ with a WEBrick::HTTPStatus::Redirect +status+.
261
+ #
262
+ # Example:
263
+ #
264
+ # res.set_redirect WEBrick::HTTPStatus::TemporaryRedirect
265
+
266
+ def set_redirect(status, url)
267
+ @body = "<HTML><A HREF=\"#{url.to_s}\">#{url.to_s}</A>.</HTML>\n"
268
+ @header['location'] = url.to_s
269
+ raise status
270
+ end
271
+
272
+ ##
273
+ # Creates an error page for exception +ex+ with an optional +backtrace+
274
+
275
+ def set_error(ex, backtrace=false)
276
+ case ex
277
+ when HTTPStatus::Status
278
+ @keep_alive = false if HTTPStatus::error?(ex.code)
279
+ self.status = ex.code
280
+ else
281
+ @keep_alive = false
282
+ self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR
283
+ end
284
+ @header['content-type'] = "text/html; charset=ISO-8859-1"
285
+
286
+ if respond_to?(:create_error_page)
287
+ create_error_page()
288
+ return
289
+ end
290
+
291
+ if @request_uri
292
+ host, port = @request_uri.host, @request_uri.port
293
+ else
294
+ host, port = @config[:ServerName], @config[:Port]
295
+ end
296
+
297
+ @body = ''
298
+ @body << <<-_end_of_html_
299
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
300
+ <HTML>
301
+ <HEAD><TITLE>#{HTMLUtils::escape(@reason_phrase)}</TITLE></HEAD>
302
+ <BODY>
303
+ <H1>#{HTMLUtils::escape(@reason_phrase)}</H1>
304
+ #{HTMLUtils::escape(ex.message)}
305
+ <HR>
306
+ _end_of_html_
307
+
308
+ if backtrace && $DEBUG
309
+ @body << "backtrace of `#{HTMLUtils::escape(ex.class.to_s)}' "
310
+ @body << "#{HTMLUtils::escape(ex.message)}"
311
+ @body << "<PRE>"
312
+ ex.backtrace.each{|line| @body << "\t#{line}\n"}
313
+ @body << "</PRE><HR>"
314
+ end
315
+
316
+ @body << <<-_end_of_html_
317
+ <ADDRESS>
318
+ #{HTMLUtils::escape(@config[:ServerSoftware])} at
319
+ #{host}:#{port}
320
+ </ADDRESS>
321
+ </BODY>
322
+ </HTML>
323
+ _end_of_html_
324
+ end
325
+
326
+ private
327
+
328
+ def send_body_io(socket)
329
+ begin
330
+ if @request_method == "HEAD"
331
+ # do nothing
332
+ elsif chunked?
333
+ while buf = @body.read(@buffer_size)
334
+ next if buf.empty?
335
+ data = ""
336
+ data << format("%x", buf.bytesize) << CRLF
337
+ data << buf << CRLF
338
+ _write_data(socket, data)
339
+ @sent_size += buf.bytesize
340
+ end
341
+ _write_data(socket, "0#{CRLF}#{CRLF}")
342
+ else
343
+ size = @header['content-length'].to_i
344
+ _send_file(socket, @body, 0, size)
345
+ @sent_size = size
346
+ end
347
+ ensure
348
+ @body.close
349
+ end
350
+ end
351
+
352
+ def send_body_string(socket)
353
+ if @request_method == "HEAD"
354
+ # do nothing
355
+ elsif chunked?
356
+ body ? @body.bytesize : 0
357
+ while buf = @body[@sent_size, @buffer_size]
358
+ break if buf.empty?
359
+ data = ""
360
+ data << format("%x", buf.bytesize) << CRLF
361
+ data << buf << CRLF
362
+ _write_data(socket, data)
363
+ @sent_size += buf.bytesize
364
+ end
365
+ _write_data(socket, "0#{CRLF}#{CRLF}")
366
+ else
367
+ if @body && @body.bytesize > 0
368
+ _write_data(socket, @body)
369
+ @sent_size = @body.bytesize
370
+ end
371
+ end
372
+ end
373
+
374
+ def _send_file(output, input, offset, size)
375
+ while offset > 0
376
+ sz = @buffer_size < size ? @buffer_size : size
377
+ buf = input.read(sz)
378
+ offset -= buf.bytesize
379
+ end
380
+
381
+ if size == 0
382
+ while buf = input.read(@buffer_size)
383
+ _write_data(output, buf)
384
+ end
385
+ else
386
+ while size > 0
387
+ sz = @buffer_size < size ? @buffer_size : size
388
+ buf = input.read(sz)
389
+ _write_data(output, buf)
390
+ size -= buf.bytesize
391
+ end
392
+ end
393
+ end
394
+
395
+ def _write_data(socket, data)
396
+ socket << data
397
+ end
398
+ end
399
+ end
@@ -0,0 +1,64 @@
1
+ #
2
+ # https.rb -- SSL/TLS enhancement for HTTPServer
3
+ #
4
+ # Author: IPR -- Internet Programming with Ruby -- writers
5
+ # Copyright (c) 2001 GOTOU Yuuzou
6
+ # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $
10
+
11
+ require 'webrick/ssl'
12
+
13
+ module WEBrick
14
+ module Config
15
+ HTTP.update(SSL)
16
+ end
17
+
18
+ class HTTPRequest
19
+ attr_reader :cipher, :server_cert, :client_cert
20
+
21
+ alias orig_parse parse
22
+
23
+ def parse(socket=nil)
24
+ if socket.respond_to?(:cert)
25
+ @server_cert = socket.cert || @config[:SSLCertificate]
26
+ @client_cert = socket.peer_cert
27
+ @client_cert_chain = socket.peer_cert_chain
28
+ @cipher = socket.cipher
29
+ end
30
+ orig_parse(socket)
31
+ end
32
+
33
+ alias orig_parse_uri parse_uri
34
+
35
+ def parse_uri(str, scheme="https")
36
+ if server_cert
37
+ return orig_parse_uri(str, scheme)
38
+ end
39
+ return orig_parse_uri(str)
40
+ end
41
+ private :parse_uri
42
+
43
+ alias orig_meta_vars meta_vars
44
+
45
+ def meta_vars
46
+ meta = orig_meta_vars
47
+ if server_cert
48
+ meta["HTTPS"] = "on"
49
+ meta["SSL_SERVER_CERT"] = @server_cert.to_pem
50
+ meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
51
+ if @client_cert_chain
52
+ @client_cert_chain.each_with_index{|cert, i|
53
+ meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem
54
+ }
55
+ end
56
+ meta["SSL_CIPHER"] = @cipher[0]
57
+ meta["SSL_PROTOCOL"] = @cipher[1]
58
+ meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s
59
+ meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s
60
+ end
61
+ meta
62
+ end
63
+ end
64
+ end