utopia 0.12.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -2
- data/Gemfile +6 -0
- data/README.md +48 -14
- data/Rakefile +5 -0
- data/bin/utopia +132 -15
- data/lib/utopia.rb +13 -10
- data/lib/utopia/content.rb +140 -0
- data/lib/utopia/content/link.rb +124 -0
- data/lib/utopia/content/links.rb +228 -0
- data/lib/utopia/content/node.rb +387 -0
- data/lib/utopia/content/processor.rb +128 -0
- data/lib/utopia/content/tag.rb +102 -0
- data/lib/utopia/controller.rb +137 -0
- data/lib/utopia/controller/action.rb +112 -0
- data/lib/utopia/controller/base.rb +174 -0
- data/lib/utopia/{middleware/controller → controller}/variables.rb +36 -38
- data/lib/utopia/exception_handler.rb +79 -0
- data/lib/utopia/extensions/array.rb +2 -2
- data/lib/utopia/localization.rb +143 -0
- data/lib/utopia/mail_exceptions.rb +136 -0
- data/lib/utopia/middleware.rb +7 -22
- data/lib/utopia/path.rb +150 -60
- data/lib/utopia/redirector.rb +152 -0
- data/lib/utopia/{extensions/hash.rb → session.rb} +4 -6
- data/lib/utopia/session/encrypted_cookie.rb +46 -48
- data/lib/utopia/{middleware/directory_index.rb → session/lazy_hash.rb} +44 -27
- data/lib/utopia/static.rb +255 -0
- data/lib/utopia/tags/deferred.rb +12 -8
- data/lib/utopia/tags/environment.rb +18 -6
- data/lib/utopia/tags/node.rb +12 -8
- data/lib/utopia/tags/override.rb +12 -12
- data/lib/utopia/version.rb +1 -1
- data/setup/.bowerrc +3 -0
- data/{lib/utopia/setup → setup}/Gemfile +1 -1
- data/setup/Rakefile +4 -0
- data/{lib/utopia/setup → setup}/cache/head/readme.txt +0 -0
- data/{lib/utopia/setup → setup}/cache/meta/readme.txt +0 -0
- data/setup/config.ru +64 -0
- data/{lib/utopia/setup → setup}/lib/readme.txt +0 -0
- data/{lib/utopia/setup → setup}/pages/_heading.xnode +0 -0
- data/{lib/utopia/setup → setup}/pages/_page.xnode +1 -1
- data/{lib/utopia/setup → setup}/pages/_static/icon.png +0 -0
- data/setup/pages/_static/site.css +70 -0
- data/{lib/utopia/setup → setup}/pages/errors/exception.xnode +0 -0
- data/{lib/utopia/setup → setup}/pages/errors/file-not-found.xnode +0 -0
- data/{lib/utopia/setup → setup}/pages/links.yaml +0 -0
- data/setup/pages/welcome/index.xnode +17 -0
- data/{lib/utopia/setup → setup}/public/readme.txt +0 -0
- data/spec/utopia/content/link_spec.rb +108 -0
- data/spec/utopia/content/links/foo/index.xnode +0 -0
- data/spec/utopia/content/links/foo/links.yaml +2 -0
- data/spec/utopia/content/links/foo/test.de.xnode +0 -0
- data/spec/utopia/content/links/foo/test.en.xnode +0 -0
- data/spec/utopia/content/links/links.yaml +9 -0
- data/spec/utopia/content/links/welcome.xnode +0 -0
- data/spec/utopia/content/localized/five/index.en.xnode +0 -0
- data/spec/utopia/content/localized/four/index.en.xnode +0 -0
- data/spec/utopia/content/localized/four/index.zh.xnode +0 -0
- data/spec/utopia/content/localized/four/links.yaml +4 -0
- data/spec/utopia/content/localized/links.yaml +16 -0
- data/spec/utopia/content/localized/one.xnode +0 -0
- data/spec/utopia/content/localized/three/index.xnode +0 -0
- data/spec/utopia/content/localized/two.en.xnode +0 -0
- data/spec/utopia/content/localized/two.zh.xnode +0 -0
- data/spec/utopia/content/node/ordered/first.xnode +0 -0
- data/spec/utopia/content/node/ordered/index.xnode +0 -0
- data/spec/utopia/content/node/ordered/links.yaml +4 -0
- data/spec/utopia/content/node/ordered/second.xnode +0 -0
- data/spec/utopia/content/node/related/foo.en.xnode +0 -0
- data/spec/utopia/content/node/related/foo.ja.xnode +0 -0
- data/spec/utopia/content/node/related/links.yaml +4 -0
- data/spec/utopia/content/node_spec.rb +63 -0
- data/spec/utopia/{middleware/content_spec.rb → content/processor_spec.rb} +34 -23
- data/spec/utopia/content_spec.rb +87 -0
- data/spec/utopia/content_spec.ru +10 -0
- data/spec/utopia/{middleware/controller_spec.rb → controller_spec.rb} +61 -16
- data/spec/utopia/controller_spec.ru +4 -0
- data/spec/utopia/extensions_spec.rb +6 -17
- data/spec/utopia/localization_spec.rb +60 -0
- data/spec/utopia/localization_spec.ru +11 -0
- data/{lib/utopia/tags.rb → spec/utopia/middleware_spec.rb} +8 -14
- data/spec/utopia/{middleware/content_root → pages}/_heading.xnode +0 -0
- data/spec/utopia/pages/content/_show-value.xnode +1 -0
- data/spec/utopia/pages/content/test-partial.xnode +1 -0
- data/spec/utopia/pages/controller/controller.rb +28 -0
- data/spec/utopia/pages/controller/index.xnode +1 -0
- data/spec/utopia/pages/controller/nested/controller.rb +4 -0
- data/spec/utopia/{middleware/content_root → pages}/index.xnode +0 -0
- data/spec/utopia/pages/localized.de.txt +1 -0
- data/spec/utopia/pages/localized.en.txt +1 -0
- data/spec/utopia/pages/localized.jp.txt +1 -0
- data/spec/utopia/pages/node/index.xnode +1 -0
- data/spec/utopia/pages/test.txt +1 -0
- data/spec/utopia/path_spec.rb +109 -0
- data/spec/utopia/rack_spec.rb +2 -0
- data/spec/utopia/session_spec.rb +82 -0
- data/spec/utopia/session_spec.ru +20 -0
- data/spec/utopia/spec_helper.rb +16 -0
- data/{lib/utopia/extensions/string.rb → spec/utopia/static_spec.rb} +24 -15
- data/spec/utopia/static_spec.ru +4 -0
- data/utopia.gemspec +3 -3
- metadata +138 -54
- data/lib/utopia/extensions/regexp.rb +0 -33
- data/lib/utopia/link.rb +0 -288
- data/lib/utopia/middleware/all.rb +0 -33
- data/lib/utopia/middleware/content.rb +0 -157
- data/lib/utopia/middleware/content/node.rb +0 -386
- data/lib/utopia/middleware/content/processor.rb +0 -123
- data/lib/utopia/middleware/controller.rb +0 -130
- data/lib/utopia/middleware/controller/action.rb +0 -121
- data/lib/utopia/middleware/controller/base.rb +0 -184
- data/lib/utopia/middleware/exception_handler.rb +0 -80
- data/lib/utopia/middleware/localization.rb +0 -147
- data/lib/utopia/middleware/localization/name.rb +0 -69
- data/lib/utopia/middleware/mail_exceptions.rb +0 -138
- data/lib/utopia/middleware/redirector.rb +0 -146
- data/lib/utopia/middleware/requester.rb +0 -126
- data/lib/utopia/middleware/static.rb +0 -295
- data/lib/utopia/setup.rb +0 -60
- data/lib/utopia/setup/config.ru +0 -47
- data/lib/utopia/setup/pages/_static/background.png +0 -0
- data/lib/utopia/setup/pages/_static/site.css +0 -48
- data/lib/utopia/setup/pages/welcome/index.xnode +0 -7
- data/lib/utopia/tag.rb +0 -105
- data/lib/utopia/tags/all.rb +0 -34
@@ -1,126 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'utopia/middleware'
|
22
|
-
|
23
|
-
require 'set'
|
24
|
-
|
25
|
-
module Utopia
|
26
|
-
module Middleware
|
27
|
-
|
28
|
-
class Requester
|
29
|
-
TTL_KEY = "utopia.requestor.ttl"
|
30
|
-
REQUESTOR_KEY = "utopia.requestor"
|
31
|
-
PATH_VARIABLES = Set.new
|
32
|
-
MAXIMUM_DEPTH = 5
|
33
|
-
|
34
|
-
class Response
|
35
|
-
def initialize(status, headers, body)
|
36
|
-
@status = status
|
37
|
-
@headers = headers
|
38
|
-
@body = body
|
39
|
-
end
|
40
|
-
|
41
|
-
attr :status
|
42
|
-
attr :headers
|
43
|
-
|
44
|
-
def body
|
45
|
-
unless @body_string
|
46
|
-
buffer = StringIO.new
|
47
|
-
|
48
|
-
@body.each do |string|
|
49
|
-
buffer.write(string)
|
50
|
-
end
|
51
|
-
|
52
|
-
@body_string = buffer.string
|
53
|
-
end
|
54
|
-
|
55
|
-
return @body_string
|
56
|
-
end
|
57
|
-
|
58
|
-
def [](key)
|
59
|
-
return @headers[key]
|
60
|
-
end
|
61
|
-
|
62
|
-
def okay?
|
63
|
-
@status == 200
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class NoRequesterError < ArgumentError
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.[](env)
|
71
|
-
requestor = env[REQUESTOR_KEY]
|
72
|
-
if requestor
|
73
|
-
return requestor
|
74
|
-
else
|
75
|
-
raise NoRequesterError
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def initialize(app, env = {})
|
80
|
-
@app = app
|
81
|
-
@env = env
|
82
|
-
@env[TTL_KEY] = 0
|
83
|
-
end
|
84
|
-
|
85
|
-
attr :env, true
|
86
|
-
|
87
|
-
def call(env)
|
88
|
-
requestor = dup
|
89
|
-
env[REQUESTOR_KEY] = requestor
|
90
|
-
requestor.env = env.merge(@env)
|
91
|
-
requestor.env.delete("rack.request")
|
92
|
-
|
93
|
-
@app.call(env)
|
94
|
-
end
|
95
|
-
|
96
|
-
class RecursiveRequestError < StandardError
|
97
|
-
end
|
98
|
-
|
99
|
-
def request(env)
|
100
|
-
env = @env.merge(env)
|
101
|
-
env[TTL_KEY] += 1
|
102
|
-
|
103
|
-
if env[TTL_KEY].to_i > MAXIMUM_DEPTH
|
104
|
-
raise RecursiveRequestError, env["PATH_INFO"]
|
105
|
-
end
|
106
|
-
|
107
|
-
return Response.new(*@app.call(env))
|
108
|
-
end
|
109
|
-
|
110
|
-
def [](path, method = "GET", env = {})
|
111
|
-
path_env = {
|
112
|
-
"REQUEST_METHOD" => method,
|
113
|
-
"PATH_INFO" => path.to_s
|
114
|
-
}
|
115
|
-
request(env.merge(path_env))
|
116
|
-
end
|
117
|
-
|
118
|
-
# Avoid a huge amount of junk being printed when inspecting +env+.
|
119
|
-
def inspect
|
120
|
-
to_s
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
@@ -1,295 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'utopia/middleware'
|
22
|
-
require 'utopia/path'
|
23
|
-
|
24
|
-
require 'time'
|
25
|
-
|
26
|
-
require 'digest/sha1'
|
27
|
-
require 'mime/types'
|
28
|
-
|
29
|
-
module Utopia
|
30
|
-
module Middleware
|
31
|
-
|
32
|
-
class Static
|
33
|
-
MIME_TYPES = {
|
34
|
-
:xiph => {
|
35
|
-
"ogx" => "application/ogg",
|
36
|
-
"ogv" => "video/ogg",
|
37
|
-
"oga" => "audio/ogg",
|
38
|
-
"ogg" => "audio/ogg",
|
39
|
-
"spx" => "audio/ogg",
|
40
|
-
"flac" => "audio/flac",
|
41
|
-
"anx" => "application/annodex",
|
42
|
-
"axa" => "audio/annodex",
|
43
|
-
"xspf" => "application/xspf+xml",
|
44
|
-
},
|
45
|
-
:media => [
|
46
|
-
:xiph, "mp3", "mp4", "wav", "aiff", ["aac", "audio/x-aac"], "mov", "avi", "wmv", "mpg"
|
47
|
-
],
|
48
|
-
:text => [
|
49
|
-
"html", "css", "js", "txt", "rtf", "xml", "pdf"
|
50
|
-
],
|
51
|
-
:fonts => [
|
52
|
-
"otf", ["eot", "application/vnd.ms-fontobject"], "ttf", "woff"
|
53
|
-
],
|
54
|
-
:archive => [
|
55
|
-
"zip", "tar", "tgz", "tar.gz", "tar.bz2", ["dmg", "application/x-apple-diskimage"],
|
56
|
-
["torrent", "application/x-bittorrent"]
|
57
|
-
],
|
58
|
-
:images => [
|
59
|
-
"png", "gif", "jpeg", "tiff", "svg"
|
60
|
-
],
|
61
|
-
:default => [
|
62
|
-
:media, :text, :archive, :images, :fonts
|
63
|
-
]
|
64
|
-
}
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
class LocalFile
|
69
|
-
def initialize(root, path)
|
70
|
-
@root = root
|
71
|
-
@path = path
|
72
|
-
@etag = Digest::SHA1.hexdigest("#{File.size(full_path)}#{mtime_date}")
|
73
|
-
|
74
|
-
@range = nil
|
75
|
-
end
|
76
|
-
|
77
|
-
attr :root
|
78
|
-
attr :path
|
79
|
-
attr :etag
|
80
|
-
attr :range
|
81
|
-
|
82
|
-
# Fit in with Rack::Sendfile
|
83
|
-
def to_path
|
84
|
-
full_path
|
85
|
-
end
|
86
|
-
|
87
|
-
def full_path
|
88
|
-
File.join(@root, @path.components)
|
89
|
-
end
|
90
|
-
|
91
|
-
def mtime_date
|
92
|
-
File.mtime(full_path).httpdate
|
93
|
-
end
|
94
|
-
|
95
|
-
def size
|
96
|
-
File.size(full_path)
|
97
|
-
end
|
98
|
-
|
99
|
-
def each
|
100
|
-
File.open(full_path, "rb") do |file|
|
101
|
-
file.seek(@range.begin)
|
102
|
-
remaining = @range.end - @range.begin+1
|
103
|
-
|
104
|
-
while remaining > 0
|
105
|
-
break unless part = file.read([8192, remaining].min)
|
106
|
-
|
107
|
-
remaining -= part.length
|
108
|
-
|
109
|
-
yield part
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def modified?(env)
|
115
|
-
if modified_since = env['HTTP_IF_MODIFIED_SINCE']
|
116
|
-
return false if File.mtime(full_path) <= Time.parse(modified_since)
|
117
|
-
end
|
118
|
-
|
119
|
-
if etags = env['HTTP_IF_NONE_MATCH']
|
120
|
-
etags = etags.split(/\s*,\s*/)
|
121
|
-
return false if etags.include?(etag) || etags.include?('*')
|
122
|
-
end
|
123
|
-
|
124
|
-
return true
|
125
|
-
end
|
126
|
-
|
127
|
-
def serve(env, response_headers)
|
128
|
-
ranges = Rack::Utils.byte_ranges(env, size)
|
129
|
-
response = [200, response_headers, self]
|
130
|
-
|
131
|
-
# LOG.info("Requesting ranges: #{ranges.inspect} (#{size})")
|
132
|
-
|
133
|
-
if ranges.nil? || ranges.length > 1
|
134
|
-
# No ranges, or multiple ranges (which we don't support):
|
135
|
-
# TODO: Support multiple byte-ranges
|
136
|
-
response[0] = 200
|
137
|
-
response[1]["Content-Length"] = size.to_s
|
138
|
-
@range = 0..size-1
|
139
|
-
elsif ranges.empty?
|
140
|
-
# Unsatisfiable. Return error, and file size:
|
141
|
-
response = Middleware::failure(416, "Invalid range specified.")
|
142
|
-
response[1]["Content-Range"] = "bytes */#{size}"
|
143
|
-
return response
|
144
|
-
else
|
145
|
-
# Partial content:
|
146
|
-
@range = ranges[0]
|
147
|
-
response[0] = 206
|
148
|
-
response[1]["Content-Range"] = "bytes #{@range.begin}-#{@range.end}/#{size}"
|
149
|
-
response[1]["Content-Length"] = (@range.end - @range.begin+1).to_s
|
150
|
-
size = @range.end - @range.begin + 1
|
151
|
-
end
|
152
|
-
|
153
|
-
# LOG.info("Response for #{self.full_path}: #{response.inspect}")
|
154
|
-
LOG.info "Serving file #{full_path.inspect}, range #{@range.inspect}"
|
155
|
-
|
156
|
-
return response
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def load_mime_types(types)
|
161
|
-
result = {}
|
162
|
-
|
163
|
-
extract_extensions = lambda do |mime_type|
|
164
|
-
# LOG.info "Extracting #{mime_type.inspect}"
|
165
|
-
mime_type.extensions.each{|ext| result["." + ext] = mime_type.content_type}
|
166
|
-
end
|
167
|
-
|
168
|
-
types.each do |type|
|
169
|
-
current_count = result.size
|
170
|
-
# LOG.info "Processing #{type.inspect}"
|
171
|
-
|
172
|
-
begin
|
173
|
-
case type
|
174
|
-
when Symbol
|
175
|
-
result = load_mime_types(MIME_TYPES[type]).merge(result)
|
176
|
-
when Array
|
177
|
-
result["." + type[0]] = type[1]
|
178
|
-
when String
|
179
|
-
mt = MIME::Types.of(type).select{|mt| !mt.obsolete?}.each do |mt|
|
180
|
-
extract_extensions.call(mt)
|
181
|
-
end
|
182
|
-
when Regexp
|
183
|
-
MIME::Types[type].select{|mt| !mt.obsolete?}.each do |mt|
|
184
|
-
extract_extensions.call(mt)
|
185
|
-
end
|
186
|
-
when MIME::Type
|
187
|
-
extract_extensions.call(type)
|
188
|
-
end
|
189
|
-
rescue
|
190
|
-
LOG.error "#{self.class.name}: Error while processing #{type.inspect}!"
|
191
|
-
raise $!
|
192
|
-
end
|
193
|
-
|
194
|
-
if result.size == current_count
|
195
|
-
LOG.warn "#{self.class.name}: Could not find any mime type for #{type.inspect}"
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
return result
|
200
|
-
end
|
201
|
-
|
202
|
-
public
|
203
|
-
|
204
|
-
def initialize(app, options = {})
|
205
|
-
@app = app
|
206
|
-
@root = options[:root] || Utopia::Middleware::default_root
|
207
|
-
|
208
|
-
if options[:types]
|
209
|
-
@extensions = load_mime_types(options[:types])
|
210
|
-
else
|
211
|
-
@extensions = load_mime_types(MIME_TYPES[:default])
|
212
|
-
end
|
213
|
-
|
214
|
-
@cache_control = options[:cache_control] || "public, max-age=3600"
|
215
|
-
end
|
216
|
-
|
217
|
-
def fetch_file(path)
|
218
|
-
# We need file_path to be an absolute path for X-Sendfile to work correctly.
|
219
|
-
file_path = File.join(@root, path.components)
|
220
|
-
|
221
|
-
if File.exist?(file_path)
|
222
|
-
return LocalFile.new(@root, path)
|
223
|
-
else
|
224
|
-
return nil
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def lookup_relative_file(path)
|
229
|
-
file = nil
|
230
|
-
name = path.basename
|
231
|
-
|
232
|
-
if split = path.split("@rel@")
|
233
|
-
path = split[0]
|
234
|
-
name = split[1].components
|
235
|
-
|
236
|
-
# Fix a problem if the browser request has multiple @rel@
|
237
|
-
# This normally indicates a browser bug.. :(
|
238
|
-
name = name.dup
|
239
|
-
name.delete("@rel@")
|
240
|
-
else
|
241
|
-
path = path.dirname
|
242
|
-
|
243
|
-
# Relative lookups are not done unless explicitly required by @rel@
|
244
|
-
# ... but they do work. This is a performance optimization.
|
245
|
-
return nil
|
246
|
-
end
|
247
|
-
|
248
|
-
# LOG.debug("Searching for #{name.inspect} starting in #{path.components}")
|
249
|
-
|
250
|
-
path.ascend do |parent_path|
|
251
|
-
file_path = File.join(@root, parent_path.components, name)
|
252
|
-
# LOG.debug("File path: #{file_path}")
|
253
|
-
if File.exist?(file_path)
|
254
|
-
return (parent_path + name).to_s
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
return nil
|
259
|
-
end
|
260
|
-
|
261
|
-
attr :extensions
|
262
|
-
|
263
|
-
def call(env)
|
264
|
-
request = Rack::Request.new(env)
|
265
|
-
ext = File.extname(request.path_info)
|
266
|
-
|
267
|
-
if @extensions.key? ext.downcase
|
268
|
-
path = Path.create(request.path_info).simplify
|
269
|
-
|
270
|
-
if file = fetch_file(path)
|
271
|
-
response_headers = {
|
272
|
-
"Last-Modified" => file.mtime_date,
|
273
|
-
"Content-Type" => @extensions[ext],
|
274
|
-
"Cache-Control" => @cache_control,
|
275
|
-
"ETag" => file.etag,
|
276
|
-
"Accept-Ranges" => "bytes"
|
277
|
-
}
|
278
|
-
|
279
|
-
if file.modified?(env)
|
280
|
-
return file.serve(env, response_headers)
|
281
|
-
else
|
282
|
-
return [304, response_headers, []]
|
283
|
-
end
|
284
|
-
elsif redirect = lookup_relative_file(path)
|
285
|
-
return [307, {"Location" => redirect}, []]
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
# else if no file was found:
|
290
|
-
return @app.call(env)
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
end
|
295
|
-
end
|
data/lib/utopia/setup.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'utopia/version'
|
22
|
-
require 'fileutils'
|
23
|
-
require 'find'
|
24
|
-
require 'rake'
|
25
|
-
|
26
|
-
module Utopia
|
27
|
-
module Setup
|
28
|
-
ROOT = File.join(File.dirname(__FILE__), "setup", "")
|
29
|
-
DIRECTORIES = ["access_log", "cache", "cache/meta", "cache/body", "lib", "pages", "public"]
|
30
|
-
|
31
|
-
def self.copy(to, config = {})
|
32
|
-
$stderr.puts "Copying files from #{ROOT} to #{to}..."
|
33
|
-
Find.find(ROOT) do |src|
|
34
|
-
dst = File.join(to, src[ROOT.size..-1])
|
35
|
-
|
36
|
-
if File.directory?(src)
|
37
|
-
FileUtils.mkdir_p(dst)
|
38
|
-
else
|
39
|
-
if File.exist? dst
|
40
|
-
$stderr.puts "File already exists: #{dst}!"
|
41
|
-
else
|
42
|
-
$stderr.puts "Copying #{src} to #{dst}..."
|
43
|
-
FileUtils.cp(src, dst)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
DIRECTORIES.each do |path|
|
49
|
-
FileUtils.mkdir_p(File.join(to, path))
|
50
|
-
end
|
51
|
-
|
52
|
-
['config.ru', 'Gemfile'].each do |configuration_file|
|
53
|
-
$stderr.puts "Updating #{configuration_file}..."
|
54
|
-
path = File.join(to, configuration_file)
|
55
|
-
buffer = File.read(path).gsub('$UTOPIA_VERSION', Utopia::VERSION)
|
56
|
-
File.open(path, "w") { |file| file.write(buffer) }
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|