In Files

  • webrick/httpservlet/filehandler.rb

Class/Module Index [+]

Quicksearch

WEBrick::HTTPServlet::DefaultFileHandler

Public Class Methods

new(server, local_path) click to toggle source
 
               # File webrick/httpservlet/filehandler.rb, line 22
def initialize(server, local_path)
  super
  @local_path = local_path
end
            

Public Instance Methods

do_GET(req, res) click to toggle source
 
               # File webrick/httpservlet/filehandler.rb, line 27
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
    res['last-modified'] = mtime.httpdate
    res.body = open(@local_path, "rb")
  end
end
            
make_partial_content(req, res, filename, filesize) click to toggle source
 
               # File webrick/httpservlet/filehandler.rb, line 72
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
  open(filename, "rb"){|io|
    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
      }
      raise HTTPStatus::RequestRangeNotSatisfiable if body.empty?
      body << "--" << boundary << "--" << CRLF
      res["content-type"] = "multipart/byteranges; boundary=#{boundary}"
      res.body = body
    elsif range = ranges[0]
      first, last = prepare_range(range, filesize)
      raise HTTPStatus::RequestRangeNotSatisfiable if first < 0
      if last == filesize - 1
        content = io.dup
        content.pos = first
      else
        io.pos = first
        content = io.read(last-first+1)
      end
      res['content-type'] = mtype
      res['content-range'] = "bytes #{first}-#{last}/#{filesize}"
      res['content-length'] = last - first + 1
      res.body = content
    else
      raise HTTPStatus::BadRequest
    end
  }
end
            
not_modified?(req, res, mtime, etag) click to toggle source
 
               # File webrick/httpservlet/filehandler.rb, line 47
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) click to toggle source
 
               # File webrick/httpservlet/filehandler.rb, line 119
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