webrick 1.4.1 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/webrick.rb +1 -1
- data/lib/webrick/accesslog.rb +3 -5
- data/lib/webrick/cgi.rb +7 -3
- data/lib/webrick/config.rb +5 -5
- data/lib/webrick/cookie.rb +1 -1
- data/lib/webrick/httpauth.rb +5 -5
- data/lib/webrick/httpauth/basicauth.rb +13 -5
- data/lib/webrick/httpauth/digestauth.rb +10 -23
- data/lib/webrick/httpauth/htdigest.rb +4 -4
- data/lib/webrick/httpauth/htgroup.rb +9 -6
- data/lib/webrick/httpauth/htpasswd.rb +39 -6
- data/lib/webrick/httpproxy.rb +44 -32
- data/lib/webrick/httprequest.rb +59 -15
- data/lib/webrick/httpresponse.rb +111 -52
- data/lib/webrick/https.rb +2 -2
- data/lib/webrick/httpserver.rb +23 -9
- data/lib/webrick/httpservlet.rb +5 -5
- data/lib/webrick/httpservlet/abstract.rb +3 -3
- data/lib/webrick/httpservlet/cgi_runner.rb +2 -2
- data/lib/webrick/httpservlet/cgihandler.rb +10 -6
- data/lib/webrick/httpservlet/erbhandler.rb +2 -2
- data/lib/webrick/httpservlet/filehandler.rb +49 -30
- data/lib/webrick/httpservlet/prochandler.rb +1 -1
- data/lib/webrick/httpstatus.rb +1 -1
- data/lib/webrick/httputils.rb +4 -4
- data/lib/webrick/log.rb +1 -1
- data/lib/webrick/server.rb +2 -2
- data/lib/webrick/ssl.rb +2 -2
- data/lib/webrick/version.rb +1 -1
- data/webrick.gemspec +76 -0
- metadata +16 -10
data/lib/webrick/httpproxy.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
# $IPR: httpproxy.rb,v 1.18 2003/03/08 18:58:10 gotoyuzo Exp $
|
11
11
|
# $kNotwork: straw.rb,v 1.3 2002/02/12 15:13:07 gotoken Exp $
|
12
12
|
|
13
|
-
|
13
|
+
require_relative "httpserver"
|
14
14
|
require "net/http"
|
15
15
|
|
16
16
|
module WEBrick
|
@@ -211,21 +211,15 @@ module WEBrick
|
|
211
211
|
end
|
212
212
|
|
213
213
|
def do_GET(req, res)
|
214
|
-
perform_proxy_request(req, res
|
215
|
-
http.get(path, header)
|
216
|
-
end
|
214
|
+
perform_proxy_request(req, res, Net::HTTP::Get)
|
217
215
|
end
|
218
216
|
|
219
217
|
def do_HEAD(req, res)
|
220
|
-
perform_proxy_request(req, res
|
221
|
-
http.head(path, header)
|
222
|
-
end
|
218
|
+
perform_proxy_request(req, res, Net::HTTP::Head)
|
223
219
|
end
|
224
220
|
|
225
221
|
def do_POST(req, res)
|
226
|
-
perform_proxy_request(req, res
|
227
|
-
http.post(path, req.body || "", header)
|
228
|
-
end
|
222
|
+
perform_proxy_request(req, res, Net::HTTP::Post, req.body_reader)
|
229
223
|
end
|
230
224
|
|
231
225
|
def do_OPTIONS(req, res)
|
@@ -301,38 +295,56 @@ module WEBrick
|
|
301
295
|
return FakeProxyURI
|
302
296
|
end
|
303
297
|
|
304
|
-
def perform_proxy_request(req, res)
|
298
|
+
def perform_proxy_request(req, res, req_class, body_stream = nil)
|
305
299
|
uri = req.request_uri
|
306
300
|
path = uri.path.dup
|
307
301
|
path << "?" << uri.query if uri.query
|
308
302
|
header = setup_proxy_header(req, res)
|
309
303
|
upstream = setup_upstream_proxy_authentication(req, res, header)
|
310
|
-
response = nil
|
311
304
|
|
305
|
+
body_tmp = []
|
312
306
|
http = Net::HTTP.new(uri.host, uri.port, upstream.host, upstream.port)
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
307
|
+
req_fib = Fiber.new do
|
308
|
+
http.start do
|
309
|
+
if @config[:ProxyTimeout]
|
310
|
+
################################## these issues are
|
311
|
+
http.open_timeout = 30 # secs # necessary (maybe because
|
312
|
+
http.read_timeout = 60 # secs # Ruby's bug, but why?)
|
313
|
+
##################################
|
314
|
+
end
|
315
|
+
if body_stream && req['transfer-encoding'] =~ /\bchunked\b/i
|
316
|
+
header['Transfer-Encoding'] = 'chunked'
|
317
|
+
end
|
318
|
+
http_req = req_class.new(path, header)
|
319
|
+
http_req.body_stream = body_stream if body_stream
|
320
|
+
http.request(http_req) do |response|
|
321
|
+
# Persistent connection requirements are mysterious for me.
|
322
|
+
# So I will close the connection in every response.
|
323
|
+
res['proxy-connection'] = "close"
|
324
|
+
res['connection'] = "close"
|
325
|
+
|
326
|
+
# stream Net::HTTP::HTTPResponse to WEBrick::HTTPResponse
|
327
|
+
res.status = response.code.to_i
|
328
|
+
res.chunked = response.chunked?
|
329
|
+
choose_header(response, res)
|
330
|
+
set_cookie(response, res)
|
331
|
+
set_via(res)
|
332
|
+
response.read_body do |buf|
|
333
|
+
body_tmp << buf
|
334
|
+
Fiber.yield # wait for res.body Proc#call
|
335
|
+
end
|
336
|
+
end # http.request
|
337
|
+
end
|
338
|
+
end
|
339
|
+
req_fib.resume # read HTTP response headers and first chunk of the body
|
340
|
+
res.body = ->(socket) do
|
341
|
+
while buf = body_tmp.shift
|
342
|
+
socket.write(buf)
|
343
|
+
buf.clear
|
344
|
+
req_fib.resume # continue response.read_body
|
319
345
|
end
|
320
|
-
response = yield(http, path, header)
|
321
346
|
end
|
322
|
-
|
323
|
-
# Persistent connection requirements are mysterious for me.
|
324
|
-
# So I will close the connection in every response.
|
325
|
-
res['proxy-connection'] = "close"
|
326
|
-
res['connection'] = "close"
|
327
|
-
|
328
|
-
# Convert Net::HTTP::HTTPResponse to WEBrick::HTTPResponse
|
329
|
-
res.status = response.code.to_i
|
330
|
-
choose_header(response, res)
|
331
|
-
set_cookie(response, res)
|
332
|
-
set_via(res)
|
333
|
-
res.body = response.body
|
334
347
|
end
|
335
|
-
|
336
348
|
# :stopdoc:
|
337
349
|
end
|
338
350
|
end
|
data/lib/webrick/httprequest.rb
CHANGED
@@ -10,10 +10,10 @@
|
|
10
10
|
# $IPR: httprequest.rb,v 1.64 2003/07/13 17:18:22 gotoyuzo Exp $
|
11
11
|
|
12
12
|
require 'uri'
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
require_relative 'httpversion'
|
14
|
+
require_relative 'httpstatus'
|
15
|
+
require_relative 'httputils'
|
16
|
+
require_relative 'cookie'
|
17
17
|
|
18
18
|
module WEBrick
|
19
19
|
|
@@ -226,9 +226,9 @@ module WEBrick
|
|
226
226
|
raise HTTPStatus::BadRequest, "bad URI `#{@unparsed_uri}'."
|
227
227
|
end
|
228
228
|
|
229
|
-
if /
|
229
|
+
if /\Aclose\z/io =~ self["connection"]
|
230
230
|
@keep_alive = false
|
231
|
-
elsif
|
231
|
+
elsif /\Akeep-alive\z/io =~ self["connection"]
|
232
232
|
@keep_alive = true
|
233
233
|
elsif @http_version < "1.1"
|
234
234
|
@keep_alive = false
|
@@ -257,6 +257,32 @@ module WEBrick
|
|
257
257
|
@body.empty? ? nil : @body
|
258
258
|
end
|
259
259
|
|
260
|
+
##
|
261
|
+
# Prepares the HTTPRequest object for use as the
|
262
|
+
# source for IO.copy_stream
|
263
|
+
|
264
|
+
def body_reader
|
265
|
+
@body_tmp = []
|
266
|
+
@body_rd = Fiber.new do
|
267
|
+
body do |buf|
|
268
|
+
@body_tmp << buf
|
269
|
+
Fiber.yield
|
270
|
+
end
|
271
|
+
end
|
272
|
+
@body_rd.resume # grab the first chunk and yield
|
273
|
+
self
|
274
|
+
end
|
275
|
+
|
276
|
+
# for IO.copy_stream. Note: we may return a larger string than +size+
|
277
|
+
# here; but IO.copy_stream does not care.
|
278
|
+
def readpartial(size, buf = ''.b) # :nodoc
|
279
|
+
res = @body_tmp.shift or raise EOFError, 'end of file reached'
|
280
|
+
buf.replace(res)
|
281
|
+
res.clear
|
282
|
+
@body_rd.resume # get more chunks
|
283
|
+
buf
|
284
|
+
end
|
285
|
+
|
260
286
|
##
|
261
287
|
# Request query as a Hash
|
262
288
|
|
@@ -414,13 +440,19 @@ module WEBrick
|
|
414
440
|
|
415
441
|
MAX_URI_LENGTH = 2083 # :nodoc:
|
416
442
|
|
443
|
+
# same as Mongrel, Thin and Puma
|
444
|
+
MAX_HEADER_LENGTH = (112 * 1024) # :nodoc:
|
445
|
+
|
417
446
|
def read_request_line(socket)
|
418
447
|
@request_line = read_line(socket, MAX_URI_LENGTH) if socket
|
419
|
-
|
448
|
+
raise HTTPStatus::EOFError unless @request_line
|
449
|
+
|
450
|
+
@request_bytes = @request_line.bytesize
|
451
|
+
if @request_bytes >= MAX_URI_LENGTH and @request_line[-1, 1] != LF
|
420
452
|
raise HTTPStatus::RequestURITooLarge
|
421
453
|
end
|
454
|
+
|
422
455
|
@request_time = Time.now
|
423
|
-
raise HTTPStatus::EOFError unless @request_line
|
424
456
|
if /^(\S+)\s+(\S++)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line
|
425
457
|
@request_method = $1
|
426
458
|
@unparsed_uri = $2
|
@@ -435,6 +467,9 @@ module WEBrick
|
|
435
467
|
if socket
|
436
468
|
while line = read_line(socket)
|
437
469
|
break if /\A(#{CRLF}|#{LF})\z/om =~ line
|
470
|
+
if (@request_bytes += line.bytesize) > MAX_HEADER_LENGTH
|
471
|
+
raise HTTPStatus::RequestEntityTooLarge, 'headers too large'
|
472
|
+
end
|
438
473
|
@raw_header << line
|
439
474
|
end
|
440
475
|
end
|
@@ -468,7 +503,7 @@ module WEBrick
|
|
468
503
|
return unless socket
|
469
504
|
if tc = self['transfer-encoding']
|
470
505
|
case tc
|
471
|
-
when /
|
506
|
+
when /\Achunked\z/io then read_chunked(socket, block)
|
472
507
|
else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}."
|
473
508
|
end
|
474
509
|
elsif self['content-length'] || @remaining_size
|
@@ -502,12 +537,16 @@ module WEBrick
|
|
502
537
|
def read_chunked(socket, block)
|
503
538
|
chunk_size, = read_chunk_size(socket)
|
504
539
|
while chunk_size > 0
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
540
|
+
begin
|
541
|
+
sz = [ chunk_size, @buffer_size ].min
|
542
|
+
data = read_data(socket, sz) # read chunk-data
|
543
|
+
if data.nil? || data.bytesize != sz
|
544
|
+
raise HTTPStatus::BadRequest, "bad chunk data size."
|
545
|
+
end
|
546
|
+
block.call(data)
|
547
|
+
end while (chunk_size -= sz) > 0
|
548
|
+
|
509
549
|
read_line(socket) # skip CRLF
|
510
|
-
block.call(data)
|
511
550
|
chunk_size, = read_chunk_size(socket)
|
512
551
|
end
|
513
552
|
read_header(socket) # trailer + CRLF
|
@@ -572,7 +611,12 @@ module WEBrick
|
|
572
611
|
end
|
573
612
|
if host_port = self["x-forwarded-host"]
|
574
613
|
host_port = host_port.split(",", 2).first
|
575
|
-
|
614
|
+
if host_port =~ /\A(\[[0-9a-fA-F:]+\])(?::(\d+))?\z/
|
615
|
+
@forwarded_host = $1
|
616
|
+
tmp = $2
|
617
|
+
else
|
618
|
+
@forwarded_host, tmp = host_port.split(":", 2)
|
619
|
+
end
|
576
620
|
@forwarded_port = (tmp || (@forwarded_proto == "https" ? 443 : 80)).to_i
|
577
621
|
end
|
578
622
|
if addrs = self["x-forwarded-for"]
|
data/lib/webrick/httpresponse.rb
CHANGED
@@ -10,10 +10,11 @@
|
|
10
10
|
# $IPR: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $
|
11
11
|
|
12
12
|
require 'time'
|
13
|
-
require '
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
require 'uri'
|
14
|
+
require_relative 'httpversion'
|
15
|
+
require_relative 'htmlutils'
|
16
|
+
require_relative 'httputils'
|
17
|
+
require_relative 'httpstatus'
|
17
18
|
|
18
19
|
module WEBrick
|
19
20
|
##
|
@@ -21,6 +22,8 @@ module WEBrick
|
|
21
22
|
# WEBrick HTTP Servlet.
|
22
23
|
|
23
24
|
class HTTPResponse
|
25
|
+
class InvalidHeader < StandardError
|
26
|
+
end
|
24
27
|
|
25
28
|
##
|
26
29
|
# HTTP Response version
|
@@ -48,8 +51,21 @@ module WEBrick
|
|
48
51
|
attr_accessor :reason_phrase
|
49
52
|
|
50
53
|
##
|
51
|
-
# Body may be
|
52
|
-
#
|
54
|
+
# Body may be:
|
55
|
+
# * a String;
|
56
|
+
# * an IO-like object that responds to +#read+ and +#readpartial+;
|
57
|
+
# * a Proc-like object that responds to +#call+.
|
58
|
+
#
|
59
|
+
# In the latter case, either #chunked= should be set to +true+,
|
60
|
+
# or <code>header['content-length']</code> explicitly provided.
|
61
|
+
# Example:
|
62
|
+
#
|
63
|
+
# server.mount_proc '/' do |req, res|
|
64
|
+
# res.chunked = true
|
65
|
+
# # or
|
66
|
+
# # res.header['content-length'] = 10
|
67
|
+
# res.body = proc { |out| out.write(Time.now.to_s) }
|
68
|
+
# end
|
53
69
|
|
54
70
|
attr_accessor :body
|
55
71
|
|
@@ -110,13 +126,14 @@ module WEBrick
|
|
110
126
|
@chunked = false
|
111
127
|
@filename = nil
|
112
128
|
@sent_size = 0
|
129
|
+
@bodytempfile = nil
|
113
130
|
end
|
114
131
|
|
115
132
|
##
|
116
133
|
# The response's HTTP status line
|
117
134
|
|
118
135
|
def status_line
|
119
|
-
"HTTP/#@http_version #@status #@reason_phrase
|
136
|
+
"HTTP/#@http_version #@status #@reason_phrase".rstrip << CRLF
|
120
137
|
end
|
121
138
|
|
122
139
|
##
|
@@ -138,6 +155,7 @@ module WEBrick
|
|
138
155
|
# Sets the response header +field+ to +value+
|
139
156
|
|
140
157
|
def []=(field, value)
|
158
|
+
@chunked = value.to_s.downcase == 'chunked' if field.downcase == 'transfer-encoding'
|
141
159
|
@header[field.downcase] = value.to_s
|
142
160
|
end
|
143
161
|
|
@@ -250,8 +268,11 @@ module WEBrick
|
|
250
268
|
elsif %r{^multipart/byteranges} =~ @header['content-type']
|
251
269
|
@header.delete('content-length')
|
252
270
|
elsif @header['content-length'].nil?
|
253
|
-
|
254
|
-
|
271
|
+
if @body.respond_to? :readpartial
|
272
|
+
elsif @body.respond_to? :call
|
273
|
+
make_body_tempfile
|
274
|
+
else
|
275
|
+
@header['content-length'] = (@body ? @body.bytesize : 0).to_s
|
255
276
|
end
|
256
277
|
end
|
257
278
|
|
@@ -274,11 +295,38 @@ module WEBrick
|
|
274
295
|
# Location is a single absoluteURI.
|
275
296
|
if location = @header['location']
|
276
297
|
if @request_uri
|
277
|
-
@header['location'] = @request_uri.merge(location)
|
298
|
+
@header['location'] = @request_uri.merge(location).to_s
|
278
299
|
end
|
279
300
|
end
|
280
301
|
end
|
281
302
|
|
303
|
+
def make_body_tempfile # :nodoc:
|
304
|
+
return if @bodytempfile
|
305
|
+
bodytempfile = Tempfile.create("webrick")
|
306
|
+
if @body.nil?
|
307
|
+
# nothing
|
308
|
+
elsif @body.respond_to? :readpartial
|
309
|
+
IO.copy_stream(@body, bodytempfile)
|
310
|
+
@body.close
|
311
|
+
elsif @body.respond_to? :call
|
312
|
+
@body.call(bodytempfile)
|
313
|
+
else
|
314
|
+
bodytempfile.write @body
|
315
|
+
end
|
316
|
+
bodytempfile.rewind
|
317
|
+
@body = @bodytempfile = bodytempfile
|
318
|
+
@header['content-length'] = bodytempfile.stat.size.to_s
|
319
|
+
end
|
320
|
+
|
321
|
+
def remove_body_tempfile # :nodoc:
|
322
|
+
if @bodytempfile
|
323
|
+
@bodytempfile.close
|
324
|
+
File.unlink @bodytempfile.path
|
325
|
+
@bodytempfile = nil
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
|
282
330
|
##
|
283
331
|
# Sends the headers on +socket+
|
284
332
|
|
@@ -287,14 +335,19 @@ module WEBrick
|
|
287
335
|
data = status_line()
|
288
336
|
@header.each{|key, value|
|
289
337
|
tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }
|
290
|
-
data << "#{tmp}: #{value}" << CRLF
|
338
|
+
data << "#{tmp}: #{check_header(value)}" << CRLF
|
291
339
|
}
|
292
340
|
@cookies.each{|cookie|
|
293
|
-
data << "Set-Cookie: " << cookie.to_s << CRLF
|
341
|
+
data << "Set-Cookie: " << check_header(cookie.to_s) << CRLF
|
294
342
|
}
|
295
343
|
data << CRLF
|
296
|
-
|
344
|
+
socket.write(data)
|
297
345
|
end
|
346
|
+
rescue InvalidHeader => e
|
347
|
+
@header.clear
|
348
|
+
@cookies.clear
|
349
|
+
set_error e
|
350
|
+
retry
|
298
351
|
end
|
299
352
|
|
300
353
|
##
|
@@ -310,12 +363,6 @@ module WEBrick
|
|
310
363
|
end
|
311
364
|
end
|
312
365
|
|
313
|
-
def to_s # :nodoc:
|
314
|
-
ret = ""
|
315
|
-
send_response(ret)
|
316
|
-
ret
|
317
|
-
end
|
318
|
-
|
319
366
|
##
|
320
367
|
# Redirects to +url+ with a WEBrick::HTTPStatus::Redirect +status+.
|
321
368
|
#
|
@@ -324,8 +371,9 @@ module WEBrick
|
|
324
371
|
# res.set_redirect WEBrick::HTTPStatus::TemporaryRedirect
|
325
372
|
|
326
373
|
def set_redirect(status, url)
|
374
|
+
url = URI(url).to_s
|
327
375
|
@body = "<HTML><A HREF=\"#{url}\">#{url}</A>.</HTML>\n"
|
328
|
-
@header['location'] = url
|
376
|
+
@header['location'] = url
|
329
377
|
raise status
|
330
378
|
end
|
331
379
|
|
@@ -359,6 +407,15 @@ module WEBrick
|
|
359
407
|
|
360
408
|
private
|
361
409
|
|
410
|
+
def check_header(header_value)
|
411
|
+
header_value = header_value.to_s
|
412
|
+
if /[\r\n]/ =~ header_value
|
413
|
+
raise InvalidHeader
|
414
|
+
else
|
415
|
+
header_value
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
362
419
|
# :stopdoc:
|
363
420
|
|
364
421
|
def error_body(backtrace, ex, host, port)
|
@@ -401,22 +458,34 @@ module WEBrick
|
|
401
458
|
@body.readpartial(@buffer_size, buf)
|
402
459
|
size = buf.bytesize
|
403
460
|
data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
|
404
|
-
|
461
|
+
socket.write(data)
|
405
462
|
data.clear
|
406
463
|
@sent_size += size
|
407
464
|
rescue EOFError
|
408
465
|
break
|
409
466
|
end while true
|
410
467
|
buf.clear
|
411
|
-
|
468
|
+
socket.write("0#{CRLF}#{CRLF}")
|
412
469
|
else
|
413
|
-
|
414
|
-
|
415
|
-
|
470
|
+
if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ @header['content-range']
|
471
|
+
offset = $1.to_i
|
472
|
+
size = $2.to_i - offset + 1
|
473
|
+
else
|
474
|
+
offset = nil
|
475
|
+
size = @header['content-length']
|
476
|
+
size = size.to_i if size
|
477
|
+
end
|
478
|
+
begin
|
479
|
+
@sent_size = IO.copy_stream(@body, socket, size, offset)
|
480
|
+
rescue NotImplementedError
|
481
|
+
@body.seek(offset, IO::SEEK_SET)
|
482
|
+
@sent_size = IO.copy_stream(@body, socket, size)
|
483
|
+
end
|
416
484
|
end
|
417
485
|
ensure
|
418
486
|
@body.close
|
419
487
|
end
|
488
|
+
remove_body_tempfile
|
420
489
|
end
|
421
490
|
|
422
491
|
def send_body_string(socket)
|
@@ -429,13 +498,13 @@ module WEBrick
|
|
429
498
|
size = buf.bytesize
|
430
499
|
data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
|
431
500
|
buf.clear
|
432
|
-
|
501
|
+
socket.write(data)
|
433
502
|
@sent_size += size
|
434
503
|
end
|
435
|
-
|
504
|
+
socket.write("0#{CRLF}#{CRLF}")
|
436
505
|
else
|
437
506
|
if @body && @body.bytesize > 0
|
438
|
-
|
507
|
+
socket.write(@body)
|
439
508
|
@sent_size = @body.bytesize
|
440
509
|
end
|
441
510
|
end
|
@@ -446,10 +515,15 @@ module WEBrick
|
|
446
515
|
# do nothing
|
447
516
|
elsif chunked?
|
448
517
|
@body.call(ChunkedWrapper.new(socket, self))
|
449
|
-
|
518
|
+
socket.write("0#{CRLF}#{CRLF}")
|
450
519
|
else
|
451
520
|
size = @header['content-length'].to_i
|
452
|
-
@
|
521
|
+
if @bodytempfile
|
522
|
+
@bodytempfile.rewind
|
523
|
+
IO.copy_stream(@bodytempfile, socket)
|
524
|
+
else
|
525
|
+
@body.call(socket)
|
526
|
+
end
|
453
527
|
@sent_size = size
|
454
528
|
end
|
455
529
|
end
|
@@ -461,40 +535,25 @@ module WEBrick
|
|
461
535
|
end
|
462
536
|
|
463
537
|
def write(buf)
|
464
|
-
return if buf.empty?
|
538
|
+
return 0 if buf.empty?
|
465
539
|
socket = @socket
|
466
540
|
@resp.instance_eval {
|
467
541
|
size = buf.bytesize
|
468
542
|
data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
|
469
|
-
|
543
|
+
socket.write(data)
|
470
544
|
data.clear
|
471
545
|
@sent_size += size
|
546
|
+
size
|
472
547
|
}
|
473
548
|
end
|
474
|
-
alias :<< :write
|
475
|
-
end
|
476
|
-
|
477
|
-
def _send_file(output, input, offset, size)
|
478
|
-
while offset > 0
|
479
|
-
sz = @buffer_size < size ? @buffer_size : size
|
480
|
-
buf = input.read(sz)
|
481
|
-
offset -= buf.bytesize
|
482
|
-
end
|
483
549
|
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
end
|
488
|
-
else
|
489
|
-
while size > 0
|
490
|
-
sz = @buffer_size < size ? @buffer_size : size
|
491
|
-
buf = input.read(sz)
|
492
|
-
_write_data(output, buf)
|
493
|
-
size -= buf.bytesize
|
494
|
-
end
|
550
|
+
def <<(*buf)
|
551
|
+
write(buf)
|
552
|
+
self
|
495
553
|
end
|
496
554
|
end
|
497
555
|
|
556
|
+
# preserved for compatibility with some 3rd-party handlers
|
498
557
|
def _write_data(socket, data)
|
499
558
|
socket << data
|
500
559
|
end
|