class Gulp::Pipeline::Rails::Server

‘Server` provides a Rack compatible `call` interface and url generation helpers.

Public Class Methods

new(app, options = {}) click to toggle source
# File lib/gulp/pipeline/rails/server.rb, line 11
def initialize(app, options = {})
  config = app.config

  @debug = config.assets.debug
  @file_server = Rack::File.new(app.root.join('public', Assets.base_path).to_s)
  @cache_duration = options[:duration] || 1
  @duration_in_seconds = duration_in_seconds
  @duration_in_words = duration_in_words
end

Public Instance Methods

call(env) click to toggle source

A request for ‘“/assets/javascripts/foo/bar.js”` will search the public directory.

# File lib/gulp/pipeline/rails/server.rb, line 22
def call(env)
  if env['REQUEST_METHOD'] != 'GET'
    return method_not_allowed_response
  end

  msg = "Served asset #{env['PATH_INFO']} -"

  # Extract the path from everything after the leading slash
  path = Rack::Utils.unescape(env['PATH_INFO'].to_s.sub(/^\//, ''))

  status, headers, body =
    if forbidden_request?(path)
      # URLs containing a `..` are rejected for security reasons.
      forbidden_response
    else
      # # If not debug, enforce/require fingerprinted url. Do we really need this or just paranoia?
      # if (!@debug)
      #   fingerprint = path_fingerprint(path)
      #   if (fingerprint.nil?)
      #     msg += ' not a manifested file'
      #     return not_found_response
      #   end
      # end

      # standard file serve
      @file_server.call(env)
    end

  # log our status
  case status
    when :ok
      logger.info "#{msg} 200 OK "
    when :not_modified
      logger.info "#{msg} 304 Not Modified "
    when :not_found
      logger.info "#{msg} 404 Not Found "
    else
      logger.info "#{msg} #{status} Unknown status message "
  end

  # add cache headers
  headers['Cache-Control'] ="max-age=#{@duration_in_seconds}, public"
  headers['Expires'] = @duration_in_words

  # return results
  [status, headers, body]

rescue Exception => e
  logger.error "Error serving asset #{path}:"
  logger.error "#{e.class.name}: #{e.message}"
  raise
end

Private Instance Methods

absolute_path?(path) click to toggle source

On Windows, ALT_SEPARATOR is \ Delegate to Pathname since the logic gets complex.

# File lib/gulp/pipeline/rails/server.rb, line 94
def absolute_path?(path)
  Pathname.new(path).absolute?
end
duration_in_seconds() click to toggle source
# File lib/gulp/pipeline/rails/server.rb, line 125
def duration_in_seconds
  (60 * 60 * 24 * 365 * @cache_duration).to_i
end
duration_in_words() click to toggle source
# File lib/gulp/pipeline/rails/server.rb, line 121
def duration_in_words
  (Time.now + duration_in_seconds).strftime '%a, %d %b %Y %H:%M:%S GMT'
end
forbidden_request?(path) click to toggle source
# File lib/gulp/pipeline/rails/server.rb, line 76
def forbidden_request?(path)
  # Prevent access to files elsewhere on the file system
  #
  #     http://example.org/assets/../../../etc/passwd
  #
  path.include?('..') || absolute_path?(path)
end
forbidden_response() click to toggle source

Returns a 403 Forbidden response tuple

# File lib/gulp/pipeline/rails/server.rb, line 104
def forbidden_response
  [403, {'Content-Type' => 'text/plain', 'Content-Length' => '9'}, ['Forbidden']]
end
logger() click to toggle source
# File lib/gulp/pipeline/rails/server.rb, line 117
def logger
  ::Rails.logger
end
method_not_allowed_response() click to toggle source
# File lib/gulp/pipeline/rails/server.rb, line 113
def method_not_allowed_response
  [405, {'Content-Type' => 'text/plain', 'Content-Length' => '18'}, ['Method Not Allowed']]
end
not_found_response() click to toggle source

Returns a 404 Not Found response tuple

# File lib/gulp/pipeline/rails/server.rb, line 109
def not_found_response
  [404, {'Content-Type' => 'text/plain', 'Content-Length' => '9', 'X-Cascade' => 'pass'}, ['Not found']]
end