infod 0.0.1 → 0.0.2

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.
Files changed (93) hide show
  1. data/infod.rb +2 -3
  2. data/infod/Es.rb +31 -67
  3. data/infod/{W/source.rb → Es/code.rb} +6 -10
  4. data/infod/Es/css.rb +21 -0
  5. data/infod/{W → Es}/csv.rb +0 -0
  6. data/infod/Es/du.rb +16 -0
  7. data/infod/{W → Es}/feed.rb +13 -11
  8. data/infod/Es/filter.rb +75 -0
  9. data/infod/Es/find.rb +20 -0
  10. data/infod/Es/fs.rb +145 -136
  11. data/infod/Es/glob.rb +22 -0
  12. data/infod/Es/grep.rb +61 -0
  13. data/infod/Es/groonga.rb +47 -56
  14. data/infod/Es/html.rb +271 -0
  15. data/infod/Es/image.rb +114 -0
  16. data/infod/Es/in.rb +68 -0
  17. data/infod/Es/index.rb +183 -0
  18. data/infod/{W → Es}/json.rb +28 -4
  19. data/infod/Es/kv.rb +60 -0
  20. data/infod/Es/ls.rb +58 -0
  21. data/infod/Es/mail.rb +87 -0
  22. data/infod/Es/man.rb +112 -0
  23. data/infod/Es/mime.rb +59 -0
  24. data/infod/Es/out.rb +52 -0
  25. data/infod/{W/page.rb → Es/pager.rb} +7 -3
  26. data/infod/Es/pdf.rb +19 -0
  27. data/infod/Es/rdf.rb +35 -0
  28. data/infod/Es/schema.rb +99 -0
  29. data/infod/Es/search.rb +24 -0
  30. data/infod/Es/sh.rb +21 -0
  31. data/infod/{W → Es}/text.rb +26 -14
  32. data/infod/H.rb +15 -29
  33. data/infod/H/audio.rb +19 -0
  34. data/infod/H/blog.rb +15 -0
  35. data/infod/{W → H}/cal.rb +2 -31
  36. data/infod/H/edit.rb +88 -0
  37. data/infod/{W/examine/examine.rb → H/facets.rb} +17 -17
  38. data/infod/{W → H}/forum.rb +1 -0
  39. data/infod/{W/examine/sw.rb → H/hf.rb} +12 -12
  40. data/infod/H/histogram.rb +78 -0
  41. data/infod/H/mail.rb +92 -0
  42. data/infod/{W/chat.rb → H/microblog.rb} +21 -16
  43. data/infod/H/threads.rb +77 -0
  44. data/infod/H/time.rb +131 -0
  45. data/infod/H/who.rb +30 -0
  46. data/infod/{W → H}/wiki.rb +0 -0
  47. data/infod/K.rb +28 -60
  48. data/infod/N.rb +151 -74
  49. data/infod/Rb.rb +3 -3
  50. data/infod/Th.rb +27 -101
  51. data/infod/Th/404.rb +29 -36
  52. data/infod/Th/500.rb +36 -5
  53. data/infod/Th/GET.rb +48 -118
  54. data/infod/Th/POST.rb +31 -11
  55. data/infod/Th/perf.rb +37 -0
  56. data/infod/Th/util.rb +89 -0
  57. data/infod/Y.rb +24 -7
  58. data/infod/infod.rb +2 -3
  59. metadata +92 -64
  60. data/infod/Es/redis.rb +0 -3
  61. data/infod/Es/sqlite.rb +0 -3
  62. data/infod/Th/local.rb +0 -22
  63. data/infod/W.rb +0 -34
  64. data/infod/W/audio.rb +0 -56
  65. data/infod/W/blog.rb +0 -3
  66. data/infod/W/color.rb +0 -28
  67. data/infod/W/core.rb +0 -77
  68. data/infod/W/css.rb +0 -24
  69. data/infod/W/du.rb +0 -35
  70. data/infod/W/edit.rb +0 -8
  71. data/infod/W/examine/exhibit.rb +0 -34
  72. data/infod/W/examine/hist.rb +0 -55
  73. data/infod/W/examine/history.rb +0 -19
  74. data/infod/W/examine/normal.rb +0 -31
  75. data/infod/W/examine/protovis.rb +0 -30
  76. data/infod/W/examine/time/graph.rb +0 -86
  77. data/infod/W/examine/time/line.rb +0 -24
  78. data/infod/W/find.rb +0 -24
  79. data/infod/W/grep.rb +0 -27
  80. data/infod/W/html.rb +0 -143
  81. data/infod/W/image.rb +0 -61
  82. data/infod/W/kv.rb +0 -66
  83. data/infod/W/ls.rb +0 -50
  84. data/infod/W/mail.rb +0 -248
  85. data/infod/W/pdf.rb +0 -16
  86. data/infod/W/post.rb +0 -9
  87. data/infod/W/rdf.rb +0 -32
  88. data/infod/W/schema.rb +0 -172
  89. data/infod/W/search.rb +0 -33
  90. data/infod/W/shell.rb +0 -30
  91. data/infod/W/table.rb +0 -87
  92. data/infod/W/tree.rb +0 -26
  93. data/infod/W/vfs.rb +0 -175
data/infod/Rb.rb CHANGED
@@ -4,7 +4,7 @@ class Array
4
4
  def head; self[0] end
5
5
  def tail; self[1..-1] end
6
6
  def snd; self[1] end
7
- def r; self[rand length] end
7
+ def random; self[rand length] end
8
8
  def h; join.h end
9
9
  def intersperse i
10
10
  inject([]){|a,b|a << b << i}[0..-2]
@@ -65,7 +65,7 @@ end
65
65
  class NilClass
66
66
  def do; nil end
67
67
  def to_ary; [] end
68
+ def to_hash; {} end
68
69
  def to_s; "" end
69
- alias_method :to_str,:to_s
70
- def method_missing *a; nil; end
70
+ %w{html to_str}.map{|m|alias_method m,:to_s}
71
71
  end
data/infod/Th.rb CHANGED
@@ -1,110 +1,36 @@
1
- %w{GET HEAD POST PATCH uid 404 500}.map{|i|require_relative 'Th/' + i}
1
+ #watch __FILE__
2
2
  require 'rack'
3
-
4
- class String
5
- # parse querystring
6
- def qp
7
- d={}
8
- split(/&/).map{|e|
9
- k,v=e.split(/=/,2).map{|x|
10
- CGI.unescape x}
11
- d[k]=v}
12
- d
13
- end
14
- def hR
15
- [200,{'Content-Type'=>'text/html'},[self]]
16
- end
17
- end
18
-
19
- module Tb
20
- def q
21
- @q ||= self.().qp
22
- end
23
- end
24
-
25
- module Th
26
- def qs
27
- (['GET','HEAD'].member? fn) ? self['QUERY_STRING'] : self['rack.input'].read
28
- end
29
- # read querystring
30
- def q
31
- @q ||= (qs||'').qp.do{|q|
32
- (q['?']).do{|d|
33
- E::F['?'][d].do{|g| # expand aliases
34
- g.merge q
35
- } || q } || q}
36
- end
37
- # read Accept header
38
- def accept_ k=''
39
- d={}
40
- self['HTTP_ACCEPT'+k].do{|k|
41
- k.split(/,/).map{|e|
42
- f,q=e.split(/;/)
43
- i=q&&q.split(/=/)[1].to_f||1
44
- d[i]||=[]
45
- d[i].push f}}
46
- d
47
- end
48
-
49
- def format
50
- @format ||= conneg
51
- end
52
-
53
- def conneg
54
- # choose a preferred content-type
55
- return q['format'] if q['format'] && E::F[E::Render+q['format']]
56
- accept.sort.reverse.map{|p|p[1].map{|mime|
57
- return mime if E::F[E::Render+mime]
58
- }}
59
- 'text/html'
60
- end
61
-
62
- def accept; @accept ||= accept_ end
63
-
64
- def fn
65
- # request method (Symbol) getter
66
- self['REQUEST_METHOD']
67
- end
68
- end
69
-
70
- class Hash
71
- def qs
72
- '?'+map{|k,v|k.to_s+'='+(v ? (CGI.escape [*v][0].to_s) : '')}.intersperse("&").join('')
73
- end
74
- def env r # thread environment through to children
75
- @r = r
76
- self
77
- end
78
- end
3
+ %w{GET HEAD POST PATCH perf uid util 404 500}.map{|i|require_relative 'Th/' + i}
79
4
 
80
5
  class E
81
6
 
82
- F['?'] ||= {}
83
-
84
- # access or update request environment
85
- def env r=nil
86
- r ? (@r = r
87
- self) : @r
88
- end
89
-
90
7
  def E.call e
91
- dev # check for changed source code
92
- e.extend Th # enable request-related utility functions
93
- e['HTTP_X_FORWARDED_HOST'].do{|h| e['SERVER_NAME'] = h } # hostname
94
- (e['REQUEST_PATH'].force_encoding('UTF-8').do{|u| # path
95
- CGI.unescape(u.index(Prefix)==0 ? u[Prefix.size..-1] : # non-local or non-HTTP URI
96
- 'http://' + e['SERVER_NAME'] + u.gsub('+','%2B')) # HTTP URI
97
- }.E.env(e).jail.do{|r| # valid path?
98
- e['uri']=r.uri; r.send e.fn # update URI and continue
99
- } || [403,{},['invalid path']]). # reject
100
- do{|response| puts [ # inspect
101
- e.fn, response[0],['http://', e['SERVER_NAME'], e['REQUEST_URI']].join,e['HTTP_USER_AGENT'],e['HTTP_REFERER']].join ' '
102
- response }
8
+ dev
9
+ e.extend Th
10
+ e['HTTP_X_FORWARDED_HOST'].do{|h| e['SERVER_NAME'] = h }
11
+ p = e['REQUEST_PATH'].force_encoding 'UTF-8'
12
+
13
+ uri = CGI.unescape(if (p.index Prefix) == 0
14
+ p[Prefix.size..-1]
15
+ else
16
+ 'http://' + e['SERVER_NAME'] + (p.gsub '+','%2B')
17
+ end).E.env e
18
+
19
+ if (uri.node.expand_path.to_s.index FSbase) == 0
20
+ e['uri'] = uri.uri
21
+ # response
22
+ r = nil # request method
23
+ b = Benchmark.measure{ r = uri.send e.fn }
24
+ F['log'][r[0],e,b.real]
25
+ r
26
+ else
27
+ [403,{},['Forbidden']]
103
28
  end
104
29
 
105
- # load site-specific code-base
106
-
107
- E['http:/*/*.rb'].glob.map{|s| puts "site config #{s}"
108
- require s.d}
30
+ rescue Exception => x
31
+ $stderr.puts 500, e['REQUEST_URI'] ,x.message,x.backtrace
32
+ F['log'][500,e]
33
+ F['E500'][x,@r]
34
+ end
109
35
 
110
36
  end
data/infod/Th/404.rb CHANGED
@@ -1,55 +1,48 @@
1
+ watch __FILE__
1
2
  class E
2
3
 
3
- # 404 response URI
4
4
  E404 = 'req/'+HTTP+'404'
5
5
 
6
- # 404 response function
7
6
  fn E404,->e,r{
8
- u = e.uri # response URI
9
- g = {u => {}} # response graph
10
- s = g[u] # resource pointer
11
- # add request data to response graph
12
- r.map{|k,v| s[k] = [v] }
13
- s[Type] = [E[HTTP+'404']]
14
- s['uri'] = u
15
- s['QUERY'] = [r.q]
16
- s['ACCEPT']= [r.accept]
17
- s['SERVER_SOFTWARE']=[('//'+r['SERVER_NAME']).E]
18
- s['http://buzzword.org.uk/rdf/personal-link-types#edit']=[E[u+'?view=edit&graph=_']]
19
- %w{CHARSET LANGUAGE ENCODING}.map{|a|s['ACCEPT_'+a] = [(r.accept_ '_' + a)]}
20
- # output
21
- r.q.delete 'view' # use 404 view if HTML
22
- [404,{'Content-Type'=> r.format},[e.render(r.format,g,r)]]}
7
+ id = e.uri # response URI
8
+ g = {id=>{}} # response graph
9
+ s = g[id] # resource pointer
10
+ fn = r['REQUEST_METHOD']
23
11
 
24
- # qs y=404 to force a 404 response
25
- F['req/404'] = F[E404]
12
+ # request environment -> graph
13
+ r.map{|k,v| s[Header + k] = k == 'uri' ? v : [v] }
14
+ %w{CHARSET LANGUAGE ENCODING}.map{|a|
15
+ s[Header+'ACCEPT_'+a] = [r.accept_('_' + a)]}
16
+ s[Header+'ACCEPT'] = [r.accept]
17
+ s[Type] = [E[HTTP+'Response']]
18
+ s[HTTP+'statusCodeValue'] = [404]
19
+ s[Header+'HTTP_HOST'] = [E['http://' + s[Header+'HTTP_HOST'][0]]]
20
+ s[Edit] = [E[r['REQUEST_PATH']+'?view=edit&graph=editable']]
21
+ s['#query'] = [r.q]
22
+ s['#seeAlso'] = [e.parent,*e.a('*').glob]
23
+ r.q['view'] = '404'
26
24
 
27
- fn 'view/'+HTTP+'404',->d,e{
28
- [H.css('/css/404'),{_: :h1, c: '404'},d.html]}
25
+ [404,{'Content-Type'=> r.format},[e.render(r.format,g,r)]]}
26
+
27
+ fn 'view/404',->d,e{
28
+ [H.css('/css/404'),{_: :style, c: "a {background-color:#{E.cs}}"},
29
+ d.html]}
29
30
 
30
- # 404.css if fs content is missing
31
- fn '/css/404.css/GET',->e,r{
32
- [200,{'Content-Type'=>'text/css'},
33
- ["body {background-color:#000;color:#fff; font-family: sans-serif}
34
- a {font-size:1.05em;background-color:#1ef;color:#000;text-decoration:none;padding:.1em}
35
- td.key {text-align:right}
36
- td.key .frag {font-weight:bold;background-color:#0f0;color:#000;padding-left:.2em;border-radius:.38em 0 0 .38em}
37
- td.key .abbr {color:#eee;font-size:.92em}
38
- td.val {border-style:dotted;border-width:0 0 .1em 0;border-color:#00f;}"]]}
31
+ # a small non-empty graph
32
+ fn 'protograph/_',->d,_,m{
33
+ m[d.uri] = {}
34
+ rand.to_s.h}
39
35
 
40
- # show response-codes for a list of URIs
36
+ # check response-codes for a list of URIs (linebreak-separated *.u files)
41
37
  def checkURIs
42
38
  r = uris.select{|u|u.to_s.match /^http/}.map{|u|
43
39
  c = [`curl -IsA 404? "#{u}"`.lines.to_a[0].match(/\d{3}/)[0].to_i,u] # HEAD
44
- #c = [`curl -s -o /dev/null -w %{http_code} "#{u}"`.chomp.to_i,u] # GET
45
40
  puts c.join ' '
46
- c # status, uri tuple
47
- }
41
+ c } # status, uri tuple
48
42
  puts "\n\n"
49
43
  r.map{|c|
50
44
  # show anomalies
51
- puts c.join(' ') unless c[0] == 200
52
- }
45
+ puts c.join(' ') unless c[0] == 200 }
53
46
  end
54
47
 
55
48
  end
data/infod/Th/500.rb CHANGED
@@ -1,10 +1,41 @@
1
- #watch __FILE__
2
1
  class E
3
2
 
4
- fn 'backtrace',->x,r{
3
+ fn '/css/500.css/GET',->e,r{
4
+ [200,{'Content-Type'=>'text/css'},["
5
+ body {margin:0; font-family: sans-serif; background-color:#fff; color:#000}
6
+ h1 {padding:.2em; background-color:#f00; color:#fff; margin:0}
7
+ div {display:inline}
8
+ table {border-spacing:0;margin:0}
9
+ b {background-color:#eee;color:#500;padding:.1em .3em .1em .3em}
10
+ .frag {font-weight:bold; color:#000; background-color:#{E.cs}}
11
+ td.space {background-color:#ddd}
12
+ td.message {background-color:#009;color:#fff}
13
+ td.path {text-align:right}
14
+ td.index {text-align:right;border-color:#000;border-width:0 0 .1em 0;border-style:dotted;background-color:#ddd;color:#000}
15
+ td.context {border-color:#ddd;border-width:0 0 .1em 0;border-style:dotted;padding:.15em}"]]}
16
+
17
+ F['/E/error/GET'] = ->e,r{1/0}
18
+
19
+ fn 'E500',->x,r{
5
20
  [500,{'Content-Type'=>'text/html'},
6
- ['<html><head><title>500</title></head><body><h1>500</h1><pre>',
7
- [x.class.to_s,x.message,*x.backtrace].join("\n").hrefs,
8
- '</pre></body></html>']]}
21
+ [H[{_: :html,
22
+ c: [{_: :head,
23
+ c: [{_: :title, c: 500},(H.css '/css/500')]},
24
+ {_: :body,
25
+ c: [{_: :h1, c: 500},
26
+ {_: :table,
27
+ c: [{_: :tr,
28
+ c: [{_: :td, c: {_: :b, c: x.class}},
29
+ {_: :td, class: :space},
30
+ {_: :td, class: :message, c: x.message.hrefs}
31
+ ]},
32
+ x.backtrace.map{|p|
33
+ p = p.split /:/, 3
34
+ {_: :tr,
35
+ c: [{_: :td, class: :path, c: F['abbrURI'][p[0]]},
36
+ {_: :td, class: :index, c: p[1]},
37
+ {_: :td, class: :context, c: (p[2]||'').hrefs}].cr}}.cr]}]}]}]]]}
9
38
 
39
+ F['/500/GET'] = ->e,r{H([Errors.sort_by{|u,r|r[:time]}.reverse.html,H.css('/css/500')]).hR}
40
+
10
41
  end
data/infod/Th/GET.rb CHANGED
@@ -1,132 +1,62 @@
1
1
  class E
2
2
 
3
3
  def GET
4
- a = @r.accept.values.flatten # acceptable MIME types
5
- send(f ? (if (@r.q.has_any_key(['format','graph','view']) || # user-specified view
6
- (MIMEcook[mime] && !@r.q.has_key?('raw')) || # view for MIME-type
7
- !(a.empty?||a.member?(mime)||a.member?('*/*'))) # file MIME not accepted
8
- :GET_resource # invoke resource handler
9
- else
10
- :GET_img # continue to file handler
11
- end) :
12
- :GET_resource)
13
- rescue Exception => x
14
- $stderr.puts 500,x.message,x.backtrace
15
- Fn 'backtrace',x,@r
16
- end
17
-
18
- def maybeSend m,b,lH=false
19
- send? ? # agent already has this version?
20
- b.().do{|b| # continue
21
- h = {'Content-Type'=> m, 'ETag'=> @r['ETag']} # response header
22
- m.match(/^(audio|image|video)/) && # media MIME-type?
23
- h.update({'Cache-Control' => 'no-transform'}) # no further compression
24
- h.update({'MS-Author-Via' => 'DAV, SPARQL'}) # authoring
25
- lH && h.update({'Link' => '<' + (URI.escape uri) + '?format=text/n3>; rel=meta'}) # Link Header - full URI variant
26
- b.class == E ? (Nginx ? # nginx env-var
27
- [200,h.update({'X-Accel-Redirect' => '/fs' + b.path}),[]] : # Nginx file-handler
28
- Apache ? # Apache env-var
29
- [200,h.update({'X-Sendfile' => b.d}),[]] : # Apache file-handler
30
- (r = Rack::File.new nil # create Rack file-handler
31
- r.instance_variable_set '@path',b.d # set path
32
- r.serving(@r).do{|s,m,b|[s,m.update(h),b]}) # Rack file-handler
33
- ) :
34
- [200, h, b]} : # response triple
35
- [304,{},[]] # not modified
4
+ # bespoke handler ||
5
+ # raw file ||
6
+ # resource
7
+ if reqFn = F['req/'+@r.q['y']]
8
+ reqFn[self,@r]
9
+ elsif file = [self,pathSegment].compact.find(&:f)
10
+ a = @r.accept.values.flatten
11
+ accepted = a.empty? || (a.member? file.mimeP) || (a.member? '*/*')
12
+ (@r.q.has_any_key(%w{format view}) ||
13
+ MIMEcook[file.mimeP] || !accepted) ? resource : (file.env @r).getFile
14
+ else
15
+ resource
16
+ end
36
17
  end
37
18
 
38
- def send?
39
- !((m=@r['HTTP_IF_NONE_MATCH']) && m.strip.split(/\s*,\s*/).include?(@r['ETag']))
40
- end
41
-
42
- def GET_file
19
+ def getFile
43
20
  @r['ETag'] = [m,size].h
44
- maybeSend mime,->{self},:link
21
+ maybeSend mimeP,->{self},:link
45
22
  end
46
23
 
47
- def GET_img
48
- (thumb? ? thumb : self).GET_file
49
- end
50
-
51
- def GET_resource # for
52
- (F['req/'+@r.q['y']] || # any URI
53
- F[@r['REQUEST_PATH'].t+('GET')]||# specific path
54
- F[uri.t+('GET')] # specific URI
55
- ).do{|y|y.(self,@r)} || # custom handler
56
- as('index.html').do{|i| # HTML index
57
- i.e && # exists?
58
- ((uri[-1]=='/') ? i.env(@r).GET_file : # are we inside dir?
59
- [301, {Location: uri.t}] )} || # rebase to index dir
24
+ def resource
25
+ # bubble up site then global tree until handled (false return-value to pass)
26
+ pathSegment.do{|path|
27
+ lambdas = path.cascade.map{|p| p.uri.t + 'GET' }
28
+ ['http://'+@r['SERVER_NAME'],""].map{|h| lambdas.map{|p|
29
+ F[h + p].do{|fn| fn[self,@r].do{|r| return r}}}}}
30
+
31
+ # default handler
60
32
  response
61
33
  end
62
34
 
63
- # graph constructor
64
- fn 'graph/',->e,q,m{
65
- F['set/' + q['set']][e, q, m]. # doc set
66
- map{|u|m[u.uri] ||= u}}
67
-
68
- # document set constructor
69
- fn 'set/',->d,e,m{d.docs}
70
-
71
- # construct HTTP response
72
- def response
73
-
74
- # request arguments
75
- q = @r.q # query-string
76
- g = q['graph'] # graph-generation function selector
77
-
78
- # request graph
79
- m = {}
80
-
81
- # add resources to request graph
82
- F['graph/' + g][self,q,m]
83
-
84
- # empty graph -> 404
85
- return F[E404][self,@r] if m.empty?
86
-
87
- # inspect request-graph
88
- if q.has_key? 'debug'
89
- puts "docs #{m.keys.join ' '}"
90
- puts "resources #{m['frag']['res']}" if m['frag']
91
- end
92
-
93
- # request-graph identifier
94
- s = (q.has_key?('nocache') ? rand.to_s : # random identifier
95
- m.sort.map{|u,r|[u, r.respond_to?(:m) && r.m]}).h # canonicalized set signature
96
-
97
- # response identifier
98
- @r['ETag'] ||= [s, q, @r.format].h
99
-
100
- # check if client has response
101
- maybeSend @r.format, ->{
102
-
103
- # cached response identifier
104
- r = E'/E/req/' + @r['ETag'].dive
105
-
106
- if r.e # response already generated
107
- r # cached response
108
- else
109
-
110
- # cached graph identifier
111
- c = E '/E/graph/' + s.dive
112
-
113
- if c.e # cached graph exists
114
- m.merge! c.r true # read cache
115
- else
116
- # construct response graph
117
- m.values.map{|r|
118
- r.env(@r).graphFromFile m}
119
-
120
- # cache response graph
121
- c.w m,true
122
- end
123
-
124
- # response graph sorting/filtering
125
- E.filter q, m, self
126
-
127
- # response body
128
- r.w render @r.format, m, @r
129
- end }
35
+ def send?
36
+ !((m=@r['HTTP_IF_NONE_MATCH']) && m.strip.split(/\s*,\s*/).include?(@r['ETag']))
130
37
  end
131
38
 
39
+ def maybeSend m,b,lH=false
40
+ # agent need this version?
41
+ send? ?
42
+ # continue
43
+ b[].do{|b|
44
+ # response metadata
45
+ h = {'Content-Type'=> m,
46
+ 'ETag'=> @r['ETag']}
47
+ h.update({'Cache-Control' => 'no-transform'}) if m.match /^(audio|image|video)/
48
+ h.update({'Link' => '<' + @r['uri'] + '?view=base>; rel=meta'}) if lH
49
+
50
+ b.class == E ? (Nginx ? # nginx enabled
51
+ [200,h.update({'X-Accel-Redirect' => '/fs' + b.path}),[]] : # Nginx file-handler
52
+ Apache ? # Apache enabled
53
+ [200,h.update({'X-Sendfile' => b.d}),[]] : # Apache file-handler
54
+ (r = Rack::File.new nil # Rack file-handler
55
+ r.instance_variable_set '@path',b.d
56
+ r.serving(@r).do{|s,m,b|[s,m.update(h),b]})
57
+ ) :
58
+ [200, h, b]} : # normal (unaccelerated) response
59
+ [304,{},[]] # client has response version
60
+ end
61
+
132
62
  end