Module: Regurgitator::Endpoint

Includes:
Rack::Mime, Rack::Utils, FileInfo
Included in:
DomainHost, DomainPath, OneDomain
Defined in:
lib/regurgitator/endpoint.rb

Overview

:nodoc:

Instance Method Summary collapse

Methods included from FileInfo

#file_info, #file_info_init

Methods included from Device

#device_init, #device_uris!, extended, #refresh_device, #refresh_device_unlocked

Methods included from ServerSettings

extended, #refresh_zone, #refresh_zone_unlocked, #server_settings_init, #zone_for

Methods included from Domain

#domain_init, #get_dmid, #refresh_domain, #refresh_domain_unlocked

Instance Method Details

#best_addr(env) ⇒ Object



19
20
21
# File 'lib/regurgitator/endpoint.rb', line 19

def best_addr(env)
  env.include?(@reproxy_key) ? env['REMOTE_ADDR'] : Regurgitator::Local.addr
end

#empty_file(env, dkey) ⇒ Object



42
43
44
45
46
# File 'lib/regurgitator/endpoint.rb', line 42

def empty_file(env, dkey)
  headers = { 'Content-Length' => '0' }
  filename!(env, headers, dkey)
  [ 200, headers, [] ]
end

#endpoint_init(app, db, reproxy_key = nil) ⇒ Object



12
13
14
15
16
17
# File 'lib/regurgitator/endpoint.rb', line 12

def endpoint_init(app, db, reproxy_key = nil)
  @app = app
  @db = db
  @reproxy_key = reproxy_key
  file_info_init
end

#filename!(env, headers, dkey) ⇒ Object

allow users to specify desired “Save As” filenames in the query string



29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/regurgitator/endpoint.rb', line 29

def filename!(env, headers, dkey)
  params = parse_query(env['QUERY_STRING'])
  cd = nil
  if fn = params['inline'] and escape(fn) == fn
    cd, dkey = 'inline', fn
  elsif fn = (params['attachment'] || params['filename']) and
        escape(fn) == fn
    cd, dkey = 'attachment', fn
  end
  headers['Content-Disposition'] = "#{cd}; filename=#{fn}" if cd
  headers['Content-Type'] = mime_type(File.extname(dkey))
end

#reproxy_path(env) ⇒ Object

see nginx config examples for reproxy



24
25
26
# File 'lib/regurgitator/endpoint.rb', line 24

def reproxy_path(env)
  env[@reproxy_key]
end

#serve_file(env, domain, dkey) ⇒ Object



48
49
50
51
52
# File 'lib/regurgitator/endpoint.rb', line 48

def serve_file(env, domain, dkey)
  env['regurgitator.zone'] ||= best_addr(env)
  info = file_info(env, domain, dkey) or return @app.call(env)
  serve_info(env, info, dkey)
end

#serve_info(env, info, dkey) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/regurgitator/endpoint.rb', line 54

def serve_info(env, info, dkey)
  info[:length] == 0 and return empty_file(env, dkey)
  zone_uris = info[:uris]

  zone = env['regurgitator.zone']
  begin
    uris = zone_uris.delete(zone)
    uris ||= zone_uris.delete(zone_for(Regurgitator::Local.addr))

    # no nearby zones? try all of them at once!
    if uris.nil?
      uris = []
      zone_uris.each_value { |v| uris.concat v }
      zone_uris.clear
    end
    uris or next

    status, headers, body = r = Regurgitator::FileRequest.run(env, uris)
    filename!(env, headers, dkey)
    headers['ETag'] = %("#{info[:fid]}")
    headers.delete('Connection'.freeze)

    case env["REQUEST_METHOD"]
    when "GET"
      if body.respond_to?(:uri) && path = reproxy_path(env)
        body.close if body.respond_to?(:close)
        headers['Content-Length'] = '0'
        headers['Location'] = body.uri.to_s
        headers['X-Accel-Redirect'] = path
        # yes we violate Rack::Lint here
        %w(Content-Type Last-Modified).each do |key|
          headers["X-Reproxy-#{key}"] = headers.delete(key)
        end
        return [ 302, headers, [] ]
      end
      return r
    when "HEAD"
      body.close if body.respond_to?(:close)
      return [ status, headers, [] ]
    else
      raise "BUG: Unexpected REQUEST_METHOD=#{env['REQUEST_METHOD']}"
    end
  rescue Regurgitator::NoDevices
    retry unless zone_uris.empty?
    if l = env["rack.logger"]
      l.error "no devices for #{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
    end
  end until zone_uris.empty?
  @app.call(env)
end