rubysl-webrick 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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