Class: Middleman::Rack

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/middleman-core/rack.rb

Instance Method Summary collapse

Constructor Details

#initialize(middleman) ⇒ Rack

Returns a new instance of Rack.



50
51
52
# File 'lib/middleman-core/rack.rb', line 50

def initialize(middleman)
  @middleman = middleman
end

Instance Method Details

#call(env) ⇒ Object

Rack Interface

Parameters:

  • env

    Rack environment



57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/middleman-core/rack.rb', line 57

def call(env)
  # Store environment, request and response for later
  req = ::Rack::Request.new(env)
  res = ::Rack::Response.new

  logger.debug "== Request: #{env['PATH_INFO']}"

  # Catch :halt exceptions and use that response if given
  catch(:halt) do
    process_request(env, req, res)
    res.status = 404
    res.finish
  end
end

#halt(response) ⇒ Object

Halt the current request and return a response

Parameters:

  • response (String)

    Response value



75
76
77
# File 'lib/middleman-core/rack.rb', line 75

def halt(response)
  throw :halt, response
end

#not_found(res, path) ⇒ Object

Halt request and return 404



127
128
129
130
131
132
# File 'lib/middleman-core/rack.rb', line 127

def not_found(res, path)
  path = ::Rack::Utils.escape_html(path)
  res.status = 404
  res.write "<html><head></head><body><h1>File Not Found</h1><p>#{path}</p></body></html>"
  res.finish
end

#process_request(env, req, res) ⇒ Object

Core response method. We process the request, check with the sitemap, and return the correct file, response or status message.

Parameters:

  • env
  • req (Rack::Request)
  • res (Rack::Response)


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/middleman-core/rack.rb', line 86

def process_request(env, req, res)
  start_time = Time.now

  request_path = URI.decode(env['PATH_INFO'].dup)
  if request_path.respond_to? :force_encoding
    request_path.force_encoding('UTF-8')
  end
  request_path = ::Middleman::Util.full_path(request_path, @middleman)
  full_request_path = File.join(env['SCRIPT_NAME'], request_path) # Path including rack mount

  # Run before callbacks
  @middleman.execute_callbacks(:before)

  # Get the resource object for this path
  resource = @middleman.sitemap.find_resource_by_destination_path(request_path.gsub(' ', '%20'))

  # Return 404 if not in sitemap
  return not_found(res, full_request_path) unless resource && !resource.ignored?

  # If this path is a binary file, send it immediately
  return send_file(resource, env) if resource.binary?

  res['Content-Type'] = resource.content_type || 'text/plain'

  begin
    # Write out the contents of the page
    res.write resource.render({}, rack: { request: req })

    # Valid content is a 200 status
    res.status = 200
  rescue Middleman::TemplateRenderer::TemplateNotFound => e
    res.write "Error: #{e.message}"
    res.status = 500
  end

  # End the request
  logger.debug "== Finishing Request: #{resource.destination_path} (#{(Time.now - start_time).round(2)}s)"
  halt res.finish
end

#send_file(resource, env) ⇒ Object

Immediately send static file



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/middleman-core/rack.rb', line 135

def send_file(resource, env)
  file      = ::Rack::File.new nil
  file.path = resource.file_descriptor[:full_path]
  response = file.serving(env)
  status = response[0]
  response[1]['Content-Encoding'] = 'gzip' if %w(.svgz .gz).include?(resource.ext)
  # Do not set Content-Type if status is 1xx, 204, 205 or 304, otherwise
  # Rack will throw an error (500)
  if !(100..199).cover?(status) && ![204, 205, 304].include?(status)
    response[1]['Content-Type'] = resource.content_type || 'application/octet-stream'
  end
  halt response
end

#to_appObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/middleman-core/rack.rb', line 28

def to_app
  app = ::Rack::Builder.new

  app.use ::Rack::Lint
  app.use ::Rack::Head

  @middleman.middleware.each do |middleware|
    app.use(middleware[:class], *middleware[:options], &middleware[:block])
  end

  inner_app = self
  app.map('/') { run inner_app }

  @middleman.mappings.each do |mapping|
    app.map(mapping[:path], &mapping[:block])
  end

  app
end