ruby-changes:50773
From: normal <ko1@a...>
Date: Wed, 28 Mar 2018 17:15:37 +0900 (JST)
Subject: [ruby-changes:50773] normal:r62959 (trunk): webrick: use IO.copy_stream for multipart response
normal 2018-03-28 17:06:18 +0900 (Wed, 28 Mar 2018) New Revision: 62959 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=62959 Log: 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 Modified files: trunk/lib/webrick/httpservlet/filehandler.rb Index: lib/webrick/httpservlet/filehandler.rb =================================================================== --- lib/webrick/httpservlet/filehandler.rb (revision 62958) +++ lib/webrick/httpservlet/filehandler.rb (revision 62959) @@ -86,6 +86,30 @@ module WEBrick https://github.com/ruby/ruby/blob/trunk/lib/webrick/httpservlet/filehandler.rb#L86 return false 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) mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes]) unless ranges = HTTPUtils::parse_range_header(req['range']) @@ -96,28 +120,20 @@ module WEBrick https://github.com/ruby/ruby/blob/trunk/lib/webrick/httpservlet/filehandler.rb#L120 if ranges.size > 1 time = Time.now boundary = "#{time.sec}_#{time.usec}_#{Process::pid}" - body = '' - ranges.each{|range| - first, last = prepare_range(range, filesize) - next if first < 0 - io.pos = first - 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 + parts = [] + ranges.each {|range| + prange = prepare_range(range, filesize) + next if prange[0] < 0 + parts.concat(prange) } - raise HTTPStatus::RequestRangeNotSatisfiable if body.empty? - body << "--" << boundary << "--" << CRLF + raise HTTPStatus::RequestRangeNotSatisfiable if parts.empty? res["content-type"] = "multipart/byteranges; boundary=#{boundary}" if req.http_version < '1.1' res['connection'] = 'close' else res.chunked = true end - res.body = body + res.body = multipart_body(io.dup, parts, boundary, mtype, filesize) elsif range = ranges[0] first, last = prepare_range(range, filesize) raise HTTPStatus::RequestRangeNotSatisfiable if first < 0 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/