rack_grid 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.
- data/README.txt +31 -0
- data/lib/rack_grid.rb +113 -0
- data/test/test_rack_grid.rb +0 -0
- metadata +68 -0
data/README.txt
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Rack::Grid
|
2
|
+
|
3
|
+
Rack::Grid is used to serve a GridFS file from rack.
|
4
|
+
Especially useful combined with Mongoid::Grid or MongoODM::Grid
|
5
|
+
|
6
|
+
Installation
|
7
|
+
|
8
|
+
# gem install rack_grid
|
9
|
+
|
10
|
+
Usage Example with Sinatra.
|
11
|
+
|
12
|
+
# app.rb
|
13
|
+
require 'rack_grid'
|
14
|
+
configure do
|
15
|
+
use Rack::Grid, {
|
16
|
+
:host => 'localhost', # MongoDB Hostname (default: localhost)
|
17
|
+
:port => 27017, # MongoDB Port (default: 27017)
|
18
|
+
:username => 'user', # Optional MongoDB Username
|
19
|
+
:password => 'pass', # Optional MongoDB Password
|
20
|
+
:prefix => 'grid', # URL Prefix (eg: /grid/xxxxxxx/file.ext)
|
21
|
+
:cache_control => 300, # Cache Control setting
|
22
|
+
:database => 'mydb' # Required database name
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
# view.erb
|
27
|
+
<img src="/grid/4ba69fde8c8f369a6e000003/filename.jpg" alt="My Image" />
|
28
|
+
|
29
|
+
|
30
|
+
Inspired by
|
31
|
+
http://github.com/skinandbones/rack-gridfs
|
data/lib/rack_grid.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'mongo'
|
3
|
+
module Rack
|
4
|
+
class Grid
|
5
|
+
class ConnectionError < StandardError ; end
|
6
|
+
|
7
|
+
attr_reader :host, :port, :database, :prefix, :username, :password
|
8
|
+
|
9
|
+
def initialize(app, options = {})
|
10
|
+
opts = {}
|
11
|
+
options.each { |k,v| opts[k.to_s] = v }
|
12
|
+
options = {
|
13
|
+
'host' => 'localhost',
|
14
|
+
'prefix' => 'grid',
|
15
|
+
'port' => Mongo::Connection::DEFAULT_PORT
|
16
|
+
}.merge(opts)
|
17
|
+
|
18
|
+
@app = app
|
19
|
+
@host = options['host']
|
20
|
+
@port = options['port']
|
21
|
+
@database = options['database']
|
22
|
+
@prefix = options['prefix']
|
23
|
+
@username = options['username']
|
24
|
+
@password = options['password']
|
25
|
+
@db = options['db']
|
26
|
+
|
27
|
+
@cache_control = options['cache_control']
|
28
|
+
end
|
29
|
+
|
30
|
+
def db
|
31
|
+
@db = @db.call() if Proc === @db
|
32
|
+
connect! unless @db
|
33
|
+
@db
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Strip the _id out of the path. This allows the user to send something
|
38
|
+
# like /grid/4ba69fde8c8f369a6e000003/filename.jpg to find the file
|
39
|
+
# with an id of 4ba69fde8c8f369a6e000003.
|
40
|
+
def call(env)
|
41
|
+
@env = env
|
42
|
+
request = Rack::Request.new(@env)
|
43
|
+
if request.path_info =~ /^\/#{prefix}\/(\w+).*$/
|
44
|
+
grid_request($1)
|
45
|
+
else
|
46
|
+
@app.call(env)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Get file from GridFS or return a 404
|
52
|
+
def grid_request(id)
|
53
|
+
file = Mongo::Grid.new(db).get(BSON::ObjectId.from_string(id))
|
54
|
+
etag, last_modified = file.instance_variable_get(:@md5), Time.at( file.upload_date.to_i )
|
55
|
+
headers = {
|
56
|
+
'ETag' => "\"#{etag}\"",
|
57
|
+
'Last-Modified' => last_modified.httpdate,
|
58
|
+
'Cache-Control' => cache_control_header,
|
59
|
+
}
|
60
|
+
if not_modified?( etag, last_modified )
|
61
|
+
[304, headers, 'Not Modified']
|
62
|
+
else
|
63
|
+
[200, headers.update('Content-Type' => file.content_type), [file.read]]
|
64
|
+
end
|
65
|
+
rescue Mongo::GridError, BSON::InvalidObjectId
|
66
|
+
[404, {'Content-Type' => 'text/plain'}, ['File not found.']]
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def connect!
|
71
|
+
Timeout::timeout(5) do
|
72
|
+
@db = Mongo::Connection.new(host,port).db(database)
|
73
|
+
db.authenticate(username, password) if (username || password)
|
74
|
+
end
|
75
|
+
rescue StandardError => e
|
76
|
+
raise ConnectionError, "Timeout connecting to GridFS (#{e.to_s})"
|
77
|
+
end
|
78
|
+
|
79
|
+
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
|
80
|
+
def cache_control_header
|
81
|
+
if @cache_control.blank?
|
82
|
+
DEFAULT_CACHE_CONTROL
|
83
|
+
|
84
|
+
elsif @cache_control[:no_cache]
|
85
|
+
'no-cache'
|
86
|
+
|
87
|
+
else
|
88
|
+
extras = @cache_control[:extras]
|
89
|
+
max_age = @cache_control[:max_age]
|
90
|
+
|
91
|
+
options = []
|
92
|
+
options << "max-age=#{max_age.to_i}" if max_age
|
93
|
+
options << (@cache_control[:public] ? 'public' : 'private')
|
94
|
+
options << 'must-revalidate' if @cache_control[:must_revalidate]
|
95
|
+
options.concat(extras) if extras
|
96
|
+
|
97
|
+
options.join(', ')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def not_modified?( etag, last_modified )
|
102
|
+
if_none_match = @env['HTTP_IF_NONE_MATCH']
|
103
|
+
if if_modified_since = @env['HTTP_IF_MODIFIED_SINCE']
|
104
|
+
if_modified_since = Time.rfc2822( if_modified_since ) rescue nil
|
105
|
+
end
|
106
|
+
|
107
|
+
not_modified = if_none_match.present? || if_modified_since.present?
|
108
|
+
not_modified &&= (if_none_match == "\"#{etag}\"") if if_none_match && etag
|
109
|
+
not_modified &&= (if_modified_since >= last_modified) if if_modified_since && last_modified
|
110
|
+
not_modified
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack_grid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.2
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dusty Doris
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-10 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: mongo
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
description: Rack helper for presenting MongoDB GridFS Files
|
28
|
+
email: github@dusty.name
|
29
|
+
executables: []
|
30
|
+
|
31
|
+
extensions: []
|
32
|
+
|
33
|
+
extra_rdoc_files:
|
34
|
+
- README.txt
|
35
|
+
files:
|
36
|
+
- README.txt
|
37
|
+
- lib/rack_grid.rb
|
38
|
+
- test/test_rack_grid.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/dusty/rack_grid
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project: none
|
63
|
+
rubygems_version: 1.6.2
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Rack helper for presenting MongoDB GridFS Files
|
67
|
+
test_files: []
|
68
|
+
|