Class: Rack::Tail::RequestHandler
- Inherits:
-
Object
- Object
- Rack::Tail::RequestHandler
- Defined in:
- lib/rack/tail/request_handler.rb
Constant Summary collapse
- SEPS =
Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
- ALLOWED_VERBS =
%w[GET HEAD]- F =
::File
Instance Attribute Summary collapse
-
#default_lines ⇒ Object
Returns the value of attribute default_lines.
-
#env ⇒ Object
Returns the value of attribute env.
-
#path ⇒ Object
Returns the value of attribute path.
-
#range ⇒ Object
Returns the value of attribute range.
-
#root ⇒ Object
Returns the value of attribute root.
Instance Method Summary collapse
- #available? ⇒ Boolean
- #call ⇒ Object
- #each ⇒ Object
-
#initialize(env, root, headers, default_mime, default_lines) ⇒ RequestHandler
constructor
A new instance of RequestHandler.
- #method_allowed? ⇒ Boolean
- #path_info ⇒ Object
- #path_is_within_root? ⇒ Boolean
- #requested_lines_size ⇒ Object
- #requested_size(response) ⇒ Object
- #serving ⇒ Object
- #tail_size_for(line_count) ⇒ Object
Constructor Details
#initialize(env, root, headers, default_mime, default_lines) ⇒ RequestHandler
Returns a new instance of RequestHandler.
20 21 22 23 24 25 26 |
# File 'lib/rack/tail/request_handler.rb', line 20 def initialize(env, root, headers, default_mime, default_lines) @root = Pathname.new(root) @headers = headers @default_mime = default_mime @default_lines = default_lines @env = env end |
Instance Attribute Details
#default_lines ⇒ Object
Returns the value of attribute default_lines.
18 19 20 |
# File 'lib/rack/tail/request_handler.rb', line 18 def default_lines @default_lines end |
#env ⇒ Object
Returns the value of attribute env.
14 15 16 |
# File 'lib/rack/tail/request_handler.rb', line 14 def env @env end |
#path ⇒ Object
Returns the value of attribute path.
17 18 19 |
# File 'lib/rack/tail/request_handler.rb', line 17 def path @path end |
#range ⇒ Object
Returns the value of attribute range.
16 17 18 |
# File 'lib/rack/tail/request_handler.rb', line 16 def range @range end |
#root ⇒ Object
Returns the value of attribute root.
15 16 17 |
# File 'lib/rack/tail/request_handler.rb', line 15 def root @root end |
Instance Method Details
#available? ⇒ Boolean
45 46 47 48 49 50 51 |
# File 'lib/rack/tail/request_handler.rb', line 45 def available? begin F.file?(path) && F.readable?(path) rescue SystemCallError false end end |
#call ⇒ Object
30 31 32 33 34 35 36 37 38 39 |
# File 'lib/rack/tail/request_handler.rb', line 30 def call return fail(405, "Method Not Allowed") unless method_allowed? return fail(403, "Forbidden") unless path_is_within_root? if available? serving else fail(404, "File not found: #{path_info}") end end |
#each ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/rack/tail/request_handler.rb', line 123 def each F.open(path, "rb") do |file| file.seek(range.begin) remaining_len = range.end-range.begin+1 while remaining_len > 0 part = file.read([8192, remaining_len].min) break unless part remaining_len -= part.length yield part end end end |
#method_allowed? ⇒ Boolean
41 42 43 |
# File 'lib/rack/tail/request_handler.rb', line 41 def method_allowed? ALLOWED_VERBS.include? env["REQUEST_METHOD"] end |
#path_info ⇒ Object
53 54 55 |
# File 'lib/rack/tail/request_handler.rb', line 53 def path_info Utils.unescape(env["PATH_INFO"]) end |
#path_is_within_root? ⇒ Boolean
57 58 59 |
# File 'lib/rack/tail/request_handler.rb', line 57 def path_is_within_root? !path.relative_path_from(root).to_s.split(SEPS).any?{|p| p == ".."} end |
#requested_lines_size ⇒ Object
81 82 83 |
# File 'lib/rack/tail/request_handler.rb', line 81 def requested_lines_size (env.fetch("QUERY_STRING")[/\d+/] || default_lines).to_i end |
#requested_size(response) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/rack/tail/request_handler.rb', line 99 def requested_size(response) # NOTE: # We check via File::size? whether this file provides size info # via stat (e.g. /proc files often don't), otherwise we have to # figure it out by reading the whole file into memory. size = F.size?(path) || Utils.bytesize(F.read(path)) # TODO handle invalid lines eg. lines=-3 tail_size = tail_size_for requested_lines_size if tail_size == size response[0] = 200 @range = 0..size-1 else start_byte = size - tail_size - 1 @range = start_byte..size-1 response[0] = 206 response[1]["Content-Range"] = "bytes #{@range.begin}-#{@range.end}/#{size}" size = @range.end - @range.begin + 1 end size end |
#serving ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/rack/tail/request_handler.rb', line 65 def serving last_modified = F.mtime(path).httpdate return [304, {}, []] if env['HTTP_IF_MODIFIED_SINCE'] == last_modified headers = { "Last-Modified" => last_modified } mime = Mime.mime_type(F.extname(path), @default_mime) headers["Content-Type"] = mime if mime # Set custom headers @headers.each { |field, content| headers[field] = content } if @headers response = [ 200, headers, env["REQUEST_METHOD"] == "HEAD" ? [] : self ] response[1]["Content-Length"] = requested_size(response).to_s response end |
#tail_size_for(line_count) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/rack/tail/request_handler.rb', line 85 def tail_size_for line_count elif = Elif.new(path) tail_size = 0 line_count.times do begin tail_size += Rack::Utils.bytesize(elif.readline) rescue EOFError return tail_size end end tail_size - 1 # Don't include the first \n end |