webrick 1.3.1 → 1.4.3

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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/lib/webrick.rb +6 -6
  3. data/lib/webrick/accesslog.rb +9 -1
  4. data/lib/webrick/cgi.rb +58 -5
  5. data/lib/webrick/compat.rb +2 -1
  6. data/lib/webrick/config.rb +47 -10
  7. data/lib/webrick/cookie.rb +69 -7
  8. data/lib/webrick/htmlutils.rb +4 -2
  9. data/lib/webrick/httpauth.rb +6 -5
  10. data/lib/webrick/httpauth/authenticator.rb +13 -8
  11. data/lib/webrick/httpauth/basicauth.rb +16 -8
  12. data/lib/webrick/httpauth/digestauth.rb +35 -32
  13. data/lib/webrick/httpauth/htdigest.rb +12 -8
  14. data/lib/webrick/httpauth/htgroup.rb +10 -6
  15. data/lib/webrick/httpauth/htpasswd.rb +46 -9
  16. data/lib/webrick/httpauth/userdb.rb +1 -0
  17. data/lib/webrick/httpproxy.rb +93 -48
  18. data/lib/webrick/httprequest.rb +192 -27
  19. data/lib/webrick/httpresponse.rb +182 -62
  20. data/lib/webrick/https.rb +90 -2
  21. data/lib/webrick/httpserver.rb +45 -15
  22. data/lib/webrick/httpservlet.rb +6 -5
  23. data/lib/webrick/httpservlet/abstract.rb +5 -6
  24. data/lib/webrick/httpservlet/cgi_runner.rb +3 -2
  25. data/lib/webrick/httpservlet/cgihandler.rb +22 -10
  26. data/lib/webrick/httpservlet/erbhandler.rb +4 -3
  27. data/lib/webrick/httpservlet/filehandler.rb +136 -65
  28. data/lib/webrick/httpservlet/prochandler.rb +15 -1
  29. data/lib/webrick/httpstatus.rb +24 -14
  30. data/lib/webrick/httputils.rb +132 -13
  31. data/lib/webrick/httpversion.rb +28 -1
  32. data/lib/webrick/log.rb +25 -5
  33. data/lib/webrick/server.rb +234 -74
  34. data/lib/webrick/ssl.rb +100 -12
  35. data/lib/webrick/utils.rb +98 -69
  36. data/lib/webrick/version.rb +6 -1
  37. metadata +66 -72
  38. data/README.txt +0 -21
  39. data/sample/webrick/demo-app.rb +0 -66
  40. data/sample/webrick/demo-multipart.cgi +0 -12
  41. data/sample/webrick/demo-servlet.rb +0 -6
  42. data/sample/webrick/demo-urlencoded.cgi +0 -12
  43. data/sample/webrick/hello.cgi +0 -11
  44. data/sample/webrick/hello.rb +0 -8
  45. data/sample/webrick/httpd.rb +0 -23
  46. data/sample/webrick/httpproxy.rb +0 -25
  47. data/sample/webrick/httpsd.rb +0 -33
  48. data/test/openssl/utils.rb +0 -313
  49. data/test/ruby/envutil.rb +0 -208
  50. data/test/webrick/test_cgi.rb +0 -134
  51. data/test/webrick/test_cookie.rb +0 -131
  52. data/test/webrick/test_filehandler.rb +0 -285
  53. data/test/webrick/test_httpauth.rb +0 -167
  54. data/test/webrick/test_httpproxy.rb +0 -282
  55. data/test/webrick/test_httprequest.rb +0 -411
  56. data/test/webrick/test_httpresponse.rb +0 -49
  57. data/test/webrick/test_httpserver.rb +0 -305
  58. data/test/webrick/test_httputils.rb +0 -96
  59. data/test/webrick/test_httpversion.rb +0 -40
  60. data/test/webrick/test_server.rb +0 -67
  61. data/test/webrick/test_utils.rb +0 -64
  62. data/test/webrick/utils.rb +0 -58
  63. data/test/webrick/webrick.cgi +0 -36
  64. data/test/webrick/webrick_long_filename.cgi +0 -36
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # httpresponse.rb -- HTTPResponse Class
3
4
  #
@@ -9,32 +10,91 @@
9
10
  # $IPR: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $
10
11
 
11
12
  require 'time'
12
- require 'webrick/httpversion'
13
- require 'webrick/htmlutils'
14
- require 'webrick/httputils'
15
- require 'webrick/httpstatus'
13
+ require 'uri'
14
+ require_relative 'httpversion'
15
+ require_relative 'htmlutils'
16
+ require_relative 'httputils'
17
+ require_relative 'httpstatus'
16
18
 
17
19
  module WEBrick
18
20
  ##
19
- # An HTTP response.
21
+ # An HTTP response. This is filled in by the service or do_* methods of a
22
+ # WEBrick HTTP Servlet.
20
23
 
21
24
  class HTTPResponse
22
- attr_reader :http_version, :status, :header
25
+ class InvalidHeader < StandardError
26
+ end
27
+
28
+ ##
29
+ # HTTP Response version
30
+
31
+ attr_reader :http_version
32
+
33
+ ##
34
+ # Response status code (200)
35
+
36
+ attr_reader :status
37
+
38
+ ##
39
+ # Response header
40
+
41
+ attr_reader :header
42
+
43
+ ##
44
+ # Response cookies
45
+
23
46
  attr_reader :cookies
47
+
48
+ ##
49
+ # Response reason phrase ("OK")
50
+
24
51
  attr_accessor :reason_phrase
25
52
 
26
53
  ##
27
- # Body may be a String or IO subclass.
54
+ # Body may be a String or IO-like object that responds to #read and
55
+ # #readpartial.
28
56
 
29
57
  attr_accessor :body
30
58
 
31
- attr_accessor :request_method, :request_uri, :request_http_version
59
+ ##
60
+ # Request method for this response
61
+
62
+ attr_accessor :request_method
63
+
64
+ ##
65
+ # Request URI for this response
66
+
67
+ attr_accessor :request_uri
68
+
69
+ ##
70
+ # Request HTTP version for this response
71
+
72
+ attr_accessor :request_http_version
73
+
74
+ ##
75
+ # Filename of the static file in this response. Only used by the
76
+ # FileHandler servlet.
77
+
32
78
  attr_accessor :filename
79
+
80
+ ##
81
+ # Is this a keep-alive response?
82
+
33
83
  attr_accessor :keep_alive
34
- attr_reader :config, :sent_size
35
84
 
36
85
  ##
37
- # Creates a new HTTP response object
86
+ # Configuration for this response
87
+
88
+ attr_reader :config
89
+
90
+ ##
91
+ # Bytes sent in this response
92
+
93
+ attr_reader :sent_size
94
+
95
+ ##
96
+ # Creates a new HTTP response object. WEBrick::Config::HTTP is the
97
+ # default configuration.
38
98
 
39
99
  def initialize(config)
40
100
  @config = config
@@ -115,7 +175,7 @@ module WEBrick
115
175
  end
116
176
 
117
177
  ##
118
- # Iterates over each header in the resopnse
178
+ # Iterates over each header in the response
119
179
 
120
180
  def each
121
181
  @header.each{|field, value| yield(field, value) }
@@ -145,7 +205,7 @@ module WEBrick
145
205
  ##
146
206
  # Sends the response on +socket+
147
207
 
148
- def send_response(socket)
208
+ def send_response(socket) # :nodoc:
149
209
  begin
150
210
  setup_header()
151
211
  send_header(socket)
@@ -162,7 +222,7 @@ module WEBrick
162
222
  ##
163
223
  # Sets up the headers for sending
164
224
 
165
- def setup_header()
225
+ def setup_header() # :nodoc:
166
226
  @reason_phrase ||= HTTPStatus::reason_phrase(@status)
167
227
  @header['server'] ||= @config[:ServerSoftware]
168
228
  @header['date'] ||= Time.now.httpdate
@@ -194,7 +254,7 @@ module WEBrick
194
254
  @header.delete('content-length')
195
255
  elsif @header['content-length'].nil?
196
256
  unless @body.is_a?(IO)
197
- @header['content-length'] = @body ? @body.bytesize : 0
257
+ @header['content-length'] = (@body ? @body.bytesize : 0).to_s
198
258
  end
199
259
  end
200
260
 
@@ -217,7 +277,7 @@ module WEBrick
217
277
  # Location is a single absoluteURI.
218
278
  if location = @header['location']
219
279
  if @request_uri
220
- @header['location'] = @request_uri.merge(location)
280
+ @header['location'] = @request_uri.merge(location).to_s
221
281
  end
222
282
  end
223
283
  end
@@ -225,28 +285,36 @@ module WEBrick
225
285
  ##
226
286
  # Sends the headers on +socket+
227
287
 
228
- def send_header(socket)
288
+ def send_header(socket) # :nodoc:
229
289
  if @http_version.major > 0
230
290
  data = status_line()
231
291
  @header.each{|key, value|
232
292
  tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }
233
- data << "#{tmp}: #{value}" << CRLF
293
+ data << "#{tmp}: #{check_header(value)}" << CRLF
234
294
  }
235
295
  @cookies.each{|cookie|
236
- data << "Set-Cookie: " << cookie.to_s << CRLF
296
+ data << "Set-Cookie: " << check_header(cookie.to_s) << CRLF
237
297
  }
238
298
  data << CRLF
239
- _write_data(socket, data)
299
+ socket.write(data)
240
300
  end
301
+ rescue InvalidHeader => e
302
+ @header.clear
303
+ @cookies.clear
304
+ set_error e
305
+ retry
241
306
  end
242
307
 
243
308
  ##
244
309
  # Sends the body on +socket+
245
310
 
246
- def send_body(socket)
247
- case @body
248
- when IO then send_body_io(socket)
249
- else send_body_string(socket)
311
+ def send_body(socket) # :nodoc:
312
+ if @body.respond_to? :readpartial then
313
+ send_body_io(socket)
314
+ elsif @body.respond_to?(:call) then
315
+ send_body_proc(socket)
316
+ else
317
+ send_body_string(socket)
250
318
  end
251
319
  end
252
320
 
@@ -264,8 +332,9 @@ module WEBrick
264
332
  # res.set_redirect WEBrick::HTTPStatus::TemporaryRedirect
265
333
 
266
334
  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
335
+ url = URI(url).to_s
336
+ @body = "<HTML><A HREF=\"#{url}\">#{url}</A>.</HTML>\n"
337
+ @header['location'] = url
269
338
  raise status
270
339
  end
271
340
 
@@ -294,6 +363,23 @@ module WEBrick
294
363
  host, port = @config[:ServerName], @config[:Port]
295
364
  end
296
365
 
366
+ error_body(backtrace, ex, host, port)
367
+ end
368
+
369
+ private
370
+
371
+ def check_header(header_value)
372
+ header_value = header_value.to_s
373
+ if /[\r\n]/ =~ header_value
374
+ raise InvalidHeader
375
+ else
376
+ header_value
377
+ end
378
+ end
379
+
380
+ # :stopdoc:
381
+
382
+ def error_body(backtrace, ex, host, port)
297
383
  @body = ''
298
384
  @body << <<-_end_of_html_
299
385
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
@@ -323,26 +409,39 @@ module WEBrick
323
409
  _end_of_html_
324
410
  end
325
411
 
326
- private
327
-
328
412
  def send_body_io(socket)
329
413
  begin
330
414
  if @request_method == "HEAD"
331
415
  # do nothing
332
416
  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}")
417
+ buf = ''
418
+ begin
419
+ @body.readpartial(@buffer_size, buf)
420
+ size = buf.bytesize
421
+ data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
422
+ socket.write(data)
423
+ data.clear
424
+ @sent_size += size
425
+ rescue EOFError
426
+ break
427
+ end while true
428
+ buf.clear
429
+ socket.write("0#{CRLF}#{CRLF}")
342
430
  else
343
- size = @header['content-length'].to_i
344
- _send_file(socket, @body, 0, size)
345
- @sent_size = size
431
+ if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ @header['content-range']
432
+ offset = $1.to_i
433
+ size = $2.to_i - offset + 1
434
+ else
435
+ offset = nil
436
+ size = @header['content-length']
437
+ size = size.to_i if size
438
+ end
439
+ begin
440
+ @sent_size = IO.copy_stream(@body, socket, size, offset)
441
+ rescue NotImplementedError
442
+ @body.seek(offset, IO::SEEK_SET)
443
+ @sent_size = IO.copy_stream(@body, socket, size)
444
+ end
346
445
  end
347
446
  ensure
348
447
  @body.close
@@ -356,44 +455,65 @@ module WEBrick
356
455
  body ? @body.bytesize : 0
357
456
  while buf = @body[@sent_size, @buffer_size]
358
457
  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
458
+ size = buf.bytesize
459
+ data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
460
+ buf.clear
461
+ socket.write(data)
462
+ @sent_size += size
364
463
  end
365
- _write_data(socket, "0#{CRLF}#{CRLF}")
464
+ socket.write("0#{CRLF}#{CRLF}")
366
465
  else
367
466
  if @body && @body.bytesize > 0
368
- _write_data(socket, @body)
467
+ socket.write(@body)
369
468
  @sent_size = @body.bytesize
370
469
  end
371
470
  end
372
471
  end
373
472
 
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
473
+ def send_body_proc(socket)
474
+ if @request_method == "HEAD"
475
+ # do nothing
476
+ elsif chunked?
477
+ @body.call(ChunkedWrapper.new(socket, self))
478
+ socket.write("0#{CRLF}#{CRLF}")
479
+ else
480
+ size = @header['content-length'].to_i
481
+ @body.call(socket)
482
+ @sent_size = size
379
483
  end
484
+ end
380
485
 
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
486
+ class ChunkedWrapper
487
+ def initialize(socket, resp)
488
+ @socket = socket
489
+ @resp = resp
490
+ end
491
+
492
+ def write(buf)
493
+ return 0 if buf.empty?
494
+ socket = @socket
495
+ @resp.instance_eval {
496
+ size = buf.bytesize
497
+ data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
498
+ socket.write(data)
499
+ data.clear
500
+ @sent_size += size
501
+ size
502
+ }
503
+ end
504
+
505
+ def <<(*buf)
506
+ write(buf)
507
+ self
392
508
  end
393
509
  end
394
510
 
511
+ # preserved for compatibility with some 3rd-party handlers
395
512
  def _write_data(socket, data)
396
513
  socket << data
397
514
  end
515
+
516
+ # :startdoc:
398
517
  end
518
+
399
519
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  #
2
3
  # https.rb -- SSL/TLS enhancement for HTTPServer
3
4
  #
@@ -8,15 +9,36 @@
8
9
  #
9
10
  # $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $
10
11
 
11
- require 'webrick/ssl'
12
+ require_relative 'ssl'
13
+ require_relative 'httpserver'
12
14
 
13
15
  module WEBrick
14
16
  module Config
15
17
  HTTP.update(SSL)
16
18
  end
17
19
 
20
+ ##
21
+ #--
22
+ # Adds SSL functionality to WEBrick::HTTPRequest
23
+
18
24
  class HTTPRequest
19
- attr_reader :cipher, :server_cert, :client_cert
25
+
26
+ ##
27
+ # HTTP request SSL cipher
28
+
29
+ attr_reader :cipher
30
+
31
+ ##
32
+ # HTTP request server certificate
33
+
34
+ attr_reader :server_cert
35
+
36
+ ##
37
+ # HTTP request client certificate
38
+
39
+ attr_reader :client_cert
40
+
41
+ # :stopdoc:
20
42
 
21
43
  alias orig_parse parse
22
44
 
@@ -60,5 +82,71 @@ module WEBrick
60
82
  end
61
83
  meta
62
84
  end
85
+
86
+ # :startdoc:
87
+ end
88
+
89
+ ##
90
+ #--
91
+ # Fake WEBrick::HTTPRequest for lookup_server
92
+
93
+ class SNIRequest
94
+
95
+ ##
96
+ # The SNI hostname
97
+
98
+ attr_reader :host
99
+
100
+ ##
101
+ # The socket address of the server
102
+
103
+ attr_reader :addr
104
+
105
+ ##
106
+ # The port this request is for
107
+
108
+ attr_reader :port
109
+
110
+ ##
111
+ # Creates a new SNIRequest.
112
+
113
+ def initialize(sslsocket, hostname)
114
+ @host = hostname
115
+ @addr = sslsocket.addr
116
+ @port = @addr[1]
117
+ end
118
+ end
119
+
120
+
121
+ ##
122
+ #--
123
+ # Adds SSL functionality to WEBrick::HTTPServer
124
+
125
+ class HTTPServer < ::WEBrick::GenericServer
126
+ ##
127
+ # ServerNameIndication callback
128
+
129
+ def ssl_servername_callback(sslsocket, hostname = nil)
130
+ req = SNIRequest.new(sslsocket, hostname)
131
+ server = lookup_server(req)
132
+ server ? server.ssl_context : nil
133
+ end
134
+
135
+ # :stopdoc:
136
+
137
+ ##
138
+ # Check whether +server+ is also SSL server.
139
+ # Also +server+'s SSL context will be created.
140
+
141
+ alias orig_virtual_host virtual_host
142
+
143
+ def virtual_host(server)
144
+ if @config[:SSLEnable] && !server.ssl_context
145
+ raise ArgumentError, "virtual host must set SSLEnable to true"
146
+ end
147
+ orig_virtual_host(server)
148
+ end
149
+
150
+ # :startdoc:
63
151
  end
64
152
  end