webrick 1.3.1 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +63 -0
  5. data/Rakefile +10 -0
  6. data/bin/console +14 -0
  7. data/bin/setup +8 -0
  8. data/lib/webrick.rb +7 -7
  9. data/lib/webrick/accesslog.rb +12 -6
  10. data/lib/webrick/cgi.rb +58 -5
  11. data/lib/webrick/compat.rb +2 -1
  12. data/lib/webrick/config.rb +47 -10
  13. data/lib/webrick/cookie.rb +69 -7
  14. data/lib/webrick/htmlutils.rb +4 -2
  15. data/lib/webrick/httpauth.rb +6 -5
  16. data/lib/webrick/httpauth/authenticator.rb +13 -8
  17. data/lib/webrick/httpauth/basicauth.rb +16 -8
  18. data/lib/webrick/httpauth/digestauth.rb +35 -32
  19. data/lib/webrick/httpauth/htdigest.rb +12 -8
  20. data/lib/webrick/httpauth/htgroup.rb +10 -6
  21. data/lib/webrick/httpauth/htpasswd.rb +46 -9
  22. data/lib/webrick/httpauth/userdb.rb +1 -0
  23. data/lib/webrick/httpproxy.rb +93 -48
  24. data/lib/webrick/httprequest.rb +201 -31
  25. data/lib/webrick/httpresponse.rb +235 -70
  26. data/lib/webrick/https.rb +90 -2
  27. data/lib/webrick/httpserver.rb +45 -15
  28. data/lib/webrick/httpservlet.rb +6 -5
  29. data/lib/webrick/httpservlet/abstract.rb +5 -6
  30. data/lib/webrick/httpservlet/cgi_runner.rb +3 -2
  31. data/lib/webrick/httpservlet/cgihandler.rb +29 -11
  32. data/lib/webrick/httpservlet/erbhandler.rb +4 -3
  33. data/lib/webrick/httpservlet/filehandler.rb +136 -65
  34. data/lib/webrick/httpservlet/prochandler.rb +15 -1
  35. data/lib/webrick/httpstatus.rb +24 -14
  36. data/lib/webrick/httputils.rb +134 -17
  37. data/lib/webrick/httpversion.rb +28 -1
  38. data/lib/webrick/log.rb +25 -5
  39. data/lib/webrick/server.rb +234 -74
  40. data/lib/webrick/ssl.rb +100 -12
  41. data/lib/webrick/utils.rb +98 -69
  42. data/lib/webrick/version.rb +6 -1
  43. data/webrick.gemspec +76 -0
  44. metadata +73 -72
  45. data/README.txt +0 -21
  46. data/sample/webrick/demo-app.rb +0 -66
  47. data/sample/webrick/demo-multipart.cgi +0 -12
  48. data/sample/webrick/demo-servlet.rb +0 -6
  49. data/sample/webrick/demo-urlencoded.cgi +0 -12
  50. data/sample/webrick/hello.cgi +0 -11
  51. data/sample/webrick/hello.rb +0 -8
  52. data/sample/webrick/httpd.rb +0 -23
  53. data/sample/webrick/httpproxy.rb +0 -25
  54. data/sample/webrick/httpsd.rb +0 -33
  55. data/test/openssl/utils.rb +0 -313
  56. data/test/ruby/envutil.rb +0 -208
  57. data/test/webrick/test_cgi.rb +0 -134
  58. data/test/webrick/test_cookie.rb +0 -131
  59. data/test/webrick/test_filehandler.rb +0 -285
  60. data/test/webrick/test_httpauth.rb +0 -167
  61. data/test/webrick/test_httpproxy.rb +0 -282
  62. data/test/webrick/test_httprequest.rb +0 -411
  63. data/test/webrick/test_httpresponse.rb +0 -49
  64. data/test/webrick/test_httpserver.rb +0 -305
  65. data/test/webrick/test_httputils.rb +0 -96
  66. data/test/webrick/test_httpversion.rb +0 -40
  67. data/test/webrick/test_server.rb +0 -67
  68. data/test/webrick/test_utils.rb +0 -64
  69. data/test/webrick/utils.rb +0 -58
  70. data/test/webrick/webrick.cgi +0 -36
  71. data/test/webrick/webrick_long_filename.cgi +0 -36
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # prochandler.rb -- ProcHandler Class
3
4
  #
@@ -8,12 +9,24 @@
8
9
  #
9
10
  # $IPR: prochandler.rb,v 1.7 2002/09/21 12:23:42 gotoyuzo Exp $
10
11
 
11
- require 'webrick/httpservlet/abstract.rb'
12
+ require_relative 'abstract'
12
13
 
13
14
  module WEBrick
14
15
  module HTTPServlet
15
16
 
17
+ ##
18
+ # Mounts a proc at a path that accepts a request and response.
19
+ #
20
+ # Instead of mounting this servlet with WEBrick::HTTPServer#mount use
21
+ # WEBrick::HTTPServer#mount_proc:
22
+ #
23
+ # server.mount_proc '/' do |req, res|
24
+ # res.body = 'it worked!'
25
+ # res.status = 200
26
+ # end
27
+
16
28
  class ProcHandler < AbstractServlet
29
+ # :stopdoc:
17
30
  def get_instance(server, *options)
18
31
  self
19
32
  end
@@ -27,6 +40,7 @@ module WEBrick
27
40
  end
28
41
 
29
42
  alias do_POST do_GET
43
+ # :startdoc:
30
44
  end
31
45
 
32
46
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #--
2
3
  # httpstatus.rb -- HTTPStatus Class
3
4
  #
@@ -8,6 +9,8 @@
8
9
  #
9
10
  # $IPR: httpstatus.rb,v 1.11 2003/03/24 20:18:55 gotoyuzo Exp $
10
11
 
12
+ require_relative 'accesslog'
13
+
11
14
  module WEBrick
12
15
 
13
16
  ##
@@ -20,26 +23,22 @@ module WEBrick
20
23
  ##
21
24
  # Root of the HTTP status class hierarchy
22
25
  class Status < StandardError
23
- def initialize(*args) # :nodoc:
24
- args[0] = AccessLog.escape(args[0]) unless args.empty?
25
- super(*args)
26
- end
27
26
  class << self
28
27
  attr_reader :code, :reason_phrase # :nodoc:
29
28
  end
30
-
29
+
31
30
  # Returns the HTTP status code
32
31
  def code() self::class::code end
33
-
32
+
34
33
  # Returns the HTTP status description
35
34
  def reason_phrase() self::class::reason_phrase end
36
-
35
+
37
36
  alias to_i code # :nodoc:
38
37
  end
39
38
 
40
39
  # Root of the HTTP info statuses
41
40
  class Info < Status; end
42
- # Root of the HTTP sucess statuses
41
+ # Root of the HTTP success statuses
43
42
  class Success < Status; end
44
43
  # Root of the HTTP redirect statuses
45
44
  class Redirect < Status; end
@@ -63,6 +62,7 @@ module WEBrick
63
62
  204 => 'No Content',
64
63
  205 => 'Reset Content',
65
64
  206 => 'Partial Content',
65
+ 207 => 'Multi-Status',
66
66
  300 => 'Multiple Choices',
67
67
  301 => 'Moved Permanently',
68
68
  302 => 'Found',
@@ -88,12 +88,22 @@ module WEBrick
88
88
  415 => 'Unsupported Media Type',
89
89
  416 => 'Request Range Not Satisfiable',
90
90
  417 => 'Expectation Failed',
91
+ 422 => 'Unprocessable Entity',
92
+ 423 => 'Locked',
93
+ 424 => 'Failed Dependency',
94
+ 426 => 'Upgrade Required',
95
+ 428 => 'Precondition Required',
96
+ 429 => 'Too Many Requests',
97
+ 431 => 'Request Header Fields Too Large',
98
+ 451 => 'Unavailable For Legal Reasons',
91
99
  500 => 'Internal Server Error',
92
100
  501 => 'Not Implemented',
93
101
  502 => 'Bad Gateway',
94
102
  503 => 'Service Unavailable',
95
103
  504 => 'Gateway Timeout',
96
- 505 => 'HTTP Version Not Supported'
104
+ 505 => 'HTTP Version Not Supported',
105
+ 507 => 'Insufficient Storage',
106
+ 511 => 'Network Authentication Required',
97
107
  }
98
108
 
99
109
  # Maps a status code to the corresponding Status class
@@ -136,31 +146,31 @@ module WEBrick
136
146
  def info?(code)
137
147
  code.to_i >= 100 and code.to_i < 200
138
148
  end
139
-
149
+
140
150
  ##
141
151
  # Is +code+ a successful status?
142
152
  def success?(code)
143
153
  code.to_i >= 200 and code.to_i < 300
144
154
  end
145
-
155
+
146
156
  ##
147
157
  # Is +code+ a redirection status?
148
158
  def redirect?(code)
149
159
  code.to_i >= 300 and code.to_i < 400
150
160
  end
151
-
161
+
152
162
  ##
153
163
  # Is +code+ an error status?
154
164
  def error?(code)
155
165
  code.to_i >= 400 and code.to_i < 600
156
166
  end
157
-
167
+
158
168
  ##
159
169
  # Is +code+ a client error status?
160
170
  def client_error?(code)
161
171
  code.to_i >= 400 and code.to_i < 500
162
172
  end
163
-
173
+
164
174
  ##
165
175
  # Is +code+ a server error status?
166
176
  def server_error?(code)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # httputils.rb -- HTTPUtils Module
3
4
  #
@@ -12,12 +13,21 @@ require 'socket'
12
13
  require 'tempfile'
13
14
 
14
15
  module WEBrick
15
- CR = "\x0d"
16
- LF = "\x0a"
17
- CRLF = "\x0d\x0a"
16
+ CR = "\x0d" # :nodoc:
17
+ LF = "\x0a" # :nodoc:
18
+ CRLF = "\x0d\x0a" # :nodoc:
19
+
20
+ ##
21
+ # HTTPUtils provides utility methods for working with the HTTP protocol.
22
+ #
23
+ # This module is generally used internally by WEBrick
18
24
 
19
25
  module HTTPUtils
20
26
 
27
+ ##
28
+ # Normalizes a request path. Raises an exception if the path cannot be
29
+ # normalized.
30
+
21
31
  def normalize_path(path)
22
32
  raise "abnormal path `#{path}'" if path[0] != ?/
23
33
  ret = path.dup
@@ -31,7 +41,8 @@ module WEBrick
31
41
  end
32
42
  module_function :normalize_path
33
43
 
34
- #####
44
+ ##
45
+ # Default mime types
35
46
 
36
47
  DefaultMimeTypes = {
37
48
  "ai" => "application/postscript",
@@ -58,6 +69,7 @@ module WEBrick
58
69
  "jpeg" => "image/jpeg",
59
70
  "jpg" => "image/jpeg",
60
71
  "js" => "application/javascript",
72
+ "json" => "application/json",
61
73
  "lha" => "application/octet-stream",
62
74
  "lzh" => "application/octet-stream",
63
75
  "mov" => "video/quicktime",
@@ -83,6 +95,7 @@ module WEBrick
83
95
  "tif" => "image/tiff",
84
96
  "tiff" => "image/tiff",
85
97
  "txt" => "text/plain",
98
+ "wasm" => "application/wasm",
86
99
  "xbm" => "image/x-xbitmap",
87
100
  "xhtml" => "text/html",
88
101
  "xls" => "application/vnd.ms-excel",
@@ -92,8 +105,12 @@ module WEBrick
92
105
  "zip" => "application/zip",
93
106
  }
94
107
 
95
- # Load Apache compatible mime.types file.
108
+ ##
109
+ # Loads Apache-compatible mime.types in +file+.
110
+
96
111
  def load_mime_types(file)
112
+ # note: +file+ may be a "| command" for now; some people may
113
+ # rely on this, but currently we do not use this method by default.
97
114
  open(file){ |io|
98
115
  hash = Hash.new
99
116
  io.each{ |line|
@@ -109,6 +126,10 @@ module WEBrick
109
126
  end
110
127
  module_function :load_mime_types
111
128
 
129
+ ##
130
+ # Returns the mime type of +filename+ from the list in +mime_tab+. If no
131
+ # mime type was found application/octet-stream is returned.
132
+
112
133
  def mime_type(filename, mime_tab)
113
134
  suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase)
114
135
  suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ filename && $1.downcase)
@@ -116,7 +137,9 @@ module WEBrick
116
137
  end
117
138
  module_function :mime_type
118
139
 
119
- #####
140
+ ##
141
+ # Parses an HTTP header +raw+ into a hash of header fields with an Array
142
+ # of values.
120
143
 
121
144
  def parse_header(raw)
122
145
  header = Hash.new([].freeze)
@@ -139,21 +162,24 @@ module WEBrick
139
162
  end
140
163
  }
141
164
  header.each{|key, values|
142
- values.each{|value|
143
- value.strip!
144
- value.gsub!(/\s+/, " ")
145
- }
165
+ values.each(&:strip!)
146
166
  }
147
167
  header
148
168
  end
149
169
  module_function :parse_header
150
170
 
171
+ ##
172
+ # Splits a header value +str+ according to HTTP specification.
173
+
151
174
  def split_header_value(str)
152
175
  str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+)
153
176
  (?:,\s*|\Z)'xn).flatten
154
177
  end
155
178
  module_function :split_header_value
156
179
 
180
+ ##
181
+ # Parses a Range header value +ranges_specifier+
182
+
157
183
  def parse_range_header(ranges_specifier)
158
184
  if /^bytes=(.*)/ =~ ranges_specifier
159
185
  byte_range_set = split_header_value($1)
@@ -169,6 +195,9 @@ module WEBrick
169
195
  end
170
196
  module_function :parse_range_header
171
197
 
198
+ ##
199
+ # Parses q values in +value+ as used in Accept headers.
200
+
172
201
  def parse_qvalues(value)
173
202
  tmp = []
174
203
  if value
@@ -187,7 +216,8 @@ module WEBrick
187
216
  end
188
217
  module_function :parse_qvalues
189
218
 
190
- #####
219
+ ##
220
+ # Removes quotes and escapes from +str+
191
221
 
192
222
  def dequote(str)
193
223
  ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
@@ -196,20 +226,43 @@ module WEBrick
196
226
  end
197
227
  module_function :dequote
198
228
 
229
+ ##
230
+ # Quotes and escapes quotes in +str+
231
+
199
232
  def quote(str)
200
233
  '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
201
234
  end
202
235
  module_function :quote
203
236
 
204
- #####
237
+ ##
238
+ # Stores multipart form data. FormData objects are created when
239
+ # WEBrick::HTTPUtils.parse_form_data is called.
205
240
 
206
241
  class FormData < String
207
- EmptyRawHeader = [].freeze
208
- EmptyHeader = {}.freeze
242
+ EmptyRawHeader = [].freeze # :nodoc:
243
+ EmptyHeader = {}.freeze # :nodoc:
244
+
245
+ ##
246
+ # The name of the form data part
247
+
248
+ attr_accessor :name
209
249
 
210
- attr_accessor :name, :filename, :next_data
250
+ ##
251
+ # The filename of the form data part
252
+
253
+ attr_accessor :filename
254
+
255
+ attr_accessor :next_data # :nodoc:
211
256
  protected :next_data
212
257
 
258
+ ##
259
+ # Creates a new FormData object.
260
+ #
261
+ # +args+ is an Array of form data entries. One FormData will be created
262
+ # for each entry.
263
+ #
264
+ # This is called by WEBrick::HTTPUtils.parse_form_data for you
265
+
213
266
  def initialize(*args)
214
267
  @name = @filename = @next_data = nil
215
268
  if args.empty?
@@ -226,6 +279,9 @@ module WEBrick
226
279
  end
227
280
  end
228
281
 
282
+ ##
283
+ # Retrieves the header at the first entry in +key+
284
+
229
285
  def [](*key)
230
286
  begin
231
287
  @header[key[0].downcase].join(", ")
@@ -234,6 +290,12 @@ module WEBrick
234
290
  end
235
291
  end
236
292
 
293
+ ##
294
+ # Adds +str+ to this FormData which may be the body, a header or a
295
+ # header entry.
296
+ #
297
+ # This is called by WEBrick::HTTPUtils.parse_form_data for you
298
+
237
299
  def <<(str)
238
300
  if @header
239
301
  super
@@ -249,6 +311,11 @@ module WEBrick
249
311
  self
250
312
  end
251
313
 
314
+ ##
315
+ # Adds +data+ at the end of the chain of entries
316
+ #
317
+ # This is called by WEBrick::HTTPUtils.parse_form_data for you.
318
+
252
319
  def append_data(data)
253
320
  tmp = self
254
321
  while tmp
@@ -261,6 +328,9 @@ module WEBrick
261
328
  self
262
329
  end
263
330
 
331
+ ##
332
+ # Yields each entry in this FormData
333
+
264
334
  def each_data
265
335
  tmp = self
266
336
  while tmp
@@ -270,6 +340,9 @@ module WEBrick
270
340
  end
271
341
  end
272
342
 
343
+ ##
344
+ # Returns all the FormData as an Array
345
+
273
346
  def list
274
347
  ret = []
275
348
  each_data{|data|
@@ -278,13 +351,22 @@ module WEBrick
278
351
  ret
279
352
  end
280
353
 
354
+ ##
355
+ # A FormData will behave like an Array
356
+
281
357
  alias :to_ary :list
282
358
 
359
+ ##
360
+ # This FormData's body
361
+
283
362
  def to_s
284
363
  String.new(self)
285
364
  end
286
365
  end
287
366
 
367
+ ##
368
+ # Parses the query component of a URI in +str+
369
+
288
370
  def parse_query(str)
289
371
  query = Hash.new
290
372
  if str
@@ -306,6 +388,9 @@ module WEBrick
306
388
  end
307
389
  module_function :parse_query
308
390
 
391
+ ##
392
+ # Parses form data in +io+ with the given +boundary+
393
+
309
394
  def parse_form_data(io, boundary)
310
395
  boundary_regexp = /\A--#{Regexp.quote(boundary)}(--)?#{CRLF}\z/
311
396
  form_data = Hash.new
@@ -350,10 +435,22 @@ module WEBrick
350
435
 
351
436
  module_function
352
437
 
438
+ # :stopdoc:
439
+
353
440
  def _make_regex(str) /([#{Regexp.escape(str)}])/n end
354
441
  def _make_regex!(str) /([^#{Regexp.escape(str)}])/n end
355
- def _escape(str, regex) str.gsub(regex){ "%%%02X" % $1.ord } end
356
- def _unescape(str, regex) str.gsub(regex){ $1.hex.chr } end
442
+ def _escape(str, regex)
443
+ str = str.b
444
+ str.gsub!(regex) {"%%%02X" % $1.ord}
445
+ # %-escaped string should contain US-ASCII only
446
+ str.force_encoding(Encoding::US_ASCII)
447
+ end
448
+ def _unescape(str, regex)
449
+ str = str.b
450
+ str.gsub!(regex) {$1.hex.chr}
451
+ # encoding of %-unescaped string is unknown
452
+ str
453
+ end
357
454
 
358
455
  UNESCAPED = _make_regex(control+space+delims+unwise+nonascii)
359
456
  UNESCAPED_FORM = _make_regex(reserved+control+delims+unwise+nonascii)
@@ -361,24 +458,41 @@ module WEBrick
361
458
  ESCAPED = /%([0-9a-fA-F]{2})/
362
459
  UNESCAPED_PCHAR = _make_regex!(unreserved+":@&=+$,")
363
460
 
461
+ # :startdoc:
462
+
463
+ ##
464
+ # Escapes HTTP reserved and unwise characters in +str+
465
+
364
466
  def escape(str)
365
467
  _escape(str, UNESCAPED)
366
468
  end
367
469
 
470
+ ##
471
+ # Unescapes HTTP reserved and unwise characters in +str+
472
+
368
473
  def unescape(str)
369
474
  _unescape(str, ESCAPED)
370
475
  end
371
476
 
477
+ ##
478
+ # Escapes form reserved characters in +str+
479
+
372
480
  def escape_form(str)
373
481
  ret = _escape(str, UNESCAPED_FORM)
374
482
  ret.gsub!(/ /, "+")
375
483
  ret
376
484
  end
377
485
 
486
+ ##
487
+ # Unescapes form reserved characters in +str+
488
+
378
489
  def unescape_form(str)
379
490
  _unescape(str.gsub(/\+/, " "), ESCAPED)
380
491
  end
381
492
 
493
+ ##
494
+ # Escapes path +str+
495
+
382
496
  def escape_path(str)
383
497
  result = ""
384
498
  str.scan(%r{/([^/]*)}).each{|i|
@@ -387,6 +501,9 @@ module WEBrick
387
501
  return result
388
502
  end
389
503
 
504
+ ##
505
+ # Escapes 8 bit characters in +str+
506
+
390
507
  def escape8bit(str)
391
508
  _escape(str, NONASCII)
392
509
  end