enable Range: responses for static files for most models
[rainbows.git] / lib / rainbows / response / range.rb
blob4c0d4a144ba97d774e718a084d4a07ebd903bb06
1 # -*- encoding: binary -*-
2 # :enddoc:
3 module Rainbows::Response::Range
4   HTTP_RANGE = 'HTTP_RANGE'
5   Content_Range = 'Content-Range'.freeze
6   Content_Length = 'Content-Length'.freeze
8   # This does not support multipart responses (does anybody actually
9   # use those?) +headers+ is always a Rack::Utils::HeaderHash
10   def parse_range(env, status, headers)
11     if 200 == status.to_i &&
12         (clen = headers[Content_Length]) &&
13         /\Abytes=(\d+-\d*|\d*-\d+)\z/ =~ env[HTTP_RANGE]
14       a, b = $1.split(/-/)
15       clen = clen.to_i
16       if b.nil? # bytes=M-
17         offset = a.to_i
18         count = clen - offset
19       elsif a.empty? # bytes=-N
20         offset = clen - b.to_i
21         count = clen - offset
22       else  # bytes=M-N
23         offset = a.to_i
24         count = b.to_i + 1 - offset
25       end
26       raise Rainbows::Response416 if count <= 0 || offset >= clen
27       count = clen if count > clen
28       headers[Content_Length] = count.to_s
29       headers[Content_Range] = "bytes #{offset}-#{offset+count-1}/#{clen}"
30       [ status, offset, count ]
31     end
32     # nil if no status
33   end
34 end