webrick 1.4.2 → 1.7.0
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.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +61 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/webrick.rb +8 -3
- 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/authenticator.rb +1 -1
- data/lib/webrick/httpauth/basicauth.rb +13 -5
- data/lib/webrick/httpauth/digestauth.rb +10 -23
- data/lib/webrick/httpauth/htdigest.rb +2 -2
- data/lib/webrick/httpauth/htgroup.rb +7 -4
- data/lib/webrick/httpauth/htpasswd.rb +37 -4
- data/lib/webrick/httpproxy.rb +51 -35
- data/lib/webrick/httprequest.rb +65 -16
- 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/cgihandler.rb +10 -6
- data/lib/webrick/httpservlet/erbhandler.rb +1 -1
- data/lib/webrick/httpservlet/filehandler.rb +62 -32
- data/lib/webrick/httpservlet/prochandler.rb +1 -1
- data/lib/webrick/httpstatus.rb +1 -1
- data/lib/webrick/httputils.rb +3 -4
- data/lib/webrick/server.rb +5 -2
- data/lib/webrick/ssl.rb +3 -3
- data/lib/webrick/utils.rb +1 -6
- data/lib/webrick/version.rb +1 -1
- data/webrick.gemspec +74 -0
- metadata +18 -13
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
|
@@ -115,7 +115,7 @@ module WEBrick
|
|
115
115
|
proxy_auth(req, res)
|
116
116
|
|
117
117
|
begin
|
118
|
-
|
118
|
+
public_send("do_#{req.request_method}", req, res)
|
119
119
|
rescue NoMethodError
|
120
120
|
raise HTTPStatus::MethodNotAllowed,
|
121
121
|
"unsupported method `#{req.request_method}'."
|
@@ -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,60 @@ module WEBrick
|
|
301
295
|
return FakeProxyURI
|
302
296
|
end
|
303
297
|
|
304
|
-
def
|
298
|
+
def create_net_http(uri, upstream)
|
299
|
+
Net::HTTP.new(uri.host, uri.port, upstream.host, upstream.port)
|
300
|
+
end
|
301
|
+
|
302
|
+
def perform_proxy_request(req, res, req_class, body_stream = nil)
|
305
303
|
uri = req.request_uri
|
306
304
|
path = uri.path.dup
|
307
305
|
path << "?" << uri.query if uri.query
|
308
306
|
header = setup_proxy_header(req, res)
|
309
307
|
upstream = setup_upstream_proxy_authentication(req, res, header)
|
310
|
-
|
311
|
-
|
312
|
-
http =
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
308
|
+
|
309
|
+
body_tmp = []
|
310
|
+
http = create_net_http(uri, upstream)
|
311
|
+
req_fib = Fiber.new do
|
312
|
+
http.start do
|
313
|
+
if @config[:ProxyTimeout]
|
314
|
+
################################## these issues are
|
315
|
+
http.open_timeout = 30 # secs # necessary (maybe because
|
316
|
+
http.read_timeout = 60 # secs # Ruby's bug, but why?)
|
317
|
+
##################################
|
318
|
+
end
|
319
|
+
if body_stream && req['transfer-encoding'] =~ /\bchunked\b/i
|
320
|
+
header['Transfer-Encoding'] = 'chunked'
|
321
|
+
end
|
322
|
+
http_req = req_class.new(path, header)
|
323
|
+
http_req.body_stream = body_stream if body_stream
|
324
|
+
http.request(http_req) do |response|
|
325
|
+
# Persistent connection requirements are mysterious for me.
|
326
|
+
# So I will close the connection in every response.
|
327
|
+
res['proxy-connection'] = "close"
|
328
|
+
res['connection'] = "close"
|
329
|
+
|
330
|
+
# stream Net::HTTP::HTTPResponse to WEBrick::HTTPResponse
|
331
|
+
res.status = response.code.to_i
|
332
|
+
res.chunked = response.chunked?
|
333
|
+
choose_header(response, res)
|
334
|
+
set_cookie(response, res)
|
335
|
+
set_via(res)
|
336
|
+
response.read_body do |buf|
|
337
|
+
body_tmp << buf
|
338
|
+
Fiber.yield # wait for res.body Proc#call
|
339
|
+
end
|
340
|
+
end # http.request
|
341
|
+
end
|
342
|
+
end
|
343
|
+
req_fib.resume # read HTTP response headers and first chunk of the body
|
344
|
+
res.body = ->(socket) do
|
345
|
+
while buf = body_tmp.shift
|
346
|
+
socket.write(buf)
|
347
|
+
buf.clear
|
348
|
+
req_fib.resume # continue response.read_body
|
319
349
|
end
|
320
|
-
response = yield(http, path, header)
|
321
350
|
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
351
|
end
|
335
|
-
|
336
352
|
# :stopdoc:
|
337
353
|
end
|
338
354
|
end
|
data/lib/webrick/httprequest.rb
CHANGED
@@ -9,11 +9,12 @@
|
|
9
9
|
#
|
10
10
|
# $IPR: httprequest.rb,v 1.64 2003/07/13 17:18:22 gotoyuzo Exp $
|
11
11
|
|
12
|
+
require 'fiber'
|
12
13
|
require 'uri'
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
require_relative 'httpversion'
|
15
|
+
require_relative 'httpstatus'
|
16
|
+
require_relative 'httputils'
|
17
|
+
require_relative 'cookie'
|
17
18
|
|
18
19
|
module WEBrick
|
19
20
|
|
@@ -226,9 +227,9 @@ module WEBrick
|
|
226
227
|
raise HTTPStatus::BadRequest, "bad URI `#{@unparsed_uri}'."
|
227
228
|
end
|
228
229
|
|
229
|
-
if /
|
230
|
+
if /\Aclose\z/io =~ self["connection"]
|
230
231
|
@keep_alive = false
|
231
|
-
elsif
|
232
|
+
elsif /\Akeep-alive\z/io =~ self["connection"]
|
232
233
|
@keep_alive = true
|
233
234
|
elsif @http_version < "1.1"
|
234
235
|
@keep_alive = false
|
@@ -257,6 +258,36 @@ module WEBrick
|
|
257
258
|
@body.empty? ? nil : @body
|
258
259
|
end
|
259
260
|
|
261
|
+
##
|
262
|
+
# Prepares the HTTPRequest object for use as the
|
263
|
+
# source for IO.copy_stream
|
264
|
+
|
265
|
+
def body_reader
|
266
|
+
@body_tmp = []
|
267
|
+
@body_rd = Fiber.new do
|
268
|
+
body do |buf|
|
269
|
+
@body_tmp << buf
|
270
|
+
Fiber.yield
|
271
|
+
end
|
272
|
+
end
|
273
|
+
@body_rd.resume # grab the first chunk and yield
|
274
|
+
self
|
275
|
+
end
|
276
|
+
|
277
|
+
# for IO.copy_stream.
|
278
|
+
def readpartial(size, buf = ''.b) # :nodoc
|
279
|
+
res = @body_tmp.shift or raise EOFError, 'end of file reached'
|
280
|
+
if res.length > size
|
281
|
+
@body_tmp.unshift(res[size..-1])
|
282
|
+
res = res[0..size - 1]
|
283
|
+
end
|
284
|
+
buf.replace(res)
|
285
|
+
res.clear
|
286
|
+
# get more chunks - check alive? because we can take a partial chunk
|
287
|
+
@body_rd.resume if @body_rd.alive?
|
288
|
+
buf
|
289
|
+
end
|
290
|
+
|
260
291
|
##
|
261
292
|
# Request query as a Hash
|
262
293
|
|
@@ -414,13 +445,19 @@ module WEBrick
|
|
414
445
|
|
415
446
|
MAX_URI_LENGTH = 2083 # :nodoc:
|
416
447
|
|
448
|
+
# same as Mongrel, Thin and Puma
|
449
|
+
MAX_HEADER_LENGTH = (112 * 1024) # :nodoc:
|
450
|
+
|
417
451
|
def read_request_line(socket)
|
418
452
|
@request_line = read_line(socket, MAX_URI_LENGTH) if socket
|
419
|
-
|
453
|
+
raise HTTPStatus::EOFError unless @request_line
|
454
|
+
|
455
|
+
@request_bytes = @request_line.bytesize
|
456
|
+
if @request_bytes >= MAX_URI_LENGTH and @request_line[-1, 1] != LF
|
420
457
|
raise HTTPStatus::RequestURITooLarge
|
421
458
|
end
|
459
|
+
|
422
460
|
@request_time = Time.now
|
423
|
-
raise HTTPStatus::EOFError unless @request_line
|
424
461
|
if /^(\S+)\s+(\S++)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line
|
425
462
|
@request_method = $1
|
426
463
|
@unparsed_uri = $2
|
@@ -435,6 +472,9 @@ module WEBrick
|
|
435
472
|
if socket
|
436
473
|
while line = read_line(socket)
|
437
474
|
break if /\A(#{CRLF}|#{LF})\z/om =~ line
|
475
|
+
if (@request_bytes += line.bytesize) > MAX_HEADER_LENGTH
|
476
|
+
raise HTTPStatus::RequestEntityTooLarge, 'headers too large'
|
477
|
+
end
|
438
478
|
@raw_header << line
|
439
479
|
end
|
440
480
|
end
|
@@ -468,7 +508,7 @@ module WEBrick
|
|
468
508
|
return unless socket
|
469
509
|
if tc = self['transfer-encoding']
|
470
510
|
case tc
|
471
|
-
when /
|
511
|
+
when /\Achunked\z/io then read_chunked(socket, block)
|
472
512
|
else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}."
|
473
513
|
end
|
474
514
|
elsif self['content-length'] || @remaining_size
|
@@ -482,7 +522,7 @@ module WEBrick
|
|
482
522
|
if @remaining_size > 0 && @socket.eof?
|
483
523
|
raise HTTPStatus::BadRequest, "invalid body size."
|
484
524
|
end
|
485
|
-
elsif BODY_CONTAINABLE_METHODS.member?(@request_method)
|
525
|
+
elsif BODY_CONTAINABLE_METHODS.member?(@request_method) && !@socket.eof
|
486
526
|
raise HTTPStatus::LengthRequired
|
487
527
|
end
|
488
528
|
return @body
|
@@ -502,12 +542,16 @@ module WEBrick
|
|
502
542
|
def read_chunked(socket, block)
|
503
543
|
chunk_size, = read_chunk_size(socket)
|
504
544
|
while chunk_size > 0
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
545
|
+
begin
|
546
|
+
sz = [ chunk_size, @buffer_size ].min
|
547
|
+
data = read_data(socket, sz) # read chunk-data
|
548
|
+
if data.nil? || data.bytesize != sz
|
549
|
+
raise HTTPStatus::BadRequest, "bad chunk data size."
|
550
|
+
end
|
551
|
+
block.call(data)
|
552
|
+
end while (chunk_size -= sz) > 0
|
553
|
+
|
509
554
|
read_line(socket) # skip CRLF
|
510
|
-
block.call(data)
|
511
555
|
chunk_size, = read_chunk_size(socket)
|
512
556
|
end
|
513
557
|
read_header(socket) # trailer + CRLF
|
@@ -572,7 +616,12 @@ module WEBrick
|
|
572
616
|
end
|
573
617
|
if host_port = self["x-forwarded-host"]
|
574
618
|
host_port = host_port.split(",", 2).first
|
575
|
-
|
619
|
+
if host_port =~ /\A(\[[0-9a-fA-F:]+\])(?::(\d+))?\z/
|
620
|
+
@forwarded_host = $1
|
621
|
+
tmp = $2
|
622
|
+
else
|
623
|
+
@forwarded_host, tmp = host_port.split(":", 2)
|
624
|
+
end
|
576
625
|
@forwarded_port = (tmp || (@forwarded_proto == "https" ? 443 : 80)).to_i
|
577
626
|
end
|
578
627
|
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
|