Class: Gopher::Handlers::DirectoryHandler

Inherits:
BaseHandler
  • Object
show all
Defined in:
lib/gopher2000/handlers/directory_handler.rb

Overview

handle browsing a directory structure/returning files to the client

Constant Summary

Constants included from Rendering

Rendering::DEFAULT_ENCODING, Rendering::LINE_ENDING

Instance Attribute Summary collapse

Attributes inherited from BaseHandler

#application

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ DirectoryHandler

Returns a new instance of DirectoryHandler.

Parameters:

  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • :filter (String)

    a subset of files to show to user

  • :path (String)

    the base path of the filesystem to work from

  • :mount_point (String)

    the route for this handler – this will be used to generate paths in the response



17
18
19
20
21
22
23
24
25
26
# 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

Instance Attribute Details

#filterObject

Returns the value of attribute filter.



10
11
12
# File 'lib/gopher2000/handlers/directory_handler.rb', line 10

def filter
  @filter
end

#mount_pointObject

Returns the value of attribute mount_point.



10
11
12
# File 'lib/gopher2000/handlers/directory_handler.rb', line 10

def mount_point
  @mount_point
end

#pathObject

Returns the value of attribute path.



10
11
12
# File 'lib/gopher2000/handlers/directory_handler.rb', line 10

def path
  @path
end

Instance Method Details

#call(params = {}, request = nil) ⇒ Object

handle a request

Parameters:

  • params (Hash) (defaults to: {})

    the params as parsed during the dispatching process - the main thing here should be :splat, which will basically be the path requested.

  • request (Request) (defaults to: nil)

    the Request object for this session – not currently used?

Raises:



71
72
73
74
75
76
77
78
79
80
81
82
83
# 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) ⇒ Boolean

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

Returns:

  • (Boolean)


43
44
45
# File 'lib/gopher2000/handlers/directory_handler.rb', line 43

def contained?(p)
  (p =~ /^#{@path}/) != nil
end

#directory(dir) ⇒ Object

generate a directory listing

Parameters:

  • dir (String)

    path to directory

Returns:

  • rendered directory output for a response



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 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) ⇒ Object

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



117
118
119
# File 'lib/gopher2000/handlers/directory_handler.rb', line 117

def file(f)
  File.new(f)
end

#request_path(params) ⇒ Object

take the incoming parameters, and turn them into a path

Parameters:

  • opts (Hash)

    a customizable set of options



51
52
53
# File 'lib/gopher2000/handlers/directory_handler.rb', line 51

def request_path(params)
  File.absolute_path(sanitize(params[:splat]), @path)
end

#sanitize(p) ⇒ Object

strip slashes, extra dots, etc, from an incoming selector and turn it into a 'normalized' path

Parameters:

  • p (String)

    path to check

Returns:

  • clean path string



33
34
35
# File 'lib/gopher2000/handlers/directory_handler.rb', line 33

def sanitize(p)
  Pathname.new(p).cleanpath.to_s
end

#to_selector(path) ⇒ Object

take the path to a file and turn it into a selector which will match up when a gopher client makes requests

Parameters:

  • path (String)

    to a file on the filesytem

Returns:

  • selector which will match the file on subsequent requests



61
62
63
# File 'lib/gopher2000/handlers/directory_handler.rb', line 61

def to_selector(path)
  path.gsub(/^#{@path}/, @mount_point)
end