Module: ServerSide::StaticFiles

Included in:
HTTP::Request
Defined in:
lib/serverside/static.rb

Overview

This module provides functionality for serving files and directory listings over HTTP.

Defined Under Namespace

Modules: Const

Constant Summary collapse

@@mime_types =
Hash.new {|h, k| ServerSide::StaticFiles::Const::TextPlain}
@@static_files =
{}

Instance Method Summary collapse

Instance Method Details

#serve_dir(dir) ⇒ Object

Serves a directory listing over HTTP in the form of an HTML page.



80
81
82
83
84
85
86
# File 'lib/serverside/static.rb', line 80

def serve_dir(dir)
  html = (Const::DirListingStart % [@path, @path]) +
    Dir.entries(dir).inject('') {|m, fn|
      (fn == '.') ? m : m << Const::DirListing % [@path/fn, fn]
    } + Const::DirListingStop
  send_response(200, 'text/html', html)
end

#serve_file(fn) ⇒ Object

Serves a file over HTTP. The file is cached in memory for later retrieval. If the If-None-Match header is included with an ETag, it is checked against the file’s current ETag. If there’s a match, a 304 response is rendered.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/serverside/static.rb', line 47

def serve_file(fn)
  stat = File.stat(fn)
  etag = (Const::ETagFormat % [stat.mtime.to_i, stat.size, stat.ino]).freeze
  date = stat.mtime.httpdate
  
  etag_match = @headers[Const::IfNoneMatch]
  last_date = @headers[Const::IfModifiedSince]
  
  modified = (!etag_match && !last_date) || 
    (etag_match && (etag != etag_match)) || (last_date && (last_date != date))
  
  if modified
    if @@static_files[fn] && (@@static_files[fn][0] == etag)
      content = @@static_files[fn][1]
    else
      content = IO.read(fn).freeze
      @@static_files[fn] = [etag.freeze, content]
    end
    
    send_response(200, @@mime_types[File.extname(fn)], content, stat.size, {
      Const::ETag => etag, 
      Const::LastModified => date, 
      Const::CacheControl => Const::MaxAge
    })
  else
    @socket << ((@persistent ? Const::NotModifiedPersist : 
      Const::NotModifiedClose) % [Time.now.httpdate, date, etag, stat.size])
  end
rescue => e
  send_response(404, Const::TextPlain, 'Error reading file.')
end

#serve_static(path) ⇒ Object

Serves static files and directory listings.



95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/serverside/static.rb', line 95

def serve_static(path)
  if File.file?(path)
    serve_file(path)
  elsif serve_template(path)
    return
  elsif File.directory?(path)
    serve_dir(path)
  else
    send_response(404, 'text', Const::FileNotFound)
  end
rescue => e
  send_response(500, 'text', e.message)
end

#serve_template(fn, b = nil) ⇒ Object



88
89
90
91
92
# File 'lib/serverside/static.rb', line 88

def serve_template(fn, b = nil)
  if (fn =~ Const::RHTML) || (File.file?(fn = fn + '.rhtml'))
    send_response(200, Const::TextHTML, Template.render(fn, b || binding))
  end
end