utopia 0.9.57 → 0.9.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,19 @@
2
2
  # Copyright 2010 Samuel Williams. All rights reserved.
3
3
  # See <utopia.rb> for licensing details.
4
4
 
5
+ class Rack::Request
6
+ def url_with_path(path = "")
7
+ url = scheme + "://"
8
+ url << host
9
+
10
+ if scheme == "https" && port != 443 || scheme == "http" && port != 80
11
+ url << ":#{port}"
12
+ end
13
+
14
+ url << path
15
+ end
16
+ end
17
+
5
18
  class Rack::Response
6
19
  def do_not_cache!
7
20
  self["Cache-Control"] = "no-cache, must-revalidate"
@@ -14,4 +27,8 @@ class Rack::Response
14
27
  self["Expires"] = (Time.now + duration).httpdate
15
28
  end
16
29
  end
30
+
31
+ def content_type!(value)
32
+ self["Content-Type"] = value.to_s
33
+ end
17
34
  end
@@ -31,6 +31,7 @@ module Utopia
31
31
  403 => "Access Forbidden",
32
32
  404 => "Resource Not Found",
33
33
  405 => "Unsupported Method",
34
+ 416 => "Byte range unsatisfiable",
34
35
  500 => "Internal Server Error",
35
36
  501 => "Not Implemented",
36
37
  503 => "Service Unavailable"
@@ -5,6 +5,7 @@
5
5
  require 'pathname'
6
6
  require 'logger'
7
7
 
8
+ require 'utopia/http_status_codes'
8
9
  require 'utopia/extensions/rack'
9
10
 
10
11
  module Utopia
@@ -15,6 +16,16 @@ module Utopia
15
16
  def self.default_root(subdir = "pages")
16
17
  Pathname.new(Dir.pwd).join(subdir).cleanpath.to_s
17
18
  end
19
+
20
+ def self.failure(status = 500, message = "Non-specific error")
21
+ body = "#{HTTP_STATUS_DESCRIPTIONS[status] || status.to_s}: #{message}"
22
+
23
+ return [status, {
24
+ "Content-Type" => "text/plain",
25
+ "Content-Length" => body.size.to_s,
26
+ "X-Cascade" => "pass"
27
+ }, [body]]
28
+ end
18
29
  end
19
30
  end
20
31
 
@@ -1,6 +1,7 @@
1
1
  # This file is part of the "Utopia Framework" project, and is licensed under the GNU AGPLv3.
2
2
  # Copyright 2010 Samuel Williams. All rights reserved.
3
3
  # See <utopia.rb> for licensing details.
4
+
4
5
  require 'utopia/middleware'
5
6
  require 'utopia/path'
6
7
 
@@ -50,11 +51,14 @@ module Utopia
50
51
  @root = root
51
52
  @path = path
52
53
  @etag = Digest::SHA1.hexdigest("#{File.size(full_path)}#{mtime_date}")
54
+
55
+ @range = nil
53
56
  end
54
57
 
55
58
  attr :root
56
59
  attr :path
57
60
  attr :etag
61
+ attr :range
58
62
 
59
63
  # Fit in with Rack::Sendfile
60
64
  def to_path
@@ -74,8 +78,15 @@ module Utopia
74
78
  end
75
79
 
76
80
  def each
77
- File.open(full_path, "rb") do |fp|
78
- while part = fp.read(8192)
81
+ File.open(full_path, "rb") do |file|
82
+ file.seek(@range.begin)
83
+ remaining = @range.end - @range.begin+1
84
+
85
+ while remaining > 0
86
+ break unless part = file.read([8192, remaining].min)
87
+
88
+ remaining -= part.length
89
+
79
90
  yield part
80
91
  end
81
92
  end
@@ -93,6 +104,38 @@ module Utopia
93
104
 
94
105
  return true
95
106
  end
107
+
108
+ def serve(env, response_headers)
109
+ ranges = Rack::Utils.byte_ranges(env, size)
110
+ response = [200, response_headers, self]
111
+
112
+ # LOG.info("Requesting ranges: #{ranges.inspect} (#{size})")
113
+
114
+ if ranges.nil? || ranges.length > 1
115
+ # No ranges, or multiple ranges (which we don't support):
116
+ # TODO: Support multiple byte-ranges
117
+ response[0] = 200
118
+ response[1]["Content-Length"] = size.to_s
119
+ @range = 0..size-1
120
+ elsif ranges.empty?
121
+ # Unsatisfiable. Return error, and file size:
122
+ response = Middleware::failure(416, "Invalid range specified.")
123
+ response[1]["Content-Range"] = "bytes */#{size}"
124
+ return response
125
+ else
126
+ # Partial content:
127
+ @range = ranges[0]
128
+ response[0] = 206
129
+ response[1]["Content-Range"] = "bytes #{@range.begin}-#{@range.end}/#{size}"
130
+ response[1]["Content-Length"] = (@range.end - @range.begin+1).to_s
131
+ size = @range.end - @range.begin + 1
132
+ end
133
+
134
+ # LOG.info("Response for #{self.full_path}: #{response.inspect}")
135
+ LOG.info "Serving file #{full_path.inspect}, range #{@range.inspect}"
136
+
137
+ return response
138
+ end
96
139
  end
97
140
 
98
141
  def load_mime_types(types)
@@ -141,15 +184,15 @@ module Utopia
141
184
  def initialize(app, options = {})
142
185
  @app = app
143
186
  @root = options[:root] || Utopia::Middleware::default_root
144
-
187
+
145
188
  if options[:types]
146
189
  @extensions = load_mime_types(options[:types])
147
190
  else
148
191
  @extensions = load_mime_types(MIME_TYPES[:default])
149
192
  end
150
-
193
+
151
194
  @cache_control = options[:cache_control] || "public, max-age=3600"
152
-
195
+
153
196
  LOG.info "** #{self.class.name}: Running in #{@root} with #{extensions.size} filetypes"
154
197
  # LOG.info @extensions.inspect
155
198
  end
@@ -203,21 +246,21 @@ module Utopia
203
246
  def call(env)
204
247
  request = Rack::Request.new(env)
205
248
  ext = File.extname(request.path_info)
249
+
206
250
  if @extensions.key? ext.downcase
207
251
  path = Path.create(request.path_info).simplify
208
-
252
+
209
253
  if file = fetch_file(path)
210
254
  response_headers = {
211
255
  "Last-Modified" => file.mtime_date,
212
256
  "Content-Type" => @extensions[ext],
213
257
  "Cache-Control" => @cache_control,
214
258
  "ETag" => file.etag,
259
+ "Accept-Ranges" => "bytes"
215
260
  }
216
261
 
217
262
  if file.modified?(env)
218
- response_headers["Content-Length"] = file.size.to_s
219
-
220
- return [200, response_headers, file]
263
+ return file.serve(env, response_headers)
221
264
  else
222
265
  return [304, response_headers, []]
223
266
  end
@@ -1,8 +1,8 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <?r response["Content-Type"] = "text/html; charset=utf-8" ?>
5
- <?r response["Cache-Control"] = "max-age=3600" ?>
4
+ <?r response.content_type! "text/html; charset=utf-8" ?>
5
+ <?r response.cache! ?>
6
6
 
7
7
  <?r if title = (attributes["title"] || @title) ?>
8
8
  <title>#{title.gsub(/<.*?>/, "")} - Utopia</title>
@@ -6,7 +6,7 @@ module Utopia
6
6
  module VERSION
7
7
  MAJOR = 0
8
8
  MINOR = 9
9
- TINY = 57
9
+ TINY = 58
10
10
 
11
11
  STRING = [MAJOR, MINOR, TINY].join('.')
12
12
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: utopia
3
3
  version: !ruby/object:Gem::Version
4
- hash: 73
5
- prerelease:
4
+ prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 9
9
- - 57
10
- version: 0.9.57
8
+ - 58
9
+ version: 0.9.58
11
10
  platform: ruby
12
11
  authors:
13
12
  - Samuel Williams
@@ -15,17 +14,16 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-08-30 00:00:00 Z
17
+ date: 2012-01-12 00:00:00 +13:00
18
+ default_executable: utopia
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: mime-types
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
24
  requirements:
26
25
  - - ">="
27
26
  - !ruby/object:Gem::Version
28
- hash: 3
29
27
  segments:
30
28
  - 0
31
29
  version: "0"
@@ -35,11 +33,9 @@ dependencies:
35
33
  name: rack
36
34
  prerelease: false
37
35
  requirement: &id002 !ruby/object:Gem::Requirement
38
- none: false
39
36
  requirements:
40
37
  - - ">="
41
38
  - !ruby/object:Gem::Version
42
- hash: 3
43
39
  segments:
44
40
  - 0
45
41
  version: "0"
@@ -49,11 +45,9 @@ dependencies:
49
45
  name: rack-cache
50
46
  prerelease: false
51
47
  requirement: &id003 !ruby/object:Gem::Requirement
52
- none: false
53
48
  requirements:
54
49
  - - ">="
55
50
  - !ruby/object:Gem::Version
56
- hash: 3
57
51
  segments:
58
52
  - 0
59
53
  version: "0"
@@ -63,11 +57,9 @@ dependencies:
63
57
  name: rack-contrib
64
58
  prerelease: false
65
59
  requirement: &id004 !ruby/object:Gem::Requirement
66
- none: false
67
60
  requirements:
68
61
  - - ">="
69
62
  - !ruby/object:Gem::Version
70
- hash: 3
71
63
  segments:
72
64
  - 0
73
65
  version: "0"
@@ -77,11 +69,9 @@ dependencies:
77
69
  name: rmagick
78
70
  prerelease: false
79
71
  requirement: &id005 !ruby/object:Gem::Requirement
80
- none: false
81
72
  requirements:
82
73
  - - ">="
83
74
  - !ruby/object:Gem::Version
84
- hash: 3
85
75
  segments:
86
76
  - 0
87
77
  version: "0"
@@ -155,6 +145,7 @@ files:
155
145
  - lib/utopia/xnode.rb
156
146
  - lib/utopia.rb
157
147
  - bin/utopia
148
+ has_rdoc: true
158
149
  homepage: http://www.oriontransfer.co.nz/software/utopia
159
150
  licenses: []
160
151
 
@@ -164,27 +155,23 @@ rdoc_options: []
164
155
  require_paths:
165
156
  - lib
166
157
  required_ruby_version: !ruby/object:Gem::Requirement
167
- none: false
168
158
  requirements:
169
159
  - - ">="
170
160
  - !ruby/object:Gem::Version
171
- hash: 3
172
161
  segments:
173
162
  - 0
174
163
  version: "0"
175
164
  required_rubygems_version: !ruby/object:Gem::Requirement
176
- none: false
177
165
  requirements:
178
166
  - - ">="
179
167
  - !ruby/object:Gem::Version
180
- hash: 3
181
168
  segments:
182
169
  - 0
183
170
  version: "0"
184
171
  requirements: []
185
172
 
186
173
  rubyforge_project:
187
- rubygems_version: 1.8.7
174
+ rubygems_version: 1.3.6
188
175
  signing_key:
189
176
  specification_version: 3
190
177
  summary: Utopia is a framework for building websites.