Class: Regurgitator::LocalFile

Inherits:
Object
  • Object
show all
Defined in:
lib/regurgitator/local_file.rb

Overview

used to serve local files, bypassing HTTP to the backend device

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, path, uri, stat) ⇒ LocalFile

Returns a new instance of LocalFile.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/regurgitator/local_file.rb', line 17

def initialize(env, path, uri, stat)
  if modified_since = env["HTTP_IF_MODIFIED_SINCE"]
    modified_since?(modified_since, stat) or return
  end
  size = stat.size

  headers = {
    "Content-Type" => "application/octet-stream".freeze, # always ".fid"
    "Content-Length" => size.to_s,
    "Last-Modified" => stat.mtime.httpdate,
    "Accept-Ranges" => "bytes".freeze,
  }
  @response = [ 200, headers ]

  ranges = Rack::Utils.get_byte_ranges(env['HTTP_RANGE'], size)
  if nil == ranges || ranges.size > 1
    @range = nil
  elsif @range = ranges[0]
    @response[0] = 206
    headers["Content-Range"] = "bytes #{@range.begin}-#{@range.end}/#{size}"
    headers["Content-Length"] = (@range.end - @range.begin + 1).to_s
  else
    @response[0] = 416
    headers["Content-Range"] = "bytes */#{size}"
    headers["Content-Length"] = '0'.freeze
    @response << []
    return
  end

  case env["REQUEST_METHOD"]
  when "GET"
    @to_path, @uri = path, uri
    @response << self
  when "HEAD"
    @response << []
  else
    raise "BUG: Unexpected REQUEST_METHOD=#{env['REQUEST_METHOD']}"
  end
end

Instance Attribute Details

#responseObject (readonly)

Stores the Rack response (a 3-element Array) on success to simulate HTTP_Spew::Request objects



15
16
17
# File 'lib/regurgitator/local_file.rb', line 15

def response
  @response
end

#to_pathObject (readonly)

may be called by some Rack web servers to use sendfile(2)



8
9
10
# File 'lib/regurgitator/local_file.rb', line 8

def to_path
  @to_path
end

#uriObject (readonly)

used to provide redirects to clients



11
12
13
# File 'lib/regurgitator/local_file.rb', line 11

def uri
  @uri
end

Instance Method Details

#eachObject

normal Rack HTTP server endpoint, used if the server can’t handle to_path



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/regurgitator/local_file.rb', line 59

def each
  File.open(@to_path) do |fp|
    buf = ""
    max = 0x4000
    if @range
      fp.seek(@range.begin)
      len = @range.end - @range.begin + 1
      while len > 0 && fp.read(len > max ? max : len, buf)
        len -= buf.size
        yield buf
      end
    else
      while fp.read(0x4000, buf)
        yield buf
      end
    end
    buf.clear
  end
end

#modified_since?(modified_since, stat) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/regurgitator/local_file.rb', line 79

def modified_since?(modified_since, stat)
  begin
    modified_since = Time.httpdate(modified_since)
  rescue ArgumentError
    h = { "Content-Type" => "text/plain", "Content-Length" => "0" }
    @response = [ 400, h, [] ]
    return false
  end
  stat.mtime > modified_since and return true
  @response = [ 304, {}, [] ]
  false
end