Class: WEBrick::HTTPServlet::DefaultFileHandler
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
AbstractServlet
|
|
Instance Chain:
self,
AbstractServlet
|
|
Inherits: |
WEBrick::HTTPServlet::AbstractServlet
|
Defined in: | lib/webrick/httpservlet/filehandler.rb |
Overview
Servlet for serving a single file. You probably want to use the FileHandler
servlet instead as it handles directories and fancy indexes.
Example:
server.mount('/my_page.txt', WEBrick::HTTPServlet::DefaultFileHandler,
'/path/to/my_page.txt')
This servlet handles If-Modified-Since and Range requests.
Class Method Summary
-
.new(server, local_path) ⇒ DefaultFileHandler
constructor
Creates a
DefaultFileHandler
instance for the file atlocal_path
.
AbstractServlet
- Inherited
.get_instance | Factory for servlet instances that will handle a request from |
.new | Initializes a new servlet for |
Instance Method Summary
- #do_GET(req, res) Internal use only
- #make_partial_content(req, res, filename, filesize) Internal use only
-
#multipart_body(body, parts, boundary, mtype, filesize)
Internal use only
returns a lambda for webrick/httpresponse.rb send_body_proc.
- #not_modified?(req, res, mtime, etag) ⇒ Boolean Internal use only
- #prepare_range(range, filesize) Internal use only
AbstractServlet
- Inherited
#do_GET | Raises a NotFound exception. |
#do_HEAD | Dispatches to do_GET. |
#do_OPTIONS | Returns the allowed HTTP request methods. |
#service | Dispatches to a |
#redirect_to_directory_uri | Redirects to a path ending in /. |
Constructor Details
.new(server, local_path) ⇒ DefaultFileHandler
Creates a DefaultFileHandler
instance for the file at local_path
.
# File 'lib/webrick/httpservlet/filehandler.rb', line 37
def initialize(server, local_path) super(server, local_path) @local_path = local_path end
Instance Method Details
#do_GET(req, res)
# File 'lib/webrick/httpservlet/filehandler.rb', line 44
def do_GET(req, res) st = File::stat(@local_path) mtime = st.mtime res['etag'] = sprintf("%x-%x-%x", st.ino, st.size, st.mtime.to_i) if not_modified?(req, res, mtime, res['etag']) res.body = '' raise HTTPStatus::NotModified elsif req['range'] make_partial_content(req, res, @local_path, st.size) raise HTTPStatus::PartialContent else mtype = HTTPUtils::mime_type(@local_path, @config[:MimeTypes]) res['content-type'] = mtype res['content-length'] = st.size.to_s res['last-modified'] = mtime.httpdate res.body = File.open(@local_path, "rb") end end
#make_partial_content(req, res, filename, filesize)
# File 'lib/webrick/httpservlet/filehandler.rb', line 118
def make_partial_content(req, res, filename, filesize) mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes]) unless ranges = HTTPUtils::parse_range_header(req['range']) raise HTTPStatus::BadRequest, "Unrecognized range-spec: \"#{req['range']}\"" end File.open(filename, "rb"){|io| if ranges.size > 1 time = Time.now boundary = "#{time.sec}_#{time.usec}_#{Process::pid}" parts = [] ranges.each {|range| prange = prepare_range(range, filesize) next if prange[0] < 0 parts.concat(prange) } 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 = multipart_body(io.dup, parts, boundary, mtype, filesize) elsif range = ranges[0] first, last = prepare_range(range, filesize) raise HTTPStatus::RequestRangeNotSatisfiable if first < 0 res['content-type'] = mtype res['content-range'] = "bytes #{first}-#{last}/#{filesize}" res['content-length'] = (last - first + 1).to_s res.body = io.dup else raise HTTPStatus::BadRequest end } end
#multipart_body(body, parts, boundary, mtype, filesize)
returns a lambda for webrick/httpresponse.rb send_body_proc
# File 'lib/webrick/httpservlet/filehandler.rb', line 90
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}" ) begin IO.copy_stream(body, socket, last - first + 1, first) rescue NotImplementedError body.seek(first, IO::SEEK_SET) IO.copy_stream(body, socket, last - first + 1) end socket.write(CRLF) end while parts[0] socket.write("--#{boundary}--#{CRLF}") ensure body.close end end end
#not_modified?(req, res, mtime, etag) ⇒ Boolean
# File 'lib/webrick/httpservlet/filehandler.rb', line 64
def not_modified?(req, res, mtime, etag) if ir = req['if-range'] begin if Time.httpdate(ir) >= mtime return true end rescue if HTTPUtils::split_header_value(ir).member?(res['etag']) return true end end end if (ims = req['if-modified-since']) && Time.parse(ims) >= mtime return true end if (inm = req['if-none-match']) && HTTPUtils::split_header_value(inm).member?(res['etag']) return true end return false end
#prepare_range(range, filesize)
# File 'lib/webrick/httpservlet/filehandler.rb', line 155
def prepare_range(range, filesize) first = range.first < 0 ? filesize + range.first : range.first return -1, -1 if first < 0 || first >= filesize last = range.last < 0 ? filesize + range.last : range.last last = filesize - 1 if last >= filesize return first, last end