Class: Utopia::Static::LocalFile

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root, path) ⇒ LocalFile

Returns a new instance of LocalFile.



119
120
121
122
123
124
125
# File 'lib/utopia/static.rb', line 119

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

  @range = nil
end

Instance Attribute Details

#etag ⇒ Object (readonly)

Returns the value of attribute etag.



129
130
131
# File 'lib/utopia/static.rb', line 129

def etag
  @etag
end

#path ⇒ Object (readonly)

Returns the value of attribute path.



128
129
130
# File 'lib/utopia/static.rb', line 128

def path
  @path
end

#range ⇒ Object (readonly)

Returns the value of attribute range.



130
131
132
# File 'lib/utopia/static.rb', line 130

def range
  @range
end

#root ⇒ Object (readonly)

Returns the value of attribute root.



127
128
129
# File 'lib/utopia/static.rb', line 127

def root
  @root
end

Instance Method Details

#each ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/utopia/static.rb', line 149

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_path ⇒ Object



137
138
139
# File 'lib/utopia/static.rb', line 137

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

#modified?(env) ⇒ Boolean

Returns:

  • (Boolean)


164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/utopia/static.rb', line 164

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_date ⇒ Object



141
142
143
# File 'lib/utopia/static.rb', line 141

def mtime_date
  File.mtime(full_path).httpdate
end

#serve(env, response_headers) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/utopia/static.rb', line 177

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 or ranges.size != 1
    # No ranges, or multiple ranges (which we don't support).
    # TODO: Support multiple byte-ranges, for now just send entire file:
    response[0] = 200
    response[1]["Content-Length"] = size.to_s
    @range = 0...size
  else
    # Partial content:
    @range = ranges[0]
    partial_size = @range.count
    
    response[0] = 206
    response[1]["Content-Length"] = partial_size.to_s
    response[1]["Content-Range"] = "bytes #{@range.min}-#{@range.max}/#{size}"
  end

  # LOG.debug {"Serving file #{full_path.inspect}, range #{@range.inspect}"}

  return response
end

#size ⇒ Object



145
146
147
# File 'lib/utopia/static.rb', line 145

def size
  File.size(full_path)
end

#to_path ⇒ Object

Fit in with Rack::Sendfile



133
134
135
# File 'lib/utopia/static.rb', line 133

def to_path
  full_path
end