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.
- checksums.yaml +7 -0
- data/lib/webrick.rb +6 -6
- data/lib/webrick/accesslog.rb +9 -1
- data/lib/webrick/cgi.rb +58 -5
- data/lib/webrick/compat.rb +2 -1
- data/lib/webrick/config.rb +47 -10
- data/lib/webrick/cookie.rb +69 -7
- data/lib/webrick/htmlutils.rb +4 -2
- data/lib/webrick/httpauth.rb +6 -5
- data/lib/webrick/httpauth/authenticator.rb +13 -8
- data/lib/webrick/httpauth/basicauth.rb +16 -8
- data/lib/webrick/httpauth/digestauth.rb +35 -32
- data/lib/webrick/httpauth/htdigest.rb +12 -8
- data/lib/webrick/httpauth/htgroup.rb +10 -6
- data/lib/webrick/httpauth/htpasswd.rb +46 -9
- data/lib/webrick/httpauth/userdb.rb +1 -0
- data/lib/webrick/httpproxy.rb +93 -48
- data/lib/webrick/httprequest.rb +192 -27
- data/lib/webrick/httpresponse.rb +182 -62
- data/lib/webrick/https.rb +90 -2
- data/lib/webrick/httpserver.rb +45 -15
- data/lib/webrick/httpservlet.rb +6 -5
- data/lib/webrick/httpservlet/abstract.rb +5 -6
- data/lib/webrick/httpservlet/cgi_runner.rb +3 -2
- data/lib/webrick/httpservlet/cgihandler.rb +22 -10
- data/lib/webrick/httpservlet/erbhandler.rb +4 -3
- data/lib/webrick/httpservlet/filehandler.rb +136 -65
- data/lib/webrick/httpservlet/prochandler.rb +15 -1
- data/lib/webrick/httpstatus.rb +24 -14
- data/lib/webrick/httputils.rb +132 -13
- data/lib/webrick/httpversion.rb +28 -1
- data/lib/webrick/log.rb +25 -5
- data/lib/webrick/server.rb +234 -74
- data/lib/webrick/ssl.rb +100 -12
- data/lib/webrick/utils.rb +98 -69
- data/lib/webrick/version.rb +6 -1
- metadata +66 -72
- data/README.txt +0 -21
- data/sample/webrick/demo-app.rb +0 -66
- data/sample/webrick/demo-multipart.cgi +0 -12
- data/sample/webrick/demo-servlet.rb +0 -6
- data/sample/webrick/demo-urlencoded.cgi +0 -12
- data/sample/webrick/hello.cgi +0 -11
- data/sample/webrick/hello.rb +0 -8
- data/sample/webrick/httpd.rb +0 -23
- data/sample/webrick/httpproxy.rb +0 -25
- data/sample/webrick/httpsd.rb +0 -33
- data/test/openssl/utils.rb +0 -313
- data/test/ruby/envutil.rb +0 -208
- data/test/webrick/test_cgi.rb +0 -134
- data/test/webrick/test_cookie.rb +0 -131
- data/test/webrick/test_filehandler.rb +0 -285
- data/test/webrick/test_httpauth.rb +0 -167
- data/test/webrick/test_httpproxy.rb +0 -282
- data/test/webrick/test_httprequest.rb +0 -411
- data/test/webrick/test_httpresponse.rb +0 -49
- data/test/webrick/test_httpserver.rb +0 -305
- data/test/webrick/test_httputils.rb +0 -96
- data/test/webrick/test_httpversion.rb +0 -40
- data/test/webrick/test_server.rb +0 -67
- data/test/webrick/test_utils.rb +0 -64
- data/test/webrick/utils.rb +0 -58
- data/test/webrick/webrick.cgi +0 -36
- data/test/webrick/webrick_long_filename.cgi +0 -36
data/lib/webrick/httpresponse.rb
CHANGED
@@ -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 '
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
#
|
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
|
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
|
-
|
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
|
-
|
248
|
-
|
249
|
-
|
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
|
-
|
268
|
-
@
|
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
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
data
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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
|
-
|
344
|
-
|
345
|
-
|
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
|
-
|
360
|
-
data
|
361
|
-
|
362
|
-
|
363
|
-
@sent_size +=
|
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
|
-
|
464
|
+
socket.write("0#{CRLF}#{CRLF}")
|
366
465
|
else
|
367
466
|
if @body && @body.bytesize > 0
|
368
|
-
|
467
|
+
socket.write(@body)
|
369
468
|
@sent_size = @body.bytesize
|
370
469
|
end
|
371
470
|
end
|
372
471
|
end
|
373
472
|
|
374
|
-
def
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
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
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
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
|
data/lib/webrick/https.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|