Class: Utopia::Middleware::Static::LocalFile

Inherits:
Object
  • Object
show all
Defined in:
lib/utopia/middleware/static.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root, path) ⇒ LocalFile

Returns a new instance of LocalFile.



53
54
55
56
57
58
59
# File 'lib/utopia/middleware/static.rb', line 53

def initialize(root, path)
	@root = root
	@path = path
	@etag = Digest::SHA1.hexdigest("#{File.size(full_path)}#{mtime_date}")

	@range = nil
end

Instance Attribute Details

#etagObject (readonly)

Returns the value of attribute etag.



63
64
65
# File 'lib/utopia/middleware/static.rb', line 63

def etag
  @etag
end

#pathObject (readonly)

Returns the value of attribute path.



62
63
64
# File 'lib/utopia/middleware/static.rb', line 62

def path
  @path
end

#rangeObject (readonly)

Returns the value of attribute range.



64
65
66
# File 'lib/utopia/middleware/static.rb', line 64

def range
  @range
end

#rootObject (readonly)

Returns the value of attribute root.



61
62
63
# File 'lib/utopia/middleware/static.rb', line 61

def root
  @root
end

Instance Method Details

#eachObject



83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/utopia/middleware/static.rb', line 83

def each
	File.open(full_path, "rb") do |file|
		file.seek(@range.begin)
		remaining = @range.end - @range.begin+1

		while remaining > 0
			break unless part = file.read([8192, remaining].min)

			remaining -= part.length

			yield part
		end
	end
end

#full_pathObject



71
72
73
# File 'lib/utopia/middleware/static.rb', line 71

def full_path
	File.join(@root, @path.components)
end

#modified?(env) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/utopia/middleware/static.rb', line 98

def modified?(env)
	if modified_since = env['HTTP_IF_MODIFIED_SINCE']
		return false if File.mtime(full_path) <= Time.parse(modified_since)
	end

	if etags = env['HTTP_IF_NONE_MATCH']
		etags = etags.split(/\s*,\s*/)
		return false if etags.include?(etag) || etags.include?('*')
	end

	return true
end

#mtime_dateObject



75
76
77
# File 'lib/utopia/middleware/static.rb', line 75

def mtime_date
	File.mtime(full_path).httpdate
end

#serve(env, response_headers) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/utopia/middleware/static.rb', line 111

def serve(env, response_headers)
	ranges = Rack::Utils.byte_ranges(env, size)
	response = [200, response_headers, self]

	# LOG.info("Requesting ranges: #{ranges.inspect} (#{size})")

	if ranges.nil? || ranges.length > 1
		# No ranges, or multiple ranges (which we don't support):
		# TODO: Support multiple byte-ranges
		response[0] = 200
		response[1]["Content-Length"] = size.to_s
		@range = 0..size-1
	elsif ranges.empty?
		# Unsatisfiable. Return error, and file size:
		response = Middleware::failure(416, "Invalid range specified.")
		response[1]["Content-Range"] = "bytes */#{size}"
		return response
	else
		# Partial content:
		@range = ranges[0]
		response[0] = 206
		response[1]["Content-Range"] = "bytes #{@range.begin}-#{@range.end}/#{size}"
		response[1]["Content-Length"] = (@range.end - @range.begin+1).to_s
		size = @range.end - @range.begin + 1
	end

	# LOG.info("Response for #{self.full_path}: #{response.inspect}")
	LOG.info "Serving file #{full_path.inspect}, range #{@range.inspect}"

	return response
end

#sizeObject



79
80
81
# File 'lib/utopia/middleware/static.rb', line 79

def size
	File.size(full_path)
end

#to_pathObject

Fit in with Rack::Sendfile



67
68
69
# File 'lib/utopia/middleware/static.rb', line 67

def to_path
	full_path
end