зеркало из https://github.com/github/ruby.git
webrick: use IO.copy_stream for multipart response
Use the new Proc response body feature to generate a multipart range response dynamically. We use a flat array to minimize object overhead as much as possible; as many ranges may fit into an HTTP request header. * lib/webrick/httpservlet/filehandler.rb (multipart_body): new method (make_partial_content): use multipart_body git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62959 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
d6c0b3d787
Коммит
4639ac8953
|
@ -86,6 +86,30 @@ module WEBrick
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# returns a lambda for webrick/httpresponse.rb send_body_proc
|
||||||
|
def multipart_body(body, parts, boundary, mtype, filesize)
|
||||||
|
lambda do |socket|
|
||||||
|
begin
|
||||||
|
begin
|
||||||
|
first = parts.shift
|
||||||
|
last = parts.shift
|
||||||
|
socket.write(
|
||||||
|
"--#{boundary}#{CRLF}" \
|
||||||
|
"Content-Type: #{mtype}#{CRLF}" \
|
||||||
|
"Content-Range: bytes #{first}-#{last}/#{filesize}#{CRLF}" \
|
||||||
|
"#{CRLF}"
|
||||||
|
)
|
||||||
|
|
||||||
|
IO.copy_stream(body, socket, last - first + 1, first)
|
||||||
|
socket.write(CRLF)
|
||||||
|
end while parts[0]
|
||||||
|
socket.write("--#{boundary}--#{CRLF}")
|
||||||
|
ensure
|
||||||
|
body.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def make_partial_content(req, res, filename, filesize)
|
def make_partial_content(req, res, filename, filesize)
|
||||||
mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes])
|
mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes])
|
||||||
unless ranges = HTTPUtils::parse_range_header(req['range'])
|
unless ranges = HTTPUtils::parse_range_header(req['range'])
|
||||||
|
@ -96,28 +120,20 @@ module WEBrick
|
||||||
if ranges.size > 1
|
if ranges.size > 1
|
||||||
time = Time.now
|
time = Time.now
|
||||||
boundary = "#{time.sec}_#{time.usec}_#{Process::pid}"
|
boundary = "#{time.sec}_#{time.usec}_#{Process::pid}"
|
||||||
body = ''
|
parts = []
|
||||||
ranges.each{|range|
|
ranges.each {|range|
|
||||||
first, last = prepare_range(range, filesize)
|
prange = prepare_range(range, filesize)
|
||||||
next if first < 0
|
next if prange[0] < 0
|
||||||
io.pos = first
|
parts.concat(prange)
|
||||||
content = io.read(last-first+1)
|
|
||||||
body << "--" << boundary << CRLF
|
|
||||||
body << "Content-Type: #{mtype}" << CRLF
|
|
||||||
body << "Content-Range: bytes #{first}-#{last}/#{filesize}" << CRLF
|
|
||||||
body << CRLF
|
|
||||||
body << content
|
|
||||||
body << CRLF
|
|
||||||
}
|
}
|
||||||
raise HTTPStatus::RequestRangeNotSatisfiable if body.empty?
|
raise HTTPStatus::RequestRangeNotSatisfiable if parts.empty?
|
||||||
body << "--" << boundary << "--" << CRLF
|
|
||||||
res["content-type"] = "multipart/byteranges; boundary=#{boundary}"
|
res["content-type"] = "multipart/byteranges; boundary=#{boundary}"
|
||||||
if req.http_version < '1.1'
|
if req.http_version < '1.1'
|
||||||
res['connection'] = 'close'
|
res['connection'] = 'close'
|
||||||
else
|
else
|
||||||
res.chunked = true
|
res.chunked = true
|
||||||
end
|
end
|
||||||
res.body = body
|
res.body = multipart_body(io.dup, parts, boundary, mtype, filesize)
|
||||||
elsif range = ranges[0]
|
elsif range = ranges[0]
|
||||||
first, last = prepare_range(range, filesize)
|
first, last = prepare_range(range, filesize)
|
||||||
raise HTTPStatus::RequestRangeNotSatisfiable if first < 0
|
raise HTTPStatus::RequestRangeNotSatisfiable if first < 0
|
||||||
|
|
Загрузка…
Ссылка в новой задаче