rubysl-webrick 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/lib/rubysl/webrick.rb +2 -0
  9. data/lib/rubysl/webrick/version.rb +5 -0
  10. data/lib/rubysl/webrick/webrick.rb +29 -0
  11. data/lib/webrick.rb +1 -0
  12. data/lib/webrick/accesslog.rb +67 -0
  13. data/lib/webrick/cgi.rb +257 -0
  14. data/lib/webrick/compat.rb +15 -0
  15. data/lib/webrick/config.rb +97 -0
  16. data/lib/webrick/cookie.rb +110 -0
  17. data/lib/webrick/htmlutils.rb +25 -0
  18. data/lib/webrick/httpauth.rb +45 -0
  19. data/lib/webrick/httpauth/authenticator.rb +79 -0
  20. data/lib/webrick/httpauth/basicauth.rb +65 -0
  21. data/lib/webrick/httpauth/digestauth.rb +343 -0
  22. data/lib/webrick/httpauth/htdigest.rb +91 -0
  23. data/lib/webrick/httpauth/htgroup.rb +61 -0
  24. data/lib/webrick/httpauth/htpasswd.rb +83 -0
  25. data/lib/webrick/httpauth/userdb.rb +29 -0
  26. data/lib/webrick/httpproxy.rb +254 -0
  27. data/lib/webrick/httprequest.rb +365 -0
  28. data/lib/webrick/httpresponse.rb +327 -0
  29. data/lib/webrick/https.rb +63 -0
  30. data/lib/webrick/httpserver.rb +210 -0
  31. data/lib/webrick/httpservlet.rb +22 -0
  32. data/lib/webrick/httpservlet/abstract.rb +71 -0
  33. data/lib/webrick/httpservlet/cgi_runner.rb +45 -0
  34. data/lib/webrick/httpservlet/cgihandler.rb +104 -0
  35. data/lib/webrick/httpservlet/erbhandler.rb +54 -0
  36. data/lib/webrick/httpservlet/filehandler.rb +398 -0
  37. data/lib/webrick/httpservlet/prochandler.rb +33 -0
  38. data/lib/webrick/httpstatus.rb +126 -0
  39. data/lib/webrick/httputils.rb +391 -0
  40. data/lib/webrick/httpversion.rb +49 -0
  41. data/lib/webrick/log.rb +88 -0
  42. data/lib/webrick/server.rb +200 -0
  43. data/lib/webrick/ssl.rb +126 -0
  44. data/lib/webrick/utils.rb +100 -0
  45. data/lib/webrick/version.rb +13 -0
  46. data/rubysl-webrick.gemspec +23 -0
  47. metadata +145 -0
@@ -0,0 +1,33 @@
1
+ #
2
+ # prochandler.rb -- ProcHandler Class
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: prochandler.rb,v 1.7 2002/09/21 12:23:42 gotoyuzo Exp $
10
+
11
+ require 'webrick/httpservlet/abstract.rb'
12
+
13
+ module WEBrick
14
+ module HTTPServlet
15
+
16
+ class ProcHandler < AbstractServlet
17
+ def get_instance(server, *options)
18
+ self
19
+ end
20
+
21
+ def initialize(proc)
22
+ @proc = proc
23
+ end
24
+
25
+ def do_GET(request, response)
26
+ @proc.call(request, response)
27
+ end
28
+
29
+ alias do_POST do_GET
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,126 @@
1
+ #
2
+ # httpstatus.rb -- HTTPStatus 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: httpstatus.rb,v 1.11 2003/03/24 20:18:55 gotoyuzo Exp $
10
+
11
+ module WEBrick
12
+
13
+ module HTTPStatus
14
+
15
+ class Status < StandardError; end
16
+ class Info < Status; end
17
+ class Success < Status; end
18
+ class Redirect < Status; end
19
+ class Error < Status; end
20
+ class ClientError < Error; end
21
+ class ServerError < Error; end
22
+
23
+ class EOFError < StandardError; end
24
+
25
+ StatusMessage = {
26
+ 100 => 'Continue',
27
+ 101 => 'Switching Protocols',
28
+ 200 => 'OK',
29
+ 201 => 'Created',
30
+ 202 => 'Accepted',
31
+ 203 => 'Non-Authoritative Information',
32
+ 204 => 'No Content',
33
+ 205 => 'Reset Content',
34
+ 206 => 'Partial Content',
35
+ 300 => 'Multiple Choices',
36
+ 301 => 'Moved Permanently',
37
+ 302 => 'Found',
38
+ 303 => 'See Other',
39
+ 304 => 'Not Modified',
40
+ 305 => 'Use Proxy',
41
+ 307 => 'Temporary Redirect',
42
+ 400 => 'Bad Request',
43
+ 401 => 'Unauthorized',
44
+ 402 => 'Payment Required',
45
+ 403 => 'Forbidden',
46
+ 404 => 'Not Found',
47
+ 405 => 'Method Not Allowed',
48
+ 406 => 'Not Acceptable',
49
+ 407 => 'Proxy Authentication Required',
50
+ 408 => 'Request Timeout',
51
+ 409 => 'Conflict',
52
+ 410 => 'Gone',
53
+ 411 => 'Length Required',
54
+ 412 => 'Precondition Failed',
55
+ 413 => 'Request Entity Too Large',
56
+ 414 => 'Request-URI Too Large',
57
+ 415 => 'Unsupported Media Type',
58
+ 416 => 'Request Range Not Satisfiable',
59
+ 417 => 'Expectation Failed',
60
+ 500 => 'Internal Server Error',
61
+ 501 => 'Not Implemented',
62
+ 502 => 'Bad Gateway',
63
+ 503 => 'Service Unavailable',
64
+ 504 => 'Gateway Timeout',
65
+ 505 => 'HTTP Version Not Supported'
66
+ }
67
+
68
+ CodeToError = {}
69
+
70
+ StatusMessage.each{|code, message|
71
+ var_name = message.gsub(/[ \-]/,'_').upcase
72
+ err_name = message.gsub(/[ \-]/,'')
73
+
74
+ case code
75
+ when 100...200; parent = Info
76
+ when 200...300; parent = Success
77
+ when 300...400; parent = Redirect
78
+ when 400...500; parent = ClientError
79
+ when 500...600; parent = ServerError
80
+ end
81
+
82
+ eval %-
83
+ RC_#{var_name} = #{code}
84
+ class #{err_name} < #{parent}
85
+ def self.code() RC_#{var_name} end
86
+ def self.reason_phrase() StatusMessage[code] end
87
+ def code() self::class::code end
88
+ def reason_phrase() self::class::reason_phrase end
89
+ alias to_i code
90
+ end
91
+ -
92
+
93
+ CodeToError[code] = const_get(err_name)
94
+ }
95
+
96
+ def reason_phrase(code)
97
+ StatusMessage[code.to_i]
98
+ end
99
+ def info?(code)
100
+ code.to_i >= 100 and code.to_i < 200
101
+ end
102
+ def success?(code)
103
+ code.to_i >= 200 and code.to_i < 300
104
+ end
105
+ def redirect?(code)
106
+ code.to_i >= 300 and code.to_i < 400
107
+ end
108
+ def error?(code)
109
+ code.to_i >= 400 and code.to_i < 600
110
+ end
111
+ def client_error?(code)
112
+ code.to_i >= 400 and code.to_i < 500
113
+ end
114
+ def server_error?(code)
115
+ code.to_i >= 500 and code.to_i < 600
116
+ end
117
+
118
+ def self.[](code)
119
+ CodeToError[code]
120
+ end
121
+
122
+ module_function :reason_phrase
123
+ module_function :info?, :success?, :redirect?, :error?
124
+ module_function :client_error?, :server_error?
125
+ end
126
+ end
@@ -0,0 +1,391 @@
1
+ #
2
+ # httputils.rb -- HTTPUtils Module
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: httputils.rb,v 1.34 2003/06/05 21:34:08 gotoyuzo Exp $
10
+
11
+ require 'socket'
12
+ require 'tempfile'
13
+
14
+ module WEBrick
15
+ CR = "\x0d"
16
+ LF = "\x0a"
17
+ CRLF = "\x0d\x0a"
18
+
19
+ module HTTPUtils
20
+
21
+ def normalize_path(path)
22
+ raise "abnormal path `#{path}'" if path[0] != ?/
23
+ ret = path.dup
24
+
25
+ ret.gsub!(%r{/+}o, '/') # // => /
26
+ while ret.sub!(%r'/\.(?:/|\Z)', '/'); end # /. => /
27
+ while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo
28
+
29
+ raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret
30
+ ret
31
+ end
32
+ module_function :normalize_path
33
+
34
+ #####
35
+
36
+ DefaultMimeTypes = {
37
+ "ai" => "application/postscript",
38
+ "asc" => "text/plain",
39
+ "avi" => "video/x-msvideo",
40
+ "bin" => "application/octet-stream",
41
+ "bmp" => "image/bmp",
42
+ "class" => "application/octet-stream",
43
+ "cer" => "application/pkix-cert",
44
+ "crl" => "application/pkix-crl",
45
+ "crt" => "application/x-x509-ca-cert",
46
+ #"crl" => "application/x-pkcs7-crl",
47
+ "css" => "text/css",
48
+ "dms" => "application/octet-stream",
49
+ "doc" => "application/msword",
50
+ "dvi" => "application/x-dvi",
51
+ "eps" => "application/postscript",
52
+ "etx" => "text/x-setext",
53
+ "exe" => "application/octet-stream",
54
+ "gif" => "image/gif",
55
+ "htm" => "text/html",
56
+ "html" => "text/html",
57
+ "jpe" => "image/jpeg",
58
+ "jpeg" => "image/jpeg",
59
+ "jpg" => "image/jpeg",
60
+ "lha" => "application/octet-stream",
61
+ "lzh" => "application/octet-stream",
62
+ "mov" => "video/quicktime",
63
+ "mpe" => "video/mpeg",
64
+ "mpeg" => "video/mpeg",
65
+ "mpg" => "video/mpeg",
66
+ "pbm" => "image/x-portable-bitmap",
67
+ "pdf" => "application/pdf",
68
+ "pgm" => "image/x-portable-graymap",
69
+ "png" => "image/png",
70
+ "pnm" => "image/x-portable-anymap",
71
+ "ppm" => "image/x-portable-pixmap",
72
+ "ppt" => "application/vnd.ms-powerpoint",
73
+ "ps" => "application/postscript",
74
+ "qt" => "video/quicktime",
75
+ "ras" => "image/x-cmu-raster",
76
+ "rb" => "text/plain",
77
+ "rd" => "text/plain",
78
+ "rtf" => "application/rtf",
79
+ "sgm" => "text/sgml",
80
+ "sgml" => "text/sgml",
81
+ "tif" => "image/tiff",
82
+ "tiff" => "image/tiff",
83
+ "txt" => "text/plain",
84
+ "xbm" => "image/x-xbitmap",
85
+ "xls" => "application/vnd.ms-excel",
86
+ "xml" => "text/xml",
87
+ "xpm" => "image/x-xpixmap",
88
+ "xwd" => "image/x-xwindowdump",
89
+ "zip" => "application/zip",
90
+ }
91
+
92
+ # Load Apache compatible mime.types file.
93
+ def load_mime_types(file)
94
+ open(file){ |io|
95
+ hash = Hash.new
96
+ io.each{ |line|
97
+ next if /^#/ =~ line
98
+ line.chomp!
99
+ mimetype, ext0 = line.split(/\s+/, 2)
100
+ next unless ext0
101
+ next if ext0.empty?
102
+ ext0.split(/\s+/).each{ |ext| hash[ext] = mimetype }
103
+ }
104
+ hash
105
+ }
106
+ end
107
+ module_function :load_mime_types
108
+
109
+ def mime_type(filename, mime_tab)
110
+ suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase)
111
+ suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ filename && $1.downcase)
112
+ mime_tab[suffix1] || mime_tab[suffix2] || "application/octet-stream"
113
+ end
114
+ module_function :mime_type
115
+
116
+ #####
117
+
118
+ def parse_header(raw)
119
+ header = Hash.new([].freeze)
120
+ field = nil
121
+ raw.each{|line|
122
+ case line
123
+ when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):\s*(.*?)\s*\z/om
124
+ field, value = $1, $2
125
+ field.downcase!
126
+ header[field] = [] unless header.has_key?(field)
127
+ header[field] << value
128
+ when /^\s+(.*?)\s*\z/om
129
+ value = $1
130
+ unless field
131
+ raise "bad header '#{line.inspect}'."
132
+ end
133
+ header[field][-1] << " " << value
134
+ else
135
+ raise "bad header '#{line.inspect}'."
136
+ end
137
+ }
138
+ header.each{|key, values|
139
+ values.each{|value|
140
+ value.strip!
141
+ value.gsub!(/\s+/, " ")
142
+ }
143
+ }
144
+ header
145
+ end
146
+ module_function :parse_header
147
+
148
+ def split_header_value(str)
149
+ str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+)
150
+ (?:,\s*|\Z)'xn).flatten
151
+ end
152
+ module_function :split_header_value
153
+
154
+ def parse_range_header(ranges_specifier)
155
+ if /^bytes=(.*)/ =~ ranges_specifier
156
+ byte_range_set = split_header_value($1)
157
+ byte_range_set.collect{|range_spec|
158
+ case range_spec
159
+ when /^(\d+)-(\d+)/ then $1.to_i .. $2.to_i
160
+ when /^(\d+)-/ then $1.to_i .. -1
161
+ when /^-(\d+)/ then -($1.to_i) .. -1
162
+ else return nil
163
+ end
164
+ }
165
+ end
166
+ end
167
+ module_function :parse_range_header
168
+
169
+ def parse_qvalues(value)
170
+ tmp = []
171
+ if value
172
+ parts = value.split(/,\s*/)
173
+ parts.each {|part|
174
+ if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
175
+ val = m[1]
176
+ q = (m[2] or 1).to_f
177
+ tmp.push([val, q])
178
+ end
179
+ }
180
+ tmp = tmp.sort_by{|val, q| -q}
181
+ tmp.collect!{|val, q| val}
182
+ end
183
+ return tmp
184
+ end
185
+ module_function :parse_qvalues
186
+
187
+ #####
188
+
189
+ def dequote(str)
190
+ ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
191
+ ret.gsub!(/\\(.)/, "\\1")
192
+ ret
193
+ end
194
+ module_function :dequote
195
+
196
+ def quote(str)
197
+ '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
198
+ end
199
+ module_function :quote
200
+
201
+ #####
202
+
203
+ class FormData < String
204
+ EmptyRawHeader = [].freeze
205
+ EmptyHeader = {}.freeze
206
+
207
+ attr_accessor :name, :filename, :next_data
208
+ protected :next_data
209
+
210
+ def initialize(*args)
211
+ @name = @filename = @next_data = nil
212
+ if args.empty?
213
+ @raw_header = []
214
+ @header = nil
215
+ super("")
216
+ else
217
+ @raw_header = EmptyRawHeader
218
+ @header = EmptyHeader
219
+ super(args.shift)
220
+ unless args.empty?
221
+ @next_data = self.class.new(*args)
222
+ end
223
+ end
224
+ end
225
+
226
+ def [](*key)
227
+ begin
228
+ @header[key[0].downcase].join(", ")
229
+ rescue StandardError, NameError
230
+ super
231
+ end
232
+ end
233
+
234
+ def <<(str)
235
+ if @header
236
+ super
237
+ elsif str == CRLF
238
+ @header = HTTPUtils::parse_header(@raw_header)
239
+ if cd = self['content-disposition']
240
+ if /\s+name="(.*?)"/ =~ cd then @name = $1 end
241
+ if /\s+filename="(.*?)"/ =~ cd then @filename = $1 end
242
+ end
243
+ else
244
+ @raw_header << str
245
+ end
246
+ self
247
+ end
248
+
249
+ def append_data(data)
250
+ tmp = self
251
+ while tmp
252
+ unless tmp.next_data
253
+ tmp.next_data = data
254
+ break
255
+ end
256
+ tmp = tmp.next_data
257
+ end
258
+ self
259
+ end
260
+
261
+ def each_data
262
+ tmp = self
263
+ while tmp
264
+ next_data = tmp.next_data
265
+ yield(tmp)
266
+ tmp = next_data
267
+ end
268
+ end
269
+
270
+ def list
271
+ ret = []
272
+ each_data{|data|
273
+ ret << data.to_s
274
+ }
275
+ ret
276
+ end
277
+
278
+ alias :to_ary :list
279
+
280
+ def to_s
281
+ String.new(self)
282
+ end
283
+ end
284
+
285
+ def parse_query(str)
286
+ query = Hash.new
287
+ if str
288
+ str.split(/[&;]/).each{|x|
289
+ next if x.empty?
290
+ key, val = x.split(/=/,2)
291
+ key = unescape_form(key)
292
+ val = unescape_form(val.to_s)
293
+ val = FormData.new(val)
294
+ val.name = key
295
+ if query.has_key?(key)
296
+ query[key].append_data(val)
297
+ next
298
+ end
299
+ query[key] = val
300
+ }
301
+ end
302
+ query
303
+ end
304
+ module_function :parse_query
305
+
306
+ def parse_form_data(io, boundary)
307
+ boundary_regexp = /\A--#{boundary}(--)?#{CRLF}\z/
308
+ form_data = Hash.new
309
+ return form_data unless io
310
+ data = nil
311
+ io.each{|line|
312
+ if boundary_regexp =~ line
313
+ if data
314
+ data.chop!
315
+ key = data.name
316
+ if form_data.has_key?(key)
317
+ form_data[key].append_data(data)
318
+ else
319
+ form_data[key] = data
320
+ end
321
+ end
322
+ data = FormData.new
323
+ next
324
+ else
325
+ if data
326
+ data << line
327
+ end
328
+ end
329
+ }
330
+ return form_data
331
+ end
332
+ module_function :parse_form_data
333
+
334
+ #####
335
+
336
+ reserved = ';/?:@&=+$,'
337
+ num = '0123456789'
338
+ lowalpha = 'abcdefghijklmnopqrstuvwxyz'
339
+ upalpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
340
+ mark = '-_.!~*\'()'
341
+ unreserved = num + lowalpha + upalpha + mark
342
+ control = (0x0..0x1f).collect{|c| c.chr }.join + "\x7f"
343
+ space = " "
344
+ delims = '<>#%"'
345
+ unwise = '{}|\\^[]`'
346
+ nonascii = (0x80..0xff).collect{|c| c.chr }.join
347
+
348
+ module_function
349
+
350
+ def _make_regex(str) /([#{Regexp.escape(str)}])/n end
351
+ def _make_regex!(str) /([^#{Regexp.escape(str)}])/n end
352
+ def _escape(str, regex) str.gsub(regex){ "%%%02X" % $1[0] } end
353
+ def _unescape(str, regex) str.gsub(regex){ $1.hex.chr } end
354
+
355
+ UNESCAPED = _make_regex(control+space+delims+unwise+nonascii)
356
+ UNESCAPED_FORM = _make_regex(reserved+control+delims+unwise+nonascii)
357
+ NONASCII = _make_regex(nonascii)
358
+ ESCAPED = /%([0-9a-fA-F]{2})/
359
+ UNESCAPED_PCHAR = _make_regex!(unreserved+":@&=+$,")
360
+
361
+ def escape(str)
362
+ _escape(str, UNESCAPED)
363
+ end
364
+
365
+ def unescape(str)
366
+ _unescape(str, ESCAPED)
367
+ end
368
+
369
+ def escape_form(str)
370
+ ret = _escape(str, UNESCAPED_FORM)
371
+ ret.gsub!(/ /, "+")
372
+ ret
373
+ end
374
+
375
+ def unescape_form(str)
376
+ _unescape(str.gsub(/\+/, " "), ESCAPED)
377
+ end
378
+
379
+ def escape_path(str)
380
+ result = ""
381
+ str.scan(%r{/([^/]*)}).each{|i|
382
+ result << "/" << _escape(i[0], UNESCAPED_PCHAR)
383
+ }
384
+ return result
385
+ end
386
+
387
+ def escape8bit(str)
388
+ _escape(str, NONASCII)
389
+ end
390
+ end
391
+ end