Class: Middleman::Rack

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

Instance Method Summary collapse

Constructor Details

#initialize(middleman) ⇒ Rack


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

def initialize(middleman)
  @middleman = middleman
end

Instance Method Details

#call(env) ⇒ Object

Rack Interface


57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'middleman-core/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


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

def halt(response)
  throw :halt, response
end

#not_found(res, path) ⇒ Object

Halt request and return 404


122
123
124
125
126
127
# File 'middleman-core/lib/middleman-core/rack.rb', line 122

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.


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
# File 'middleman-core/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)
  request_path.force_encoding('UTF-8') if request_path.respond_to? :force_encoding
  request_path = ::Middleman::Util.full_path(request_path, @middleman)
  full_request_path = File.join(env['SCRIPT_NAME'], request_path) # Path including rack mount

  # Get the resource object for this path
  resource = @middleman.sitemap.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? || resource.static_file?

  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


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'middleman-core/lib/middleman-core/rack.rb', line 130

def send_file(resource, env)
  file     = ::Rack::File.new nil
  path     = resource.file_descriptor[:full_path]
  if !file.respond_to?(:path=)
    request  = ::Rack::Request.new(env)
    response = file.serving(request, path)
  else
    file.path = path
    response = file.serving(env)
  end
  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 || (resource.binary? ? 'application/octet-stream' : 'text/plain')
  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 'middleman-core/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