# Copyright (c) 2007 Pat Allan - pat@freelancing-gods.com # You can redistribute it and/or modify it under the same terms as Ruby. # # Built on the DirHandler in Mongrel. It will not remove tar files generated for # directories - keeps them to save on regeneration. # # Usage: # ruby browser.rb # # Example: # ruby browser.rb 3001 /Volumes/Media/Movies # # Changes that would be nice: # - Ability to run and clear tar files that match a directory name (ie: avoid other tar files # that weren't generated by this server). # - Read a YAML file to set up multiple handlers over the same port # - Have an index page that automatically lists all handlers being served # - Check if files have been modified since the tar file was created, and regenerate the tar # file if needed require 'rubygems' require 'mongrel' class BrowserHandler < Mongrel::DirHandler def process(request, response) # extremely basic logging to STDOUT unless request.params["REQUEST_URI"] == "/favicon.ico" puts "IP: #{request.params["REMOTE_ADDR"]}\nREQUEST: #{request.params["REQUEST_URI"]}\n\n" super(request, response) end end def can_serve(path_info) req_path = File.expand_path(File.join(@path,Mongrel::HttpRequest.unescape(path_info)), @path) # fool the server into thinking the tar file exists even if it doesn't unless File.exist?(req_path) && req_path["\.tar$"].nil? return req_path else return super(path_info) end end def send_dir_listing(base, dir, response) base = Mongrel::HttpRequest.unescape(base) base.chop! if base[-1] == "/"[-1] if @listing_allowed response.start(200) do |head,out| head[Mongrel::Const::CONTENT_TYPE] = "text/html" out << "Browser: #{base}" out << "

Back up a level

" out << "

Download this folder as a tar file

" if base.length > 0 out << "" end else response.start(403) do |head,out| out.write("Directory listings not allowed") end end end def send_file(req_path, request, response, header_only=false) # generate tar file if required unless File.exist?(req_path) && req_path[/\.tar$/].nil? Dir.chdir(req_path.gsub(/\.tar$/, '') + "/..") system("tar -cf \"#{req_path[/\/([^\/]+\.tar)$/, 1]}\" \"#{req_path[/\/([^\/]+)\.tar$/, 1]}\"") end response.header['Content-Disposition'] = "attachment" super(req_path, request, response, header_only) end end require 'optparse' options = { :port => 3000, :directories => [] } OptionParser.new do |opts| opts.banner = "Usage: browser.rb --file directories.yml" opts.on("-p", "--port PORT", "Port to bind to") do |p| options[:port] = p end opts.on("-f", "--file FILE", "YAML listing of directories") do |yaml| options[:directories] = YAML.load_file(yaml) end end.parse! class IndexHandler < Mongrel::HttpHandler def initialize(directories) @directories = directories puts @directories.inspect end def process(request, response) response.start(200) do |head,out| head["Content-Type"] = "text/html" out << "Browser index" puts @directories.inspect if @directories.any? @directories.each do |k,directory| out << "#{directory['uri']}
" end else out << "No fucking directories, im a souless bastard." end out << "" end end end h = Mongrel::HttpServer.new("0.0.0.0", options[:port]) h.register('/', IndexHandler.new(options[:directories])) options[:directories].each do |k,directory| h.register(directory['uri'], BrowserHandler.new(directory['path'])) end h.run.join