class VaeSiteServlet

Constants

SERVER_PARSED

Public Class Methods

new(site) click to toggle source
# File lib/vae_site_servlet.rb, line 4
def initialize(site)
  @cache = {}
  @changed = {}
  @lock = Mutex.new
  @site = site

  dw = DirectoryWatcher.new @site.root, interval: 1.0, glob: SERVER_PARSED.map { |ext| "**/*#{ext}" }, pre_load: true, logger: DirectoryWatcher::NullLogger.new
  dw.add_observer { |*args|
    args.each { |event|
      path = event.path.gsub(@site.root, "")
      @lock.synchronize {
        @changed[path] = event.type
      }
    }
  }
  dw.start
end

Public Instance Methods

bundle_changed_source_files(source_files) click to toggle source
# File lib/vae_site_servlet.rb, line 22
def bundle_changed_source_files(source_files)
  source_files ||= []
  changed = nil
  @lock.synchronize {
    changed = @changed
    @changed = {}
  }
  source_files.concat(changed.map { |filename,action|
    begin
      get_source_file(filename, (action == :deleted))
    rescue FileNotFound
      nil
    end
  }).reject { |src| src.nil? }
end
fetch_from_vae(wb_req, method, source_files = nil) click to toggle source
# File lib/vae_site_servlet.rb, line 71
def fetch_from_vae(wb_req, method, source_files = nil)
  uri = wb_req.params["REQUEST_URI"] + ((wb_req.params["REQUEST_URI"] =~ /\?/) ? "&" : "?") + "__vae_local=#{@site.session_id}"
  source_files = bundle_changed_source_files(source_files)
  if method == "GET"
    if source_files.is_a?(Array) and source_files.size > 0
      req = Net::HTTP::Post.new(uri)
      source_files.map { |src| puts "sending #{src[0]}" }
      req.body = source_files.collect { |src| "__vae_local_files[#{src[0]}]=#{CGI.escape(src[1])}" }.join("&")
    else
      req = Net::HTTP::Get.new(uri)
    end
  else
    if source_files.is_a?(Array) and source_files.size > 0
      fetch_from_vae(wb_req, "GET", source_files)
    end
    req = Net::HTTP::Post.new(uri)
    req.body = wb_req.body.read
  end
  req_404 = Net::HTTP::Get.new("/error_pages/not_found.html")
  req['cookie'] = req_404['cookie'] = wb_req.params["HTTP_COOKIE"]
  if wb_req.params['HTTP_X_REQUESTED_WITH']
    req['X-Requested-With'] = req_404['X-Requested-With'] = wb_req.params['HTTP_X_REQUESTED_WITH']
  end
  req['X-Vae-Local-Host'] = wb_req.params['HTTP_HOST']
  res = @site.fetch_from_server(req)
  if res.body =~ /__vae_local_needs=(.*)/
    begin
      return fetch_from_vae(wb_req, method, [ get_source_file($1) ])
    rescue FileNotFound
      puts "* Could not find requested file: #{$1}"
      return @site.fetch_from_server(req_404)
    end
  end
  res
end
fetch_from_vae_and_include_source_of_current_page(req, method) click to toggle source
# File lib/vae_site_servlet.rb, line 107
def fetch_from_vae_and_include_source_of_current_page(req, method)
  fetch_from_vae(req, method, [ find_source_file_from_path(req.params["REQUEST_URI"]), get_source_file("/__vae.php", true), get_source_file("/__verb.php", true) ])
end
find_source_file_from_path(path) click to toggle source
# File lib/vae_site_servlet.rb, line 111
def find_source_file_from_path(path)
  path_parts = path.split("/").reject { |part| part.length < 1 }
  local_path = ""
  loop do
    gotit = false
    if part = path_parts.shift
      new_local_path = local_path + "/" + part
      (SERVER_PARSED + [ "" ]).each do |ext|
        if File.exists?(@site.root + new_local_path + ext)
          gotit = true
          local_path = new_local_path + ext
        end
      end
    end
    break unless gotit
  end
  return nil unless local_path.length > 0
  get_source_file(local_path)
end
get_line_from_sass_exception(exception) click to toggle source
# File lib/vae_site_servlet.rb, line 131
def get_line_from_sass_exception(exception)
  return exception.message.scan(/:(\d+)/).first.first if exception.is_a?(::SyntaxError)
  exception.backtrace[0].scan(/:(\d+)/).first.first
end
get_source_file(path, optional = false) click to toggle source
# File lib/vae_site_servlet.rb, line 38
def get_source_file(path, optional = false)
  full_path = nil
  if File.exists?(@site.root + path)
    full_path = path
  else
    SERVER_PARSED.each do |ext|
      if full_path.nil? and File.exists?(@site.root + path + ext)
        full_path = path + ext
      end
    end
  end
  if full_path.nil? and !optional
    raise FileNotFound
  elsif full_path
    begin
      file = File.read(@site.root + full_path)
      md5 = Digest::MD5.hexdigest(file)
    rescue Errno::EISDIR
      return nil
    end
  else
    full_path = path
    md5 = ""
    file = ""
  end
  if @cache[full_path] != md5
    @cache[full_path] = md5
    [ full_path, file ]
  else
    nil
  end
end
not_modified?(req, res, mtime, etag) click to toggle source
# File lib/vae_site_servlet.rb, line 136
def not_modified?(req, res, mtime, etag)
  return true if (ims = req.params['IF_MODIFIED_SINCE']) && Time.parse(ims) >= mtime
  return true if (inm = req.params['IF_NONE_MATCH']) && WEBrick::HTTPUtils::split_header_value(inm).member?(etag)
  false
end
process(request, response) click to toggle source
# File lib/vae_site_servlet.rb, line 155
def process(request, response)
  serve(request, response)
  response.finished
end
render_sass(local_path) click to toggle source
# File lib/vae_site_servlet.rb, line 142
def render_sass(local_path)
  begin
    options = Compass.sass_engine_options
    options[:load_paths] << File.dirname(local_path)
    options[:syntax] = :scss if local_path =~ /\.scss$/
    engine = Sass::Engine.new(open(local_path, "rb").read, options)
    engine.render
  rescue Sass::SyntaxError => e
    e.message
    "Sass Syntax Error on line #{get_line_from_sass_exception(e)} #{e.message}"
  end
end
req_scss?(req) click to toggle source
# File lib/vae_site_servlet.rb, line 209
def req_scss?(req)
  req.params["REQUEST_URI"] =~ /\.(sass|scss)$/
end
serve(req, res) click to toggle source
# File lib/vae_site_servlet.rb, line 160
def serve(req, res)
  res.status = 200
  local_path = (@site.root+req.params["REQUEST_URI"] || "/").split("?").first
  if File.exists?(local_path) and !File.directory?(local_path) and !server_parsed?(local_path)
    st = File::stat(local_path)
    mtime = st.mtime
    etag = sprintf("%x-%x-%x", st.ino, st.size, st.mtime.to_i)
    res.header['etag'] = etag if !req_scss?(req)
    if not_modified?(req, res, mtime, etag)
      puts "#{req.params["REQUEST_URI"]} not modified"
      res.status = 304
    else
      mtype = WEBrick::HTTPUtils::mime_type(local_path, WEBrick::HTTPUtils::DefaultMimeTypes)
      res.header['last-modified'] = mtime.httpdate if !req_scss?(req)
      if req_scss?(req)
        res.header['Content-Type'] = "text/css"
        res.body << render_sass(local_path)
      else
        res.header['Content-Type'] = mtype
        res.body << open(local_path, "rb").read
      end
      puts "#{req.params["REQUEST_URI"]} local asset"
    end
  else
    if req.params["REQUEST_URI"] =~ /^\/__data\// or req.params["REQUEST_URI"] =~ /^\/__assets\//
      from_vae = { 'location' => "http://#{@site.domain}#{req.params["REQUEST_URI"]}"}
      puts "#{req.params["REQUEST_URI"]} static asset"
    else
      from_vae = fetch_from_vae_and_include_source_of_current_page(req, req.params["REQUEST_METHOD"])
      if from_vae['location']
        puts "#{req.params["REQUEST_URI"]} redirecting to #{from_vae['location']}"
      end
    end
    if from_vae['location']
      res.body << "<p>Redirecting to <a href=\"#{from_vae['location']}\">#{from_vae['location']}</a>"
      res.status = 302
      res.header['Location'] = from_vae['location']
    else
      res.header['Etag'] = from_vae['etag']
      res.header['Last-Modified'] = from_vae['last-modified']
      res.header['Content-Type'] = from_vae['content-type']
      res.header['Content-Disposition'] = from_vae['content-disposition']
      res.header['Set-Cookie'] = from_vae['set-cookie']
      puts "#{req.params["REQUEST_URI"]} rendering"
      res.body << from_vae.body
    end
  end
end
server_parsed?(path) click to toggle source
# File lib/vae_site_servlet.rb, line 213
def server_parsed?(path)
  SERVER_PARSED.each do |ext|
    return true if Regexp.new("#{ext}$").match(path)
  end
  false
end