Class: WEBrick::HTTPServlet::DefaultFileHandler
- Inherits:
-
AbstractServlet
- Object
- AbstractServlet
- WEBrick::HTTPServlet::DefaultFileHandler
- 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.
Instance Method Summary collapse
-
#do_GET(req, res) ⇒ Object
:stopdoc:.
-
#initialize(server, local_path) ⇒ DefaultFileHandler
constructor
Creates a DefaultFileHandler instance for the file at
local_path
. - #make_partial_content(req, res, filename, filesize) ⇒ Object
-
#multipart_body(body, parts, boundary, mtype, filesize) ⇒ Object
returns a lambda for webrick/httpresponse.rb send_body_proc.
- #not_modified?(req, res, mtime, etag) ⇒ Boolean
- #prepare_range(range, filesize) ⇒ Object
Methods inherited from AbstractServlet
#do_HEAD, #do_OPTIONS, get_instance, #service
Constructor Details
#initialize(server, local_path) ⇒ DefaultFileHandler
Creates a DefaultFileHandler instance for the file at local_path
.
37 38 39 40 |
# 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) ⇒ Object
:stopdoc:
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# 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) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# 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) ⇒ Object
returns a lambda for webrick/httpresponse.rb send_body_proc
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 |
# 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
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# 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) ⇒ Object
155 156 157 158 159 160 161 |
# 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 |