dragonfly 0.9.15 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dragonfly might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitignore +1 -8
- data/.travis.yml +11 -0
- data/Gemfile +1 -0
- data/History.md +52 -2
- data/LICENSE +1 -1
- data/README.md +38 -95
- data/dev/grid.jpg +0 -0
- data/dev/irbrc.rb +27 -0
- data/dev/rails_template.rb +38 -0
- data/dev/test.ru +56 -0
- data/dev/test_rails +19 -0
- data/dragonfly.gemspec +3 -21
- data/lib/dragonfly.rb +45 -44
- data/lib/dragonfly/app.rb +175 -96
- data/lib/dragonfly/configurable.rb +71 -170
- data/lib/dragonfly/content.rb +211 -0
- data/lib/dragonfly/core_ext/object.rb +1 -6
- data/lib/dragonfly/file_data_store.rb +197 -0
- data/lib/dragonfly/image_magick/analysers/image_properties.rb +23 -0
- data/lib/dragonfly/image_magick/generators/convert.rb +19 -0
- data/lib/dragonfly/image_magick/generators/plain.rb +26 -0
- data/lib/dragonfly/image_magick/generators/plasma.rb +25 -0
- data/lib/dragonfly/image_magick/generators/text.rb +127 -0
- data/lib/dragonfly/image_magick/plugin.rb +83 -0
- data/lib/dragonfly/image_magick/processors/convert.rb +29 -0
- data/lib/dragonfly/image_magick/processors/encode.rb +18 -0
- data/lib/dragonfly/image_magick/processors/thumb.rb +76 -0
- data/lib/dragonfly/job.rb +118 -134
- data/lib/dragonfly/job_endpoint.rb +2 -0
- data/lib/dragonfly/memory_data_store.rb +34 -0
- data/lib/dragonfly/middleware.rb +5 -3
- data/lib/dragonfly/{active_model_extensions.rb → model.rb} +5 -3
- data/lib/dragonfly/{active_model_extensions → model}/attachment.rb +40 -35
- data/lib/dragonfly/{active_model_extensions → model}/attachment_class_methods.rb +36 -40
- data/lib/dragonfly/model/class_methods.rb +109 -0
- data/lib/dragonfly/{active_model_extensions → model}/instance_methods.rb +2 -2
- data/lib/dragonfly/{active_model_extensions → model}/validations.rb +17 -12
- data/lib/dragonfly/railtie.rb +8 -6
- data/lib/dragonfly/register.rb +27 -0
- data/lib/dragonfly/response.rb +47 -52
- data/lib/dragonfly/routed_endpoint.rb +4 -0
- data/lib/dragonfly/serializer.rb +15 -5
- data/lib/dragonfly/server.rb +56 -29
- data/lib/dragonfly/shell.rb +12 -23
- data/lib/dragonfly/spec/data_store_examples.rb +64 -0
- data/lib/dragonfly/temp_object.rb +32 -47
- data/lib/dragonfly/url_attributes.rb +19 -22
- data/lib/dragonfly/url_mapper.rb +3 -0
- data/lib/dragonfly/utils.rb +12 -0
- data/lib/dragonfly/version.rb +1 -1
- data/lib/dragonfly/whitelist.rb +19 -0
- data/lib/rails/generators/dragonfly/USAGE +8 -0
- data/lib/rails/generators/dragonfly/dragonfly_generator.rb +24 -0
- data/lib/rails/generators/dragonfly/templates/initializer.rb.erb +27 -0
- data/samples/gif.gif +0 -0
- data/spec/dragonfly/app_spec.rb +270 -64
- data/spec/dragonfly/configurable_spec.rb +142 -418
- data/spec/dragonfly/content_spec.rb +353 -0
- data/spec/dragonfly/cookie_monster_spec.rb +2 -1
- data/spec/dragonfly/file_data_store_spec.rb +301 -0
- data/spec/dragonfly/image_magick/analysers/image_properties_spec.rb +20 -0
- data/spec/dragonfly/image_magick/generators/convert_spec.rb +19 -0
- data/spec/dragonfly/image_magick/generators/plain_spec.rb +50 -0
- data/spec/dragonfly/image_magick/generators/plasma_spec.rb +32 -0
- data/spec/dragonfly/image_magick/generators/text_spec.rb +77 -0
- data/spec/dragonfly/image_magick/plugin_spec.rb +131 -0
- data/spec/dragonfly/image_magick/processors/convert_spec.rb +56 -0
- data/spec/dragonfly/image_magick/processors/thumb_spec.rb +173 -0
- data/spec/dragonfly/job_endpoint_spec.rb +30 -73
- data/spec/dragonfly/job_spec.rb +280 -608
- data/spec/dragonfly/memory_data_store_spec.rb +20 -0
- data/spec/dragonfly/middleware_spec.rb +47 -27
- data/spec/dragonfly/{active_model_extensions → model}/model_spec.rb +331 -555
- data/spec/dragonfly/model/validations_spec.rb +196 -0
- data/spec/dragonfly/register_spec.rb +35 -0
- data/spec/dragonfly/routed_endpoint_spec.rb +6 -6
- data/spec/dragonfly/serializer_spec.rb +13 -15
- data/spec/dragonfly/server_spec.rb +122 -46
- data/spec/dragonfly/shell_spec.rb +43 -24
- data/spec/dragonfly/temp_object_spec.rb +69 -94
- data/spec/dragonfly/url_attributes_spec.rb +49 -0
- data/spec/dragonfly/utils_spec.rb +32 -0
- data/spec/dragonfly/whitelist_spec.rb +30 -0
- data/spec/dragonfly_spec.rb +43 -0
- data/spec/fixtures/deprecated_stored_content/eggs.bonus +1 -0
- data/spec/fixtures/deprecated_stored_content/eggs.bonus.meta +1 -0
- data/spec/functional/configuration_spec.rb +19 -0
- data/spec/functional/model_urls_spec.rb +43 -41
- data/spec/functional/remote_on_the_fly_spec.rb +14 -16
- data/spec/functional/shell_commands_spec.rb +24 -14
- data/spec/functional/to_response_spec.rb +10 -10
- data/spec/functional/urls_spec.rb +5 -3
- data/spec/spec_helper.rb +23 -28
- data/spec/support/argument_matchers.rb +7 -8
- data/spec/support/image_matchers.rb +14 -36
- data/spec/support/model_helpers.rb +97 -0
- data/spec/support/simple_matchers.rb +12 -0
- metadata +92 -393
- data/.yardopts +0 -29
- data/Rakefile +0 -36
- data/config.ru +0 -14
- data/docs.watchr +0 -1
- data/extra_docs/Analysers.md +0 -68
- data/extra_docs/Caching.md +0 -23
- data/extra_docs/Configuration.md +0 -149
- data/extra_docs/Couch.md +0 -49
- data/extra_docs/DataStorage.md +0 -226
- data/extra_docs/Encoding.md +0 -67
- data/extra_docs/ExampleUseCases.md +0 -116
- data/extra_docs/GeneralUsage.md +0 -105
- data/extra_docs/Generators.md +0 -68
- data/extra_docs/Heroku.md +0 -50
- data/extra_docs/ImageMagick.md +0 -136
- data/extra_docs/Index.md +0 -33
- data/extra_docs/MimeTypes.md +0 -40
- data/extra_docs/Models.md +0 -441
- data/extra_docs/Mongo.md +0 -42
- data/extra_docs/Processing.md +0 -77
- data/extra_docs/Rack.md +0 -52
- data/extra_docs/Rails2.md +0 -57
- data/extra_docs/Rails3.md +0 -56
- data/extra_docs/ServingRemotely.md +0 -104
- data/extra_docs/Sinatra.md +0 -25
- data/extra_docs/URLs.md +0 -203
- data/features/images.feature +0 -47
- data/features/no_processing.feature +0 -14
- data/features/rails.feature +0 -8
- data/features/steps/common_steps.rb +0 -8
- data/features/steps/dragonfly_steps.rb +0 -66
- data/features/steps/rails_steps.rb +0 -40
- data/features/support/env.rb +0 -13
- data/features/support/setup.rb +0 -41
- data/fixtures/rails/files/app/models/album.rb +0 -6
- data/fixtures/rails/files/app/views/albums/new.html.erb +0 -7
- data/fixtures/rails/files/app/views/albums/show.html.erb +0 -6
- data/fixtures/rails/files/config/initializers/dragonfly.rb +0 -4
- data/fixtures/rails/files/features/manage_album_images.feature +0 -38
- data/fixtures/rails/files/features/step_definitions/helper_steps.rb +0 -7
- data/fixtures/rails/files/features/step_definitions/image_steps.rb +0 -25
- data/fixtures/rails/files/features/step_definitions/web_steps.rb +0 -189
- data/fixtures/rails/files/features/support/paths.rb +0 -17
- data/fixtures/rails/files/features/text_images.feature +0 -7
- data/fixtures/rails/template.rb +0 -20
- data/irbrc.rb +0 -19
- data/lib/dragonfly/active_model_extensions/class_methods.rb +0 -98
- data/lib/dragonfly/analyser.rb +0 -58
- data/lib/dragonfly/analysis/file_command_analyser.rb +0 -33
- data/lib/dragonfly/analysis/image_magick_analyser.rb +0 -6
- data/lib/dragonfly/config/heroku.rb +0 -26
- data/lib/dragonfly/config/image_magick.rb +0 -6
- data/lib/dragonfly/config/rails.rb +0 -20
- data/lib/dragonfly/data_storage.rb +0 -11
- data/lib/dragonfly/data_storage/couch_data_store.rb +0 -83
- data/lib/dragonfly/data_storage/file_data_store.rb +0 -144
- data/lib/dragonfly/data_storage/mongo_data_store.rb +0 -96
- data/lib/dragonfly/data_storage/s3data_store.rb +0 -168
- data/lib/dragonfly/encoder.rb +0 -13
- data/lib/dragonfly/encoding/image_magick_encoder.rb +0 -6
- data/lib/dragonfly/function_manager.rb +0 -67
- data/lib/dragonfly/generation/image_magick_generator.rb +0 -6
- data/lib/dragonfly/generator.rb +0 -9
- data/lib/dragonfly/image_magick/analyser.rb +0 -53
- data/lib/dragonfly/image_magick/config.rb +0 -44
- data/lib/dragonfly/image_magick/encoder.rb +0 -57
- data/lib/dragonfly/image_magick/generator.rb +0 -147
- data/lib/dragonfly/image_magick/processor.rb +0 -114
- data/lib/dragonfly/image_magick/utils.rb +0 -46
- data/lib/dragonfly/image_magick_utils.rb +0 -4
- data/lib/dragonfly/job_builder.rb +0 -39
- data/lib/dragonfly/job_definitions.rb +0 -30
- data/lib/dragonfly/loggable.rb +0 -28
- data/lib/dragonfly/processing/image_magick_processor.rb +0 -6
- data/lib/dragonfly/processor.rb +0 -9
- data/lib/dragonfly/rails/images.rb +0 -32
- data/lib/dragonfly/simple_cache.rb +0 -23
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +0 -95
- data/spec/dragonfly/analyser_spec.rb +0 -123
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +0 -49
- data/spec/dragonfly/data_storage/couch_data_store_spec.rb +0 -84
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +0 -308
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +0 -81
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +0 -277
- data/spec/dragonfly/data_storage/shared_data_store_examples.rb +0 -77
- data/spec/dragonfly/function_manager_spec.rb +0 -154
- data/spec/dragonfly/image_magick/analyser_spec.rb +0 -73
- data/spec/dragonfly/image_magick/encoder_spec.rb +0 -46
- data/spec/dragonfly/image_magick/generator_spec.rb +0 -178
- data/spec/dragonfly/image_magick/processor_spec.rb +0 -293
- data/spec/dragonfly/job_builder_spec.rb +0 -37
- data/spec/dragonfly/job_definitions_spec.rb +0 -57
- data/spec/dragonfly/loggable_spec.rb +0 -80
- data/spec/dragonfly/simple_cache_spec.rb +0 -27
- data/spec/dragonfly/url_attributes.rb +0 -47
- data/spec/functional/deprecations_spec.rb +0 -51
- data/spec/functional/image_magick_app_spec.rb +0 -27
- data/spec/test_imagemagick.ru +0 -49
- data/yard/handlers/configurable_attr_handler.rb +0 -38
- data/yard/setup.rb +0 -15
- data/yard/templates/default/fulldoc/html/css/common.css +0 -109
- data/yard/templates/default/layout/html/layout.erb +0 -93
- data/yard/templates/default/module/html/configuration_summary.erb +0 -31
- data/yard/templates/default/module/setup.rb +0 -17
@@ -1,18 +1,23 @@
|
|
1
|
+
require 'active_model/validator'
|
2
|
+
|
1
3
|
module Dragonfly
|
2
|
-
module
|
4
|
+
module Model
|
3
5
|
module Validations
|
4
6
|
|
5
7
|
class PropertyValidator < ActiveModel::EachValidator
|
6
|
-
|
8
|
+
|
7
9
|
def validate_each(model, attribute, attachment)
|
8
10
|
if attachment
|
9
11
|
property = attachment.send(property_name)
|
10
12
|
model.errors.add(attribute, message(property, model)) unless matches?(property)
|
11
13
|
end
|
14
|
+
rescue RuntimeError => e
|
15
|
+
Dragonfly.warn("validation of property #{property_name} of #{attribute} failed with error #{e}")
|
16
|
+
model.errors.add(attribute, message(nil, model))
|
12
17
|
end
|
13
|
-
|
18
|
+
|
14
19
|
private
|
15
|
-
|
20
|
+
|
16
21
|
def matches?(property)
|
17
22
|
if case_insensitive?
|
18
23
|
prop = property.to_s.downcase
|
@@ -21,7 +26,7 @@ module Dragonfly
|
|
21
26
|
allowed_values.include?(property)
|
22
27
|
end
|
23
28
|
end
|
24
|
-
|
29
|
+
|
25
30
|
def message(property, model)
|
26
31
|
message = options[:message] ||
|
27
32
|
"#{property_name.to_s.humanize.downcase} is incorrect. " +
|
@@ -29,23 +34,23 @@ module Dragonfly
|
|
29
34
|
(property ? ", but was '#{property}'" : "")
|
30
35
|
message.respond_to?(:call) ? message.call(property, model) : message
|
31
36
|
end
|
32
|
-
|
37
|
+
|
33
38
|
def check_validity!
|
34
39
|
raise ArgumentError, "you must provide either :in => [<value1>, <value2>..] or :as => <value>" unless options[:in] || options[:as]
|
35
40
|
end
|
36
|
-
|
41
|
+
|
37
42
|
def property_name
|
38
43
|
options[:property_name]
|
39
44
|
end
|
40
|
-
|
45
|
+
|
41
46
|
def case_insensitive?
|
42
47
|
options[:case_sensitive] == false
|
43
48
|
end
|
44
|
-
|
49
|
+
|
45
50
|
def allowed_values
|
46
51
|
@allowed_values ||= options[:in] || [options[:as]]
|
47
52
|
end
|
48
|
-
|
53
|
+
|
49
54
|
def expected_values_string
|
50
55
|
if allowed_values.is_a?(Range)
|
51
56
|
"between #{allowed_values.first} and #{allowed_values.last}"
|
@@ -53,7 +58,7 @@ module Dragonfly
|
|
53
58
|
allowed_values.length > 1 ? "one of '#{allowed_values.join('\', \'')}'" : "'#{allowed_values.first.to_s}'"
|
54
59
|
end
|
55
60
|
end
|
56
|
-
|
61
|
+
|
57
62
|
end
|
58
63
|
|
59
64
|
private
|
@@ -65,4 +70,4 @@ module Dragonfly
|
|
65
70
|
|
66
71
|
end
|
67
72
|
end
|
68
|
-
end
|
73
|
+
end
|
data/lib/dragonfly/railtie.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
require 'dragonfly'
|
2
|
-
require 'rails'
|
1
|
+
require 'dragonfly/cookie_monster'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
if defined?(Rails::Railtie)
|
4
|
+
module Dragonfly
|
5
|
+
class Railtie < ::Rails::Railtie
|
6
|
+
initializer "dragonfly.railtie.initializer" do |app|
|
7
|
+
app.middleware.insert 3, Dragonfly::CookieMonster
|
8
|
+
end
|
8
9
|
end
|
9
10
|
end
|
10
11
|
end
|
12
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Dragonfly
|
2
|
+
class Register
|
3
|
+
|
4
|
+
# Exceptions
|
5
|
+
class NotFound < RuntimeError; end
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@items = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :items
|
12
|
+
|
13
|
+
def add(name, item=nil, &block)
|
14
|
+
items[name.to_sym] = item || block || raise(ArgumentError, "you must give either an argument or a block")
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(name)
|
18
|
+
items[name.to_sym] || raise(NotFound, "#{name.inspect} not registered")
|
19
|
+
end
|
20
|
+
|
21
|
+
def names
|
22
|
+
items.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
data/lib/dragonfly/response.rb
CHANGED
@@ -1,34 +1,38 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'rack'
|
2
3
|
|
3
4
|
module Dragonfly
|
4
5
|
class Response
|
5
6
|
|
6
|
-
DEFAULT_FILENAME = proc do |job, request|
|
7
|
-
[job.basename, job.format].compact.join('.') if job.basename
|
8
|
-
end
|
9
|
-
|
10
7
|
def initialize(job, env)
|
11
8
|
@job, @env = job, env
|
12
9
|
@app = @job.app
|
13
10
|
end
|
14
11
|
|
15
12
|
def to_response
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
13
|
+
response = begin
|
14
|
+
if !(request.head? || request.get?)
|
15
|
+
[405, method_not_allowed_headers, ["method not allowed"]]
|
16
|
+
elsif etag_matches?
|
17
|
+
[304, cache_headers, []]
|
18
|
+
else
|
19
|
+
job.apply
|
20
|
+
env['dragonfly.job'] = job
|
21
|
+
[
|
22
|
+
200,
|
23
|
+
success_headers,
|
24
|
+
(request.head? ? [] : job)
|
25
|
+
]
|
26
|
+
end
|
27
|
+
rescue Job::Fetch::NotFound => e
|
28
|
+
Dragonfly.warn(e.message)
|
29
|
+
[404, {"Content-Type" => "text/plain"}, ["Not found"]]
|
30
|
+
rescue RuntimeError => e
|
31
|
+
Dragonfly.warn("caught error - #{e.message}")
|
32
|
+
[500, {"Content-Type" => "text/plain"}, ["Internal Server Error"]]
|
28
33
|
end
|
29
|
-
|
30
|
-
|
31
|
-
[404, {"Content-Type" => 'text/plain'}, ['Not found']]
|
34
|
+
log_response(response)
|
35
|
+
response
|
32
36
|
end
|
33
37
|
|
34
38
|
def will_be_served?
|
@@ -43,11 +47,9 @@ module Dragonfly
|
|
43
47
|
@request ||= Rack::Request.new(env)
|
44
48
|
end
|
45
49
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
"ETag" => %("#{job.unique_signature}")
|
50
|
-
}
|
50
|
+
def log_response(response)
|
51
|
+
r = request
|
52
|
+
Dragonfly.info [r.request_method, r.fullpath, response[0]].join(' ')
|
51
53
|
end
|
52
54
|
|
53
55
|
def etag_matches?
|
@@ -55,28 +57,12 @@ module Dragonfly
|
|
55
57
|
if_none_match = env['HTTP_IF_NONE_MATCH']
|
56
58
|
@etag_matches = if if_none_match
|
57
59
|
if_none_match.tr!('"','')
|
58
|
-
if_none_match.split(',').include?(job.
|
60
|
+
if_none_match.split(',').include?(job.signature) || if_none_match == '*'
|
59
61
|
else
|
60
62
|
false
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
def success_headers
|
65
|
-
{
|
66
|
-
"Content-Type" => job.mime_type,
|
67
|
-
"Content-Length" => job.size.to_s
|
68
|
-
}.merge(content_disposition_header).
|
69
|
-
merge(cache_headers).
|
70
|
-
merge(custom_headers)
|
71
|
-
end
|
72
|
-
|
73
|
-
def content_disposition_header
|
74
|
-
parts = []
|
75
|
-
parts << content_disposition if content_disposition
|
76
|
-
parts << %(filename="#{URI.encode(filename)}") if filename
|
77
|
-
parts.any? ? {"Content-Disposition" => parts.join('; ')} : {}
|
78
|
-
end
|
79
|
-
|
80
66
|
def method_not_allowed_headers
|
81
67
|
{
|
82
68
|
'Content-Type' => 'text/plain',
|
@@ -84,24 +70,33 @@ module Dragonfly
|
|
84
70
|
}
|
85
71
|
end
|
86
72
|
|
87
|
-
def
|
88
|
-
|
73
|
+
def success_headers
|
74
|
+
headers = standard_headers.merge(cache_headers)
|
75
|
+
customize_headers(headers)
|
76
|
+
headers.delete_if{|k, v| v.nil? }
|
89
77
|
end
|
90
78
|
|
91
|
-
def
|
92
|
-
|
79
|
+
def standard_headers
|
80
|
+
{
|
81
|
+
"Content-Type" => job.mime_type,
|
82
|
+
"Content-Length" => job.size.to_s,
|
83
|
+
"Content-Disposition" => (%(filename="#{URI.encode(job.name)}") if job.name)
|
84
|
+
}
|
93
85
|
end
|
94
86
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
87
|
+
def cache_headers
|
88
|
+
{
|
89
|
+
"Cache-Control" => "public, max-age=31536000", # (1 year)
|
90
|
+
"ETag" => %("#{job.signature}")
|
91
|
+
}
|
100
92
|
end
|
101
93
|
|
102
|
-
def
|
103
|
-
|
94
|
+
def customize_headers(headers)
|
95
|
+
app.response_headers.each do |k, v|
|
96
|
+
headers[k] = v.respond_to?(:call) ? v.call(job, request, headers) : v
|
97
|
+
end
|
104
98
|
end
|
105
99
|
|
106
100
|
end
|
107
101
|
end
|
102
|
+
|
data/lib/dragonfly/serializer.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'base64'
|
3
3
|
require 'multi_json'
|
4
|
+
require 'dragonfly/utils'
|
4
5
|
|
5
6
|
module Dragonfly
|
6
7
|
module Serializer
|
@@ -21,11 +22,11 @@ module Dragonfly
|
|
21
22
|
Base64.decode64(string + '=' * padding_length)
|
22
23
|
end
|
23
24
|
|
24
|
-
def
|
25
|
+
def marshal_b64_encode(object)
|
25
26
|
b64_encode(Marshal.dump(object))
|
26
27
|
end
|
27
28
|
|
28
|
-
def
|
29
|
+
def marshal_b64_decode(string, opts={})
|
29
30
|
marshal_string = b64_decode(string)
|
30
31
|
raise MaliciousString, "potentially malicious marshal string #{marshal_string.inspect}" if opts[:check_malicious] && marshal_string[/@[a-z_]/i]
|
31
32
|
Marshal.load(marshal_string)
|
@@ -34,14 +35,23 @@ module Dragonfly
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def json_encode(object)
|
37
|
-
|
38
|
+
MultiJson.encode(object)
|
38
39
|
end
|
39
40
|
|
40
|
-
def json_decode(string
|
41
|
-
|
41
|
+
def json_decode(string)
|
42
|
+
raise BadString, "can't decode blank string" if Utils.blank?(string)
|
43
|
+
MultiJson.decode(string)
|
42
44
|
rescue MultiJson::DecodeError => e
|
43
45
|
raise BadString, "couldn't decode #{string} - got #{e}"
|
44
46
|
end
|
45
47
|
|
48
|
+
def json_b64_encode(object)
|
49
|
+
b64_encode(json_encode(object))
|
50
|
+
end
|
51
|
+
|
52
|
+
def json_b64_decode(string)
|
53
|
+
json_decode(b64_decode(string))
|
54
|
+
end
|
55
|
+
|
46
56
|
end
|
47
57
|
end
|
data/lib/dragonfly/server.rb
CHANGED
@@ -1,32 +1,51 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'dragonfly/whitelist'
|
3
|
+
require 'dragonfly/url_mapper'
|
4
|
+
require 'dragonfly/job'
|
5
|
+
require 'dragonfly/response'
|
6
|
+
require 'dragonfly/serializer'
|
7
|
+
|
1
8
|
module Dragonfly
|
2
9
|
class Server
|
3
10
|
|
4
11
|
# Exceptions
|
5
12
|
class JobNotAllowed < RuntimeError; end
|
6
13
|
|
7
|
-
include Loggable
|
8
|
-
include Configurable
|
9
|
-
|
10
|
-
configurable_attr :allow_fetch_file, false
|
11
|
-
configurable_attr :allow_fetch_url, false
|
12
|
-
configurable_attr :dragonfly_url, '/dragonfly'
|
13
|
-
configurable_attr :protect_from_dos_attacks, false
|
14
|
-
configurable_attr :url_format, '/:job/:basename.:format'
|
15
|
-
configurable_attr :url_host
|
16
|
-
|
17
14
|
extend Forwardable
|
18
15
|
def_delegator :url_mapper, :params_in_url
|
19
16
|
|
20
17
|
def initialize(app)
|
21
18
|
@app = app
|
22
|
-
|
23
|
-
|
19
|
+
@dragonfly_url = '/dragonfly'
|
20
|
+
self.url_format = '/:job/:name'
|
21
|
+
@fetch_file_whitelist = Whitelist.new
|
22
|
+
@fetch_url_whitelist = Whitelist.new
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_accessor :protect_from_dos_attacks, :url_host, :url_path_prefix, :dragonfly_url
|
26
|
+
|
27
|
+
attr_reader :url_format, :fetch_file_whitelist, :fetch_url_whitelist
|
28
|
+
|
29
|
+
def add_to_fetch_file_whitelist(patterns)
|
30
|
+
fetch_file_whitelist.push *patterns
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_to_fetch_url_whitelist(patterns)
|
34
|
+
fetch_url_whitelist.push *patterns
|
35
|
+
end
|
36
|
+
|
37
|
+
def url_format=(url_format)
|
38
|
+
@url_format = url_format
|
39
|
+
self.url_mapper = UrlMapper.new(url_format,
|
40
|
+
:basename => '[^\/]',
|
41
|
+
:name => '[^\/]',
|
42
|
+
:format => '[^\.]'
|
43
|
+
)
|
24
44
|
end
|
25
45
|
|
26
46
|
def before_serve(&block)
|
27
47
|
self.before_serve_callback = block
|
28
48
|
end
|
29
|
-
configuration_method :before_serve
|
30
49
|
|
31
50
|
def call(env)
|
32
51
|
if dragonfly_url == env["PATH_INFO"]
|
@@ -50,35 +69,29 @@ module Dragonfly
|
|
50
69
|
rescue Job::IncorrectSHA => e
|
51
70
|
[400, {"Content-Type" => 'text/plain'}, ["The SHA parameter you gave (#{e}) is incorrect"]]
|
52
71
|
rescue JobNotAllowed => e
|
53
|
-
|
72
|
+
Dragonfly.warn(e.message)
|
54
73
|
[403, {"Content-Type" => 'text/plain'}, ["Forbidden"]]
|
55
74
|
rescue Serializer::BadString, Serializer::MaliciousString, Job::InvalidArray => e
|
56
|
-
|
75
|
+
Dragonfly.warn(e.message)
|
57
76
|
[404, {'Content-Type' => 'text/plain'}, ['Not found']]
|
58
77
|
end
|
59
78
|
|
60
79
|
def url_for(job, opts={})
|
61
80
|
opts = opts.dup
|
62
81
|
host = opts.delete(:host) || url_host
|
63
|
-
|
82
|
+
path_prefix = opts.delete(:path_prefix) || url_path_prefix
|
83
|
+
params = job.url_attributes.extract(url_mapper.params_in_url)
|
84
|
+
params.merge!(stringify_keys(opts))
|
64
85
|
params['job'] = job.serialize
|
65
86
|
params['sha'] = job.sha if protect_from_dos_attacks
|
66
87
|
url = url_mapper.url_for(params)
|
67
|
-
"#{host}#{url}"
|
88
|
+
"#{host}#{path_prefix}#{url}"
|
68
89
|
end
|
69
90
|
|
70
91
|
private
|
71
92
|
|
72
93
|
attr_reader :app
|
73
|
-
attr_accessor :before_serve_callback
|
74
|
-
|
75
|
-
def url_mapper
|
76
|
-
@url_mapper ||= UrlMapper.new(url_format,
|
77
|
-
:basename => '[^\/]',
|
78
|
-
:name => '[^\/]',
|
79
|
-
:format => '[^\.]'
|
80
|
-
)
|
81
|
-
end
|
94
|
+
attr_accessor :before_serve_callback, :url_mapper
|
82
95
|
|
83
96
|
def stringify_keys(params)
|
84
97
|
params.inject({}) do |hash, (k, v)|
|
@@ -109,11 +122,25 @@ module Dragonfly
|
|
109
122
|
end
|
110
123
|
|
111
124
|
def validate_job!(job)
|
112
|
-
if job.fetch_file_step
|
113
|
-
|
114
|
-
|
125
|
+
if step = job.fetch_file_step
|
126
|
+
validate_fetch_file_step!(step)
|
127
|
+
end
|
128
|
+
if step = job.fetch_url_step
|
129
|
+
validate_fetch_url_step!(step)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def validate_fetch_file_step!(step)
|
134
|
+
unless fetch_file_whitelist.include?(step.path)
|
135
|
+
raise JobNotAllowed, "fetch file #{step.path} disallowed - use fetch_file_whitelist to allow it"
|
115
136
|
end
|
116
137
|
end
|
117
138
|
|
139
|
+
def validate_fetch_url_step!(step)
|
140
|
+
unless fetch_url_whitelist.include?(step.url)
|
141
|
+
raise JobNotAllowed, "fetch url #{step.url} disallowed - use fetch_url_whitelist to allow it"
|
142
|
+
end
|
143
|
+
end
|
118
144
|
end
|
119
145
|
end
|
146
|
+
|