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.

Files changed (203) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -8
  3. data/.travis.yml +11 -0
  4. data/Gemfile +1 -0
  5. data/History.md +52 -2
  6. data/LICENSE +1 -1
  7. data/README.md +38 -95
  8. data/dev/grid.jpg +0 -0
  9. data/dev/irbrc.rb +27 -0
  10. data/dev/rails_template.rb +38 -0
  11. data/dev/test.ru +56 -0
  12. data/dev/test_rails +19 -0
  13. data/dragonfly.gemspec +3 -21
  14. data/lib/dragonfly.rb +45 -44
  15. data/lib/dragonfly/app.rb +175 -96
  16. data/lib/dragonfly/configurable.rb +71 -170
  17. data/lib/dragonfly/content.rb +211 -0
  18. data/lib/dragonfly/core_ext/object.rb +1 -6
  19. data/lib/dragonfly/file_data_store.rb +197 -0
  20. data/lib/dragonfly/image_magick/analysers/image_properties.rb +23 -0
  21. data/lib/dragonfly/image_magick/generators/convert.rb +19 -0
  22. data/lib/dragonfly/image_magick/generators/plain.rb +26 -0
  23. data/lib/dragonfly/image_magick/generators/plasma.rb +25 -0
  24. data/lib/dragonfly/image_magick/generators/text.rb +127 -0
  25. data/lib/dragonfly/image_magick/plugin.rb +83 -0
  26. data/lib/dragonfly/image_magick/processors/convert.rb +29 -0
  27. data/lib/dragonfly/image_magick/processors/encode.rb +18 -0
  28. data/lib/dragonfly/image_magick/processors/thumb.rb +76 -0
  29. data/lib/dragonfly/job.rb +118 -134
  30. data/lib/dragonfly/job_endpoint.rb +2 -0
  31. data/lib/dragonfly/memory_data_store.rb +34 -0
  32. data/lib/dragonfly/middleware.rb +5 -3
  33. data/lib/dragonfly/{active_model_extensions.rb → model.rb} +5 -3
  34. data/lib/dragonfly/{active_model_extensions → model}/attachment.rb +40 -35
  35. data/lib/dragonfly/{active_model_extensions → model}/attachment_class_methods.rb +36 -40
  36. data/lib/dragonfly/model/class_methods.rb +109 -0
  37. data/lib/dragonfly/{active_model_extensions → model}/instance_methods.rb +2 -2
  38. data/lib/dragonfly/{active_model_extensions → model}/validations.rb +17 -12
  39. data/lib/dragonfly/railtie.rb +8 -6
  40. data/lib/dragonfly/register.rb +27 -0
  41. data/lib/dragonfly/response.rb +47 -52
  42. data/lib/dragonfly/routed_endpoint.rb +4 -0
  43. data/lib/dragonfly/serializer.rb +15 -5
  44. data/lib/dragonfly/server.rb +56 -29
  45. data/lib/dragonfly/shell.rb +12 -23
  46. data/lib/dragonfly/spec/data_store_examples.rb +64 -0
  47. data/lib/dragonfly/temp_object.rb +32 -47
  48. data/lib/dragonfly/url_attributes.rb +19 -22
  49. data/lib/dragonfly/url_mapper.rb +3 -0
  50. data/lib/dragonfly/utils.rb +12 -0
  51. data/lib/dragonfly/version.rb +1 -1
  52. data/lib/dragonfly/whitelist.rb +19 -0
  53. data/lib/rails/generators/dragonfly/USAGE +8 -0
  54. data/lib/rails/generators/dragonfly/dragonfly_generator.rb +24 -0
  55. data/lib/rails/generators/dragonfly/templates/initializer.rb.erb +27 -0
  56. data/samples/gif.gif +0 -0
  57. data/spec/dragonfly/app_spec.rb +270 -64
  58. data/spec/dragonfly/configurable_spec.rb +142 -418
  59. data/spec/dragonfly/content_spec.rb +353 -0
  60. data/spec/dragonfly/cookie_monster_spec.rb +2 -1
  61. data/spec/dragonfly/file_data_store_spec.rb +301 -0
  62. data/spec/dragonfly/image_magick/analysers/image_properties_spec.rb +20 -0
  63. data/spec/dragonfly/image_magick/generators/convert_spec.rb +19 -0
  64. data/spec/dragonfly/image_magick/generators/plain_spec.rb +50 -0
  65. data/spec/dragonfly/image_magick/generators/plasma_spec.rb +32 -0
  66. data/spec/dragonfly/image_magick/generators/text_spec.rb +77 -0
  67. data/spec/dragonfly/image_magick/plugin_spec.rb +131 -0
  68. data/spec/dragonfly/image_magick/processors/convert_spec.rb +56 -0
  69. data/spec/dragonfly/image_magick/processors/thumb_spec.rb +173 -0
  70. data/spec/dragonfly/job_endpoint_spec.rb +30 -73
  71. data/spec/dragonfly/job_spec.rb +280 -608
  72. data/spec/dragonfly/memory_data_store_spec.rb +20 -0
  73. data/spec/dragonfly/middleware_spec.rb +47 -27
  74. data/spec/dragonfly/{active_model_extensions → model}/model_spec.rb +331 -555
  75. data/spec/dragonfly/model/validations_spec.rb +196 -0
  76. data/spec/dragonfly/register_spec.rb +35 -0
  77. data/spec/dragonfly/routed_endpoint_spec.rb +6 -6
  78. data/spec/dragonfly/serializer_spec.rb +13 -15
  79. data/spec/dragonfly/server_spec.rb +122 -46
  80. data/spec/dragonfly/shell_spec.rb +43 -24
  81. data/spec/dragonfly/temp_object_spec.rb +69 -94
  82. data/spec/dragonfly/url_attributes_spec.rb +49 -0
  83. data/spec/dragonfly/utils_spec.rb +32 -0
  84. data/spec/dragonfly/whitelist_spec.rb +30 -0
  85. data/spec/dragonfly_spec.rb +43 -0
  86. data/spec/fixtures/deprecated_stored_content/eggs.bonus +1 -0
  87. data/spec/fixtures/deprecated_stored_content/eggs.bonus.meta +1 -0
  88. data/spec/functional/configuration_spec.rb +19 -0
  89. data/spec/functional/model_urls_spec.rb +43 -41
  90. data/spec/functional/remote_on_the_fly_spec.rb +14 -16
  91. data/spec/functional/shell_commands_spec.rb +24 -14
  92. data/spec/functional/to_response_spec.rb +10 -10
  93. data/spec/functional/urls_spec.rb +5 -3
  94. data/spec/spec_helper.rb +23 -28
  95. data/spec/support/argument_matchers.rb +7 -8
  96. data/spec/support/image_matchers.rb +14 -36
  97. data/spec/support/model_helpers.rb +97 -0
  98. data/spec/support/simple_matchers.rb +12 -0
  99. metadata +92 -393
  100. data/.yardopts +0 -29
  101. data/Rakefile +0 -36
  102. data/config.ru +0 -14
  103. data/docs.watchr +0 -1
  104. data/extra_docs/Analysers.md +0 -68
  105. data/extra_docs/Caching.md +0 -23
  106. data/extra_docs/Configuration.md +0 -149
  107. data/extra_docs/Couch.md +0 -49
  108. data/extra_docs/DataStorage.md +0 -226
  109. data/extra_docs/Encoding.md +0 -67
  110. data/extra_docs/ExampleUseCases.md +0 -116
  111. data/extra_docs/GeneralUsage.md +0 -105
  112. data/extra_docs/Generators.md +0 -68
  113. data/extra_docs/Heroku.md +0 -50
  114. data/extra_docs/ImageMagick.md +0 -136
  115. data/extra_docs/Index.md +0 -33
  116. data/extra_docs/MimeTypes.md +0 -40
  117. data/extra_docs/Models.md +0 -441
  118. data/extra_docs/Mongo.md +0 -42
  119. data/extra_docs/Processing.md +0 -77
  120. data/extra_docs/Rack.md +0 -52
  121. data/extra_docs/Rails2.md +0 -57
  122. data/extra_docs/Rails3.md +0 -56
  123. data/extra_docs/ServingRemotely.md +0 -104
  124. data/extra_docs/Sinatra.md +0 -25
  125. data/extra_docs/URLs.md +0 -203
  126. data/features/images.feature +0 -47
  127. data/features/no_processing.feature +0 -14
  128. data/features/rails.feature +0 -8
  129. data/features/steps/common_steps.rb +0 -8
  130. data/features/steps/dragonfly_steps.rb +0 -66
  131. data/features/steps/rails_steps.rb +0 -40
  132. data/features/support/env.rb +0 -13
  133. data/features/support/setup.rb +0 -41
  134. data/fixtures/rails/files/app/models/album.rb +0 -6
  135. data/fixtures/rails/files/app/views/albums/new.html.erb +0 -7
  136. data/fixtures/rails/files/app/views/albums/show.html.erb +0 -6
  137. data/fixtures/rails/files/config/initializers/dragonfly.rb +0 -4
  138. data/fixtures/rails/files/features/manage_album_images.feature +0 -38
  139. data/fixtures/rails/files/features/step_definitions/helper_steps.rb +0 -7
  140. data/fixtures/rails/files/features/step_definitions/image_steps.rb +0 -25
  141. data/fixtures/rails/files/features/step_definitions/web_steps.rb +0 -189
  142. data/fixtures/rails/files/features/support/paths.rb +0 -17
  143. data/fixtures/rails/files/features/text_images.feature +0 -7
  144. data/fixtures/rails/template.rb +0 -20
  145. data/irbrc.rb +0 -19
  146. data/lib/dragonfly/active_model_extensions/class_methods.rb +0 -98
  147. data/lib/dragonfly/analyser.rb +0 -58
  148. data/lib/dragonfly/analysis/file_command_analyser.rb +0 -33
  149. data/lib/dragonfly/analysis/image_magick_analyser.rb +0 -6
  150. data/lib/dragonfly/config/heroku.rb +0 -26
  151. data/lib/dragonfly/config/image_magick.rb +0 -6
  152. data/lib/dragonfly/config/rails.rb +0 -20
  153. data/lib/dragonfly/data_storage.rb +0 -11
  154. data/lib/dragonfly/data_storage/couch_data_store.rb +0 -83
  155. data/lib/dragonfly/data_storage/file_data_store.rb +0 -144
  156. data/lib/dragonfly/data_storage/mongo_data_store.rb +0 -96
  157. data/lib/dragonfly/data_storage/s3data_store.rb +0 -168
  158. data/lib/dragonfly/encoder.rb +0 -13
  159. data/lib/dragonfly/encoding/image_magick_encoder.rb +0 -6
  160. data/lib/dragonfly/function_manager.rb +0 -67
  161. data/lib/dragonfly/generation/image_magick_generator.rb +0 -6
  162. data/lib/dragonfly/generator.rb +0 -9
  163. data/lib/dragonfly/image_magick/analyser.rb +0 -53
  164. data/lib/dragonfly/image_magick/config.rb +0 -44
  165. data/lib/dragonfly/image_magick/encoder.rb +0 -57
  166. data/lib/dragonfly/image_magick/generator.rb +0 -147
  167. data/lib/dragonfly/image_magick/processor.rb +0 -114
  168. data/lib/dragonfly/image_magick/utils.rb +0 -46
  169. data/lib/dragonfly/image_magick_utils.rb +0 -4
  170. data/lib/dragonfly/job_builder.rb +0 -39
  171. data/lib/dragonfly/job_definitions.rb +0 -30
  172. data/lib/dragonfly/loggable.rb +0 -28
  173. data/lib/dragonfly/processing/image_magick_processor.rb +0 -6
  174. data/lib/dragonfly/processor.rb +0 -9
  175. data/lib/dragonfly/rails/images.rb +0 -32
  176. data/lib/dragonfly/simple_cache.rb +0 -23
  177. data/spec/dragonfly/active_model_extensions/spec_helper.rb +0 -95
  178. data/spec/dragonfly/analyser_spec.rb +0 -123
  179. data/spec/dragonfly/analysis/file_command_analyser_spec.rb +0 -49
  180. data/spec/dragonfly/data_storage/couch_data_store_spec.rb +0 -84
  181. data/spec/dragonfly/data_storage/file_data_store_spec.rb +0 -308
  182. data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +0 -81
  183. data/spec/dragonfly/data_storage/s3_data_store_spec.rb +0 -277
  184. data/spec/dragonfly/data_storage/shared_data_store_examples.rb +0 -77
  185. data/spec/dragonfly/function_manager_spec.rb +0 -154
  186. data/spec/dragonfly/image_magick/analyser_spec.rb +0 -73
  187. data/spec/dragonfly/image_magick/encoder_spec.rb +0 -46
  188. data/spec/dragonfly/image_magick/generator_spec.rb +0 -178
  189. data/spec/dragonfly/image_magick/processor_spec.rb +0 -293
  190. data/spec/dragonfly/job_builder_spec.rb +0 -37
  191. data/spec/dragonfly/job_definitions_spec.rb +0 -57
  192. data/spec/dragonfly/loggable_spec.rb +0 -80
  193. data/spec/dragonfly/simple_cache_spec.rb +0 -27
  194. data/spec/dragonfly/url_attributes.rb +0 -47
  195. data/spec/functional/deprecations_spec.rb +0 -51
  196. data/spec/functional/image_magick_app_spec.rb +0 -27
  197. data/spec/test_imagemagick.ru +0 -49
  198. data/yard/handlers/configurable_attr_handler.rb +0 -38
  199. data/yard/setup.rb +0 -15
  200. data/yard/templates/default/fulldoc/html/css/common.css +0 -109
  201. data/yard/templates/default/layout/html/layout.erb +0 -93
  202. data/yard/templates/default/module/html/configuration_summary.erb +0 -31
  203. data/yard/templates/default/module/setup.rb +0 -17
@@ -1,5 +1,5 @@
1
1
  module Dragonfly
2
- module ActiveModelExtensions
2
+ module Model
3
3
  module InstanceMethods
4
4
 
5
5
  def dragonfly_attachments
@@ -25,4 +25,4 @@ module Dragonfly
25
25
 
26
26
  end
27
27
  end
28
- end
28
+ end
@@ -1,18 +1,23 @@
1
+ require 'active_model/validator'
2
+
1
3
  module Dragonfly
2
- module ActiveModelExtensions
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
@@ -1,10 +1,12 @@
1
- require 'dragonfly'
2
- require 'rails'
1
+ require 'dragonfly/cookie_monster'
3
2
 
4
- module Dragonfly
5
- class Railtie < ::Rails::Railtie
6
- initializer "dragonfly.railtie.initializer" do |app|
7
- app.middleware.insert_before 'ActionDispatch::Cookies', Dragonfly::CookieMonster
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
+
@@ -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
- if !(request.head? || request.get?)
17
- [405, method_not_allowed_headers, ["#{request.request_method} method not allowed"]]
18
- elsif etag_matches?
19
- [304, cache_headers, []]
20
- elsif request.head?
21
- job.apply
22
- env['dragonfly.job'] = job
23
- [200, success_headers, []]
24
- elsif request.get?
25
- job.apply
26
- env['dragonfly.job'] = job
27
- [200, success_headers, job]
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
- rescue DataStorage::DataNotFound, DataStorage::BadUID => e
30
- app.log.warn(e.message)
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 cache_headers
47
- {
48
- "Cache-Control" => "public, max-age=#{app.cache_duration}",
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.unique_signature) || if_none_match == '*'
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 content_disposition
88
- @content_disposition ||= evaluate(app.content_disposition)
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 filename
92
- @filename ||= evaluate(app.content_filename)
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 custom_headers
96
- @custom_headers ||= app.response_headers.inject({}) do |headers, (k, v)|
97
- headers[k] = evaluate(v)
98
- headers
99
- end
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 evaluate(attribute)
103
- attribute.respond_to?(:call) ? attribute.call(job, request) : attribute
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
+
@@ -1,3 +1,7 @@
1
+ require 'rack'
2
+ require 'dragonfly/utils'
3
+ require 'dragonfly/response'
4
+
1
5
  module Dragonfly
2
6
  class RoutedEndpoint
3
7
 
@@ -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 marshal_encode(object)
25
+ def marshal_b64_encode(object)
25
26
  b64_encode(Marshal.dump(object))
26
27
  end
27
28
 
28
- def marshal_decode(string, opts={})
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
- b64_encode(MultiJson.encode(object))
38
+ MultiJson.encode(object)
38
39
  end
39
40
 
40
- def json_decode(string, opts={})
41
- MultiJson.decode(b64_decode(string), :symbolize_keys => opts[:symbolize_keys])
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
@@ -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
- use_same_log_as(app)
23
- use_as_fallback_config(app)
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
- log.warn(e.message)
72
+ Dragonfly.warn(e.message)
54
73
  [403, {"Content-Type" => 'text/plain'}, ["Forbidden"]]
55
74
  rescue Serializer::BadString, Serializer::MaliciousString, Job::InvalidArray => e
56
- log.warn(e.message)
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
- params = stringify_keys(opts)
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 && !allow_fetch_file ||
113
- job.fetch_url_step && !allow_fetch_url
114
- raise JobNotAllowed, "Dragonfly Server doesn't allow requesting job with steps #{job.steps.inspect}"
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
+