webrick 1.3.1 → 1.6.1

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.

Potentially problematic release.


This version of webrick might be problematic. Click here for more details.

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