Class WEBrick::HTTPServlet::FileHandler
In: lib/webrick/httpservlet/filehandler.rb
Parent: AbstractServlet

Methods

Constants

HandlerTable = Hash.new

Public Class methods

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 131
131:       def self.add_handler(suffix, handler)
132:         HandlerTable[suffix] = handler
133:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 139
139:       def initialize(server, root, options={}, default=Config::FileHandler)
140:         @config = server.config
141:         @logger = @config[:Logger]
142:         @root = File.expand_path(root)
143:         if options == true || options == false
144:           options = { :FancyIndexing => options }
145:         end
146:         @options = default.dup.update(options)
147:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 135
135:       def self.remove_handler(suffix)
136:         HandlerTable.delete(suffix)
137:       end

Public Instance methods

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 170
170:       def do_GET(req, res)
171:         unless exec_handler(req, res)
172:           set_dir_list(req, res)
173:         end
174:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 182
182:       def do_OPTIONS(req, res)
183:         unless exec_handler(req, res)
184:           super(req, res)
185:         end
186:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 176
176:       def do_POST(req, res)
177:         unless exec_handler(req, res)
178:           raise HTTPStatus::NotFound, "`#{req.path}' not found."
179:         end
180:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 149
149:       def service(req, res)
150:         # if this class is mounted on "/" and /~username is requested.
151:         # we're going to override path informations before invoking service.
152:         if defined?(Etc) && @options[:UserDir] && req.script_name.empty?
153:           if %r|^(/~([^/]+))| =~ req.path_info
154:             script_name, user = $1, $2
155:             path_info = $'
156:             begin
157:               passwd = Etc::getpwnam(user)
158:               @root = File::join(passwd.dir, @options[:UserDir])
159:               req.script_name = script_name
160:               req.path_info = path_info
161:             rescue
162:               @logger.debug "#{self.class}#do_GET: getpwnam(#{user}) failed"
163:             end
164:           end
165:         end
166:         prevent_directory_traversal(req, res)
167:         super(req, res)
168:       end

Private Instance methods

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 322
322:       def call_callback(callback_name, req, res)
323:         if cb = @options[callback_name]
324:           cb.call(req, res)
325:         end
326:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 274
274:       def check_filename(req, res, name)
275:         @options[:NondisclosureName].each{|pattern|
276:           if File.fnmatch("/#{pattern}", name, File::FNM_CASEFOLD)
277:             @logger.warn("the request refers nondisclosure name `#{name}'.")
278:             raise HTTPStatus::NotFound, "`#{req.path}' not found."
279:           end
280:         }
281:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 218
218:       def exec_handler(req, res)
219:         raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root
220:         if set_filename(req, res)
221:           handler = get_handler(req)
222:           call_callback(:HandlerCallback, req, res)
223:           h = handler.get_instance(@config, res.filename)
224:           h.service(req, res)
225:           return true
226:         end
227:         call_callback(:HandlerCallback, req, res)
228:         return false
229:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 231
231:       def get_handler(req)
232:         suffix1 = (/\.(\w+)$/ =~ req.script_name) && $1.downcase
233:         suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ req.script_name) && $1.downcase
234:         handler_table = @options[:HandlerTable]
235:         return handler_table[suffix1] || handler_table[suffix2] ||
236:                HandlerTable[suffix1] || HandlerTable[suffix2] ||
237:                DefaultFileHandler
238:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 328
328:       def nondisclosure_name?(name)
329:         @options[:NondisclosureName].each{|pattern|
330:           if File.fnmatch(pattern, name, File::FNM_CASEFOLD)
331:             return true
332:           end
333:         }
334:         return false
335:       end

RFC3253: Versioning Extensions to WebDAV

         (Web Distributed Authoring and Versioning)

VERSION-CONTROL REPORT CHECKOUT CHECK_IN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE ACTIVITY

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 202
202:       def prevent_directory_traversal(req, res)
203:         # Preventing directory traversal on DOSISH platforms;
204:         # Backslashes (0x5c) in path_info are not interpreted as special
205:         # character in URI notation. So the value of path_info should be
206:         # normalize before accessing to the filesystem.
207:         if File::ALT_SEPARATOR
208:           # File.expand_path removes the trailing path separator.
209:           # Adding a character is a workaround to save it.
210:           #  File.expand_path("/aaa/")        #=> "/aaa"
211:           #  File.expand_path("/aaa/" + "x")  #=> "/aaa/x"
212:           expanded = File.expand_path(req.path_info + "x")
213:           expanded[-1, 1] = ""  # remove trailing "x"
214:           req.path_info = expanded
215:         end
216:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 300
300:       def search_file(req, res, basename)
301:         langs = @options[:AcceptableLanguages]
302:         path = res.filename + basename
303:         if File.file?(path)
304:           return basename
305:         elsif langs.size > 0
306:           req.accept_language.each{|lang|
307:             path_with_lang = path + ".#{lang}"
308:             if langs.member?(lang) && File.file?(path_with_lang)
309:               return basename + ".#{lang}"
310:             end
311:           }
312:           (langs - req.accept_language).each{|lang|
313:             path_with_lang = path + ".#{lang}"
314:             if File.file?(path_with_lang)
315:               return basename + ".#{lang}"
316:             end
317:           }
318:         end
319:         return nil
320:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 291
291:       def search_index_file(req, res)
292:         @config[:DirectoryIndex].each{|index|
293:           if file = search_file(req, res, "/"+index)
294:             return file
295:           end
296:         }
297:         return nil
298:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 337
337:       def set_dir_list(req, res)
338:         redirect_to_directory_uri(req, res)
339:         unless @options[:FancyIndexing]
340:           raise HTTPStatus::Forbidden, "no access permission to `#{req.path}'"
341:         end
342:         local_path = res.filename
343:         list = Dir::entries(local_path).collect{|name|
344:           next if name == "." || name == ".."
345:           next if nondisclosure_name?(name)
346:           st = (File::stat(local_path + name) rescue nil)
347:           if st.nil?
348:             [ name, nil, -1 ]
349:           elsif st.directory?
350:             [ name + "/", st.mtime, -1 ]
351:           else
352:             [ name, st.mtime, st.size ]
353:           end
354:         }
355:         list.compact!
356: 
357:         if    d0 = req.query["N"]; idx = 0
358:         elsif d0 = req.query["M"]; idx = 1
359:         elsif d0 = req.query["S"]; idx = 2
360:         else  d0 = "A"           ; idx = 0
361:         end
362:         d1 = (d0 == "A") ? "D" : "A"
363: 
364:         if d0 == "A"
365:           list.sort!{|a,b| a[idx] <=> b[idx] }
366:         else
367:           list.sort!{|a,b| b[idx] <=> a[idx] }
368:         end
369: 
370:         res['content-type'] = "text/html"
371: 
372:         res.body = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<HTML>\n<HEAD><TITLE>Index of \#{HTMLUtils::escape(req.path)}</TITLE></HEAD>\n<BODY>\n<H1>Index of \#{HTMLUtils::escape(req.path)}</H1>\n"
373: 
374:         res.body << "<PRE>\n"
375:         res.body << " <A HREF=\"?N=#{d1}\">Name</A>                          "
376:         res.body << "<A HREF=\"?M=#{d1}\">Last modified</A>         "
377:         res.body << "<A HREF=\"?S=#{d1}\">Size</A>\n"
378:         res.body << "<HR>\n"
379:        
380:         list.unshift [ "..", File::mtime(local_path+".."), -1 ]
381:         list.each{ |name, time, size|
382:           if name == ".."
383:             dname = "Parent Directory"
384:           elsif name.size > 25
385:             dname = name.sub(/^(.{23})(.*)/){ $1 + ".." }
386:           else
387:             dname = name
388:           end
389:           s =  " <A HREF=\"#{HTTPUtils::escape(name)}\">#{dname}</A>"
390:           s << " " * (30 - dname.size)
391:           s << (time ? time.strftime("%Y/%m/%d %H:%M      ") : " " * 22)
392:           s << (size >= 0 ? size.to_s : "-") << "\n"
393:           res.body << s
394:         }
395:         res.body << "</PRE><HR>"
396: 
397:         res.body << "<ADDRESS>\n\#{HTMLUtils::escape(@config[:ServerSoftware])}<BR>\nat \#{req.host}:\#{req.port}\n</ADDRESS>\n</BODY>\n</HTML>\n"    
398:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 240
240:       def set_filename(req, res)
241:         res.filename = @root.dup
242:         path_info = req.path_info.scan(%r|/[^/]*|)
243: 
244:         path_info.unshift("")  # dummy for checking @root dir
245:         while base = path_info.first
246:           check_filename(req, res, base)
247:           break if base == "/"
248:           break unless File.directory?(res.filename + base)
249:           shift_path_info(req, res, path_info)
250:           call_callback(:DirectoryCallback, req, res)
251:         end
252: 
253:         if base = path_info.first
254:           check_filename(req, res, base)
255:           if base == "/"
256:             if file = search_index_file(req, res)
257:               shift_path_info(req, res, path_info, file)
258:               call_callback(:FileCallback, req, res)
259:               return true
260:             end
261:             shift_path_info(req, res, path_info)
262:           elsif file = search_file(req, res, base)
263:             shift_path_info(req, res, path_info, file)
264:             call_callback(:FileCallback, req, res)
265:             return true
266:           else
267:             raise HTTPStatus::NotFound, "`#{req.path}' not found."
268:           end
269:         end
270: 
271:         return false
272:       end

[Source]

     # File lib/webrick/httpservlet/filehandler.rb, line 283
283:       def shift_path_info(req, res, path_info, base=nil)
284:         tmp = path_info.shift
285:         base = base || tmp
286:         req.path_info = path_info.join
287:         req.script_name << base
288:         res.filename << base
289:       end

[Validate]