Class: WEBrick::HTTPServlet::DefaultFileHandler

Inherits:
AbstractServlet show all
Defined in:
lib/webrick/httpservlet/filehandler.rb

Instance Method Summary collapse

Methods inherited from AbstractServlet

#do_HEAD, #do_OPTIONS, get_instance, #service

Constructor Details

#initialize(server, local_path) ⇒ DefaultFileHandler

Returns a new instance of DefaultFileHandler.



22
23
24
25
# File 'lib/webrick/httpservlet/filehandler.rb', line 22

def initialize(server, local_path)
  super(server, local_path)
  @local_path = local_path
end

Instance Method Details

#do_GET(req, res) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/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) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/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) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/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) ⇒ Object



119
120
121
122
123
124
125
# File 'lib/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