infod 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/infod.rb +2 -3
- data/infod/Es.rb +31 -67
- data/infod/{W/source.rb → Es/code.rb} +6 -10
- data/infod/Es/css.rb +21 -0
- data/infod/{W → Es}/csv.rb +0 -0
- data/infod/Es/du.rb +16 -0
- data/infod/{W → Es}/feed.rb +13 -11
- data/infod/Es/filter.rb +75 -0
- data/infod/Es/find.rb +20 -0
- data/infod/Es/fs.rb +145 -136
- data/infod/Es/glob.rb +22 -0
- data/infod/Es/grep.rb +61 -0
- data/infod/Es/groonga.rb +47 -56
- data/infod/Es/html.rb +271 -0
- data/infod/Es/image.rb +114 -0
- data/infod/Es/in.rb +68 -0
- data/infod/Es/index.rb +183 -0
- data/infod/{W → Es}/json.rb +28 -4
- data/infod/Es/kv.rb +60 -0
- data/infod/Es/ls.rb +58 -0
- data/infod/Es/mail.rb +87 -0
- data/infod/Es/man.rb +112 -0
- data/infod/Es/mime.rb +59 -0
- data/infod/Es/out.rb +52 -0
- data/infod/{W/page.rb → Es/pager.rb} +7 -3
- data/infod/Es/pdf.rb +19 -0
- data/infod/Es/rdf.rb +35 -0
- data/infod/Es/schema.rb +99 -0
- data/infod/Es/search.rb +24 -0
- data/infod/Es/sh.rb +21 -0
- data/infod/{W → Es}/text.rb +26 -14
- data/infod/H.rb +15 -29
- data/infod/H/audio.rb +19 -0
- data/infod/H/blog.rb +15 -0
- data/infod/{W → H}/cal.rb +2 -31
- data/infod/H/edit.rb +88 -0
- data/infod/{W/examine/examine.rb → H/facets.rb} +17 -17
- data/infod/{W → H}/forum.rb +1 -0
- data/infod/{W/examine/sw.rb → H/hf.rb} +12 -12
- data/infod/H/histogram.rb +78 -0
- data/infod/H/mail.rb +92 -0
- data/infod/{W/chat.rb → H/microblog.rb} +21 -16
- data/infod/H/threads.rb +77 -0
- data/infod/H/time.rb +131 -0
- data/infod/H/who.rb +30 -0
- data/infod/{W → H}/wiki.rb +0 -0
- data/infod/K.rb +28 -60
- data/infod/N.rb +151 -74
- data/infod/Rb.rb +3 -3
- data/infod/Th.rb +27 -101
- data/infod/Th/404.rb +29 -36
- data/infod/Th/500.rb +36 -5
- data/infod/Th/GET.rb +48 -118
- data/infod/Th/POST.rb +31 -11
- data/infod/Th/perf.rb +37 -0
- data/infod/Th/util.rb +89 -0
- data/infod/Y.rb +24 -7
- data/infod/infod.rb +2 -3
- metadata +92 -64
- data/infod/Es/redis.rb +0 -3
- data/infod/Es/sqlite.rb +0 -3
- data/infod/Th/local.rb +0 -22
- data/infod/W.rb +0 -34
- data/infod/W/audio.rb +0 -56
- data/infod/W/blog.rb +0 -3
- data/infod/W/color.rb +0 -28
- data/infod/W/core.rb +0 -77
- data/infod/W/css.rb +0 -24
- data/infod/W/du.rb +0 -35
- data/infod/W/edit.rb +0 -8
- data/infod/W/examine/exhibit.rb +0 -34
- data/infod/W/examine/hist.rb +0 -55
- data/infod/W/examine/history.rb +0 -19
- data/infod/W/examine/normal.rb +0 -31
- data/infod/W/examine/protovis.rb +0 -30
- data/infod/W/examine/time/graph.rb +0 -86
- data/infod/W/examine/time/line.rb +0 -24
- data/infod/W/find.rb +0 -24
- data/infod/W/grep.rb +0 -27
- data/infod/W/html.rb +0 -143
- data/infod/W/image.rb +0 -61
- data/infod/W/kv.rb +0 -66
- data/infod/W/ls.rb +0 -50
- data/infod/W/mail.rb +0 -248
- data/infod/W/pdf.rb +0 -16
- data/infod/W/post.rb +0 -9
- data/infod/W/rdf.rb +0 -32
- data/infod/W/schema.rb +0 -172
- data/infod/W/search.rb +0 -33
- data/infod/W/shell.rb +0 -30
- data/infod/W/table.rb +0 -87
- data/infod/W/tree.rb +0 -26
- 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
|
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
|
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
|
-
|
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
|
92
|
-
e.extend Th
|
93
|
-
e['HTTP_X_FORWARDED_HOST'].do{|h| e['SERVER_NAME'] = h }
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
9
|
-
g = {
|
10
|
-
s = g[
|
11
|
-
|
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
|
-
|
25
|
-
|
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
|
-
|
28
|
-
|
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
|
-
#
|
31
|
-
fn '/
|
32
|
-
[
|
33
|
-
|
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
|
-
#
|
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 '
|
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
|
-
[
|
7
|
-
|
8
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
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
|
21
|
+
maybeSend mimeP,->{self},:link
|
45
22
|
end
|
46
23
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
64
|
-
|
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
|