class Gopher::Handlers::DirectoryHandler

handle browsing a directory structure/returning files to the client

Attributes

filter[RW]
mount_point[RW]
path[RW]

Public Class Methods

new(opts = {}) click to toggle source

@option opts [String] :filter a subset of files to show to user @option opts [String] :path the base path of the filesystem to work from @option opts [String] :mount_point the route for this handler – this will be used to generate paths in the response

# File lib/gopher2000/handlers/directory_handler.rb, line 17
def initialize(opts = {})
  opts = {
    :filter => "*.*",
    :path => Dir.getwd
  }.merge(opts)

  @path = opts[:path]
  @filter = opts[:filter]
  @mount_point = opts[:mount_point]
end

Public Instance Methods

call(params = {}, request = nil) click to toggle source

handle a request

@param [Hash] params the params as parsed during the dispatching process - the main thing here should be :splat, which will basically be the path requested. @param [Request] request the Request object for this session – not currently used?

# File lib/gopher2000/handlers/directory_handler.rb, line 71
def call(params = {}, request = nil)
  lookup = request_path(params)

  raise Gopher::InvalidRequest if ! contained?(lookup)

  if File.directory?(lookup)
    directory(lookup)
  elsif File.file?(lookup)
    file(lookup)
  else
    raise Gopher::NotFoundError
  end
end
contained?(p) click to toggle source

make sure that the requested file is actually contained within our mount point. this prevents requests like the below from working:

echo “/files/../../../../../tmp/foo” | nc localhost 7070

# File lib/gopher2000/handlers/directory_handler.rb, line 43
def contained?(p)
  (p =~ /^#{@path}/) != nil
end
directory(dir) click to toggle source

generate a directory listing @param [String] dir path to directory @return rendered directory output for a response

# File lib/gopher2000/handlers/directory_handler.rb, line 90
def directory(dir)
  m = Menu.new(@application)

  m.text "Browsing: #{dir}"

  #
  # iterate through the contents of this directory.
  # NOTE: we don't filter this, so we will ALWAYS list subdirectories of a mounted folder
  #
  Dir.glob("#{dir}/*").each do |x|
    # if this is a directory, then generate a directory link for it
    if File.directory?(x)
      m.directory File.basename(x), to_selector(x), @application.host, @application.port

    elsif File.file?(x) && File.fnmatch(filter, x)
      # fnmatch makes sure that the file matches the glob filter specified in the mount directive

      # otherwise, it's a normal file link
      m.link File.basename(x), to_selector(x), @application.host, @application.port
    end
  end
  m.to_s
end
file(f) click to toggle source

return a file handle – Connection will take this and send it back to the client

# File lib/gopher2000/handlers/directory_handler.rb, line 117
def file(f)
  File.new(f)
end
request_path(params) click to toggle source

take the incoming parameters, and turn them into a path @option opts [String] :splat splat value from Request params

# File lib/gopher2000/handlers/directory_handler.rb, line 51
def request_path(params)
  File.absolute_path(sanitize(params[:splat]), @path)
end
sanitize(p) click to toggle source

strip slashes, extra dots, etc, from an incoming selector and turn it into a ‘normalized’ path @param [String] p path to check @return clean path string

# File lib/gopher2000/handlers/directory_handler.rb, line 33
def sanitize(p)
  Pathname.new(p).cleanpath.to_s
end
to_selector(path) click to toggle source

take the path to a file and turn it into a selector which will match up when a gopher client makes requests @param [String] path to a file on the filesytem @return selector which will match the file on subsequent requests

# File lib/gopher2000/handlers/directory_handler.rb, line 61
def to_selector(path)
  path.gsub(/^#{@path}/, @mount_point)
end