git clone works
[repobrowse.git] / lib / repobrowse / static.rb
blobb4e62eb24aa8bb8b19b4f59120f4dbba8a59f0e5
1 # Copyright (C) 2017 all contributors <repobrowse@80x24.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3 # frozen_string_literal: true
5 module Repobrowse::Static
6   class F < File
7     def each
8       while buf = read(8192, buf)
9         yield buf
10       end
11     ensure
12       buf&.clear
13     end
14   end
16   def fopen(env, r, pathname)
17     F.open(pathname)
18   rescue SystemCallError => e
19     b = -"Not Found\n"
20     h = {
21       'Content-Type' => -'text/plain; charset=UTF-8',
22       'Content-Length' => -b.size.to_s,
23     }
24     env['rack.logger']&.debug("E: #{pathname.inspect}: #{e.message}")
25     r.halt [ 404, h, [ b ] ]
26   end
28   def prepare_range(r, fp, h, beg, fin, size)
29     code = 200
30     len = size
31     if beg == -''
32       if fin != -'' # "bytes=-end" => last N bytes
33         beg = size - fin
34         beg = 0 if beg < 0
35         fin = size - 1
36         code = 206
37       else
38         code = 416
39       end
40     else
41       if beg > size
42         code = 416
43       elsif fin == -'' || fin >= size
44         fin = size - 1
45         code = 206
46       elsif fin < size
47         code = 206
48       else
49         code = 416
50       end
51     end
52     if code == 206
53       len = fin - beg + 1;
54       if len <= 0
55         code = 416
56       else
57         fp.seek(beg, IO::SEEK_SET) or r.halt [ 500, [], [] ]
58         h['Accept-Ranges'] = -'bytes'
59         h['Content-Range'] = "bytes #{beg}-#{fin}/#{size}"
60       end
61     end
62     if code == 416
63       h['Content-Range'] = -"bytes */#{size}"
64       r.halt [ 416, h, [] ]
65     end
66     [ code, len ]
67   end
69   def static(env, r, pathname, type, exp = 31536000)
70     h = { 'Content-Type' => type }
71     if exp
72       h['Expires'] = -((Time.now + exp).httpdate)
73       h['Cache-Control'] = -"public, max-age=#{exp}"
74     else
75       h['Expires'] = 'Fri, 01 Jan 1980 00:00:00 GMT'
76       h['Pragma'] = 'no-cache'
77       h['Cache-Control'] = 'no-cache, max-age=0, must-revalidate'
78     end
79     fp = fopen(env, r, pathname)
80     # TODO: If-Modified-Since and Last-Modified?
81     code = 200
82     st = fp.stat
83     size = st.size
84     if env['HTTP_RANGE'] =~ /\bbytes=(\d*)-(\d*)\z/
85       code, size = prepare_range(r, fp, h, $1, $2, size)
86     end
87     h['Content-Length'] = -size.to_s
88     r.halt [ code, h, fp ]
89   end
90 end