magickly 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,5 @@
1
1
  require 'httparty'
2
+ require 'uri'
2
3
 
3
4
  module Dragonfly
4
5
  module DataStorage
@@ -6,13 +7,14 @@ module Dragonfly
6
7
 
7
8
  class RemoteDataStore
8
9
  include Configurable
9
-
10
+ configurable_attr :url_host
11
+
10
12
  def store(temp_object, opts={})
11
13
  raise "Sorry friend, this datastore is read-only."
12
14
  end
13
15
 
14
16
  def retrieve(uid)
15
- response = HTTParty.get uid, :timeout => 3
17
+ response = HTTParty.get URI::join(url_host.to_s, uid).to_s, :timeout => 3
16
18
  unless response.ok?
17
19
  #raise Forbidden if response.code == 403
18
20
  raise DataNotFound
data/lib/magickly/app.rb CHANGED
@@ -6,6 +6,7 @@ module Magickly
6
6
  enable :logging
7
7
  set :root, File.join(File.dirname(__FILE__), '..')
8
8
  set :homepage, "http://github.com/afeld/magickly"
9
+ set :protection, :except => :path_traversal
9
10
 
10
11
  configure :production do
11
12
  require 'newrelic_rpm' if ENV['NEW_RELIC_ID']
@@ -31,25 +32,16 @@ module Magickly
31
32
  process_src_or_display_demo params[:src], @options
32
33
  end
33
34
 
34
- get '/q/*' do
35
- src = nil
36
- opts = ActiveSupport::OrderedHash.new
37
- splat = request.path_info.sub /^\/q\//, ''
38
-
39
- splat.split('/').each_slice(2) do |k, v|
40
- if RESERVED_PARAMS.include? k
41
- if k == 'src'
42
- src = URI.unescape(v)
43
- # slashes come in double-escaped by Apache so we
44
- # need to unescape again
45
- src = URI.unescape(src) if src =~ /%2F/
46
- end
47
- else
48
- opts[k] = URI.unescape(v)
49
- end
50
- end
35
+ get '/q/*' do
36
+ process_path request.path_info.sub /^\/q\//, ''
37
+ end
51
38
 
52
- process_src_or_display_demo src, opts
39
+ get '/qe/*' do
40
+ # TODO use Base64.urlsafe_decode64
41
+ decoded = request.path_info.sub /^\/qe\//, ''
42
+ decoded = decoded.tr("-_", "+/").unpack("m0").first
43
+
44
+ process_path decoded
53
45
  end
54
46
 
55
47
  get '/analyze' do
@@ -78,6 +70,26 @@ module Magickly
78
70
  end
79
71
  end
80
72
 
73
+ def process_path splat
74
+ src = nil
75
+ opts = []
76
+
77
+ splat.split('/').each_slice(2) do |k, v|
78
+ if RESERVED_PARAMS.include? k
79
+ if k == 'src'
80
+ src = URI.unescape(v)
81
+ # slashes come in double-escaped by Apache so we
82
+ # need to unescape again
83
+ src = URI.unescape(src) if src =~ /%2F/
84
+ end
85
+ else
86
+ opts << [k, URI.unescape(v)]
87
+ end
88
+ end
89
+
90
+ process_src_or_display_demo src, opts
91
+ end
92
+
81
93
  def process_src_or_display_demo src, options
82
94
  if src
83
95
  # process image
@@ -0,0 +1,3 @@
1
+ module Magickly
2
+ VERSION = '2.0.0'
3
+ end
@@ -3,11 +3,11 @@ require 'uri'
3
3
 
4
4
  describe Magickly::App do
5
5
  include Rack::Test::Methods
6
-
6
+
7
7
  def app
8
8
  Magickly::App
9
9
  end
10
-
10
+
11
11
  def setup_image(host='http://www.foo.com')
12
12
  @image_filename = 'imagemagick.png'
13
13
  @image_url = "#{host}/#{@image_filename}"
@@ -15,61 +15,70 @@ describe Magickly::App do
15
15
  @image_path = File.join(File.dirname(__FILE__), '..', 'support', @image_filename)
16
16
  stub_request(:get, @image_url).to_return(:body => File.new(@image_path))
17
17
  end
18
-
18
+
19
+ def get_image(uri)
20
+ get(uri)
21
+ file = Tempfile.new('testimage')
22
+ file.write(last_response.body)
23
+ file.rewind
24
+
25
+ file
26
+ end
27
+
19
28
  describe "GET /" do
20
29
  it "should display the demo page for no params" do
21
30
  get '/'
22
- last_response.should be_ok
31
+ last_response.status.should eq(200)
23
32
  # TODO test that it renders the view
24
33
  end
25
-
34
+
26
35
  it "retrieves an image with no options" do
27
36
  setup_image
28
-
37
+
29
38
  get "/?src=#{@image_url}"
30
-
39
+
31
40
  a_request(:get, @image_url).should have_been_made.once
32
- last_response.should be_ok
33
-
41
+ last_response.status.should eq(200)
42
+
34
43
  # check that the returned file is identical to the original
35
44
  compare_binary(last_response.body, IO.read(@image_path))
36
45
  end
37
-
46
+
38
47
  it "should ignore unused params" do
39
48
  setup_image
40
-
49
+
41
50
  get "/?src=#{@image_url}&bad_param=666"
42
-
51
+
43
52
  a_request(:get, @image_url).should have_been_made.once
44
- last_response.should be_ok
45
-
53
+ last_response.status.should eq(200)
54
+
46
55
  # check that the returned file is identical to the original
47
56
  compare_binary(last_response.body, IO.read(@image_path))
48
57
  end
49
-
58
+
50
59
  it "retrieves an image at a relative URI" do
51
60
  setup_image "http://#{Rack::Test::DEFAULT_HOST}"
52
-
61
+
53
62
  get "/?src=/#{@image_filename}"
54
-
63
+
55
64
  a_request(:get, @image_url).should have_been_made.once
56
- last_response.should be_ok
57
-
65
+ last_response.status.should eq(200)
66
+
58
67
  # check that the returned file is identical to the original
59
68
  compare_binary(last_response.body, IO.read(@image_path))
60
69
  end
61
-
70
+
62
71
  it "resizes an image" do
63
72
  setup_image
64
73
  width = 100
65
-
66
- get "/?src=#{@image_url}&resize=#{width}x"
67
-
74
+
75
+ file = get_image "/?src=#{@image_url}&resize=#{width}x"
76
+
68
77
  a_request(:get, @image_url).should have_been_made.once
69
- last_response.should be_ok
70
- ImageSize.new(last_response.body).get_width.should eq width
78
+ last_response.status.should eq(200)
79
+ FastImage.size(file)[0].should eq(width)
71
80
  end
72
-
81
+
73
82
  it "should use my Dragonfly shortcut with no arguments" do
74
83
  setup_image
75
84
  width = 100
@@ -79,13 +88,13 @@ describe Magickly::App do
79
88
  process :convert, "-filter Gaussian -resize #{width}x"
80
89
  end
81
90
  end
82
-
83
- get "/?src=#{@image_url}&#{shortcut}=true"
84
-
85
- last_response.should be_ok
86
- ImageSize.new(last_response.body).get_width.should eq width
91
+
92
+ file = get_image "/?src=#{@image_url}&#{shortcut}=true"
93
+
94
+ last_response.status.should eq(200)
95
+ FastImage.size(file)[0].should eq width
87
96
  end
88
-
97
+
89
98
  it "should use my Dragonfly shortcut with one argument" do
90
99
  setup_image
91
100
  width = 100
@@ -96,10 +105,10 @@ describe Magickly::App do
96
105
  end
97
106
  end
98
107
 
99
- get "/?src=#{@image_url}&#{shortcut}=#{width}x"
100
-
101
- last_response.should be_ok
102
- ImageSize.new(last_response.body).get_width.should eq width
108
+ file = get_image "/?src=#{@image_url}&#{shortcut}=#{width}x"
109
+
110
+ last_response.status.should eq(200)
111
+ FastImage.size(file)[0].should eq width
103
112
  end
104
113
  end
105
114
 
@@ -109,47 +118,69 @@ describe Magickly::App do
109
118
  setup_image
110
119
  width = 100
111
120
 
112
- get "/q/src/#{@escaped_image_url}/resize/#{width}x"
113
-
121
+ file = get_image "/q/src/#{@escaped_image_url}/resize/#{width}x"
122
+
123
+ a_request(:get, @image_url).should have_been_made.once
124
+ last_response.status.should eq(200)
125
+ FastImage.size(file)[0].should eq width
126
+ end
127
+
128
+ end
129
+
130
+ describe "GET /qe" do
131
+
132
+ it "resized an image" do
133
+ setup_image
134
+ width = 100
135
+
136
+ # This is just Base64.urlsafe_encode64 which is not available in ruby 1.8.7
137
+ encoded = ["src/#{@escaped_image_url}/resize/#{width}x"].pack("m0").tr("+/", "-_")
138
+
139
+ # Strip the newlines from the encoding since m0 should mean no newlines
140
+ # but doesn't seem to be doing that in ruby 1.8.7
141
+ encoded = encoded.tr("\n", "")
142
+
143
+ file = get_image "/qe/#{encoded}"
144
+
114
145
  a_request(:get, @image_url).should have_been_made.once
115
- last_response.should be_ok
116
- ImageSize.new(last_response.body).get_width.should eq width
146
+ last_response.status.should eq(200)
147
+ FastImage.size(file)[0].should eq width
117
148
  end
118
149
 
119
150
  end
120
-
151
+
121
152
  describe "GET /analyze" do
122
153
  it "retrieves the mime_type of an image" do
123
154
  setup_image
124
-
155
+
125
156
  get "/analyze/mime_type?src=#{@image_url}"
126
-
157
+
127
158
  a_request(:get, @image_url).should have_been_made.once
128
- last_response.should be_ok
159
+ last_response.status.should eq(200)
129
160
  last_response.body.should eq 'image/png'
130
161
  end
131
-
162
+
132
163
  it "retrieves the color palette of an image" do
133
164
  setup_image
134
-
165
+
135
166
  get "/analyze/color_palette?src=#{@image_url}"
136
-
167
+
137
168
  a_request(:get, @image_url).should have_been_made.once
138
- last_response.should be_ok
169
+ last_response.status.should eq(200)
139
170
  last_response.body.should_not be_empty
140
171
  json = ActiveSupport::JSON.decode(last_response.body)
141
172
  json.should be_an Array
142
173
  json.size.should eq 5
143
174
  end
144
-
175
+
145
176
  it "should handle analyzer methods where the question mark is missing" do
146
177
  Magickly.dragonfly.analyser_methods.map{|m| m.to_s }.should include 'landscape?'
147
178
  setup_image
148
-
179
+
149
180
  get "/analyze/landscape?src=#{@image_url}"
150
-
181
+
151
182
  a_request(:get, @image_url).should have_been_made.once
152
- last_response.should be_ok
183
+ last_response.status.should eq(200)
153
184
  last_response.body.should =~ /false/
154
185
  end
155
186
  end
@@ -157,18 +188,18 @@ end
157
188
 
158
189
  describe MagicklyApp do
159
190
  include Rack::Test::Methods
160
-
191
+
161
192
  def app
162
193
  MagicklyApp
163
194
  end
164
-
195
+
165
196
  describe "backward compatibility test" do
166
-
197
+
167
198
  it "should display the demo page for no params" do
168
199
  get '/'
169
- last_response.should be_ok
200
+ last_response.status.should eq(200)
170
201
  # TODO test that it renders the view
171
202
  end
172
-
203
+
173
204
  end
174
205
  end
data/spec/spec_helper.rb CHANGED
@@ -4,7 +4,7 @@ require 'magickly'
4
4
  require 'rack/test'
5
5
  require 'sinatra'
6
6
  require 'webmock/rspec'
7
- require 'image_size'
7
+ require 'fastimage'
8
8
 
9
9
  # Requires supporting files with custom matchers and macros, etc,
10
10
  # in ./support/ and its subdirectories.
@@ -17,12 +17,10 @@ RSpec.configure do |config|
17
17
  end
18
18
 
19
19
  def compare_binary(one, two)
20
- if String.instance_methods.include?(:encoding)
21
- # Ruby 1.9
22
- unless one.encoding == two.encoding
23
- one = one.force_encoding("UTF-8")
24
- two = two.force_encoding("UTF-8")
25
- end
20
+ # Ruby 1.9
21
+ unless one.encoding == two.encoding
22
+ one = one.force_encoding("UTF-8")
23
+ two = two.force_encoding("UTF-8")
26
24
  end
27
25
 
28
26
  one.should eq two
@@ -20,6 +20,21 @@ describe Dragonfly::DataStorage::RemoteDataStore do
20
20
  image,extra = datastore.retrieve(url)
21
21
  image.should eq IO.read(image_path)
22
22
  end
23
+
24
+ it "should fetch the image based on the url_host variable" do
25
+ path = "foo/bar/iamgemagick.png"
26
+ url_host = "http://www.foo.com/"
27
+ url = url_host + path
28
+ stub_request(:get, url)
29
+
30
+ datastore = Dragonfly::DataStorage::RemoteDataStore.new
31
+ datastore.configure do |c|
32
+ c.url_host = url_host
33
+ end
34
+
35
+ datastore.retrieve path
36
+ a_request(:get, url).should have_been_made.once
37
+ end
23
38
  end
24
39
  end
25
40
 
metadata CHANGED
@@ -1,126 +1,91 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magickly
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
5
- prerelease:
4
+ version: 2.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Aidan Feldman
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-01-26 00:00:00.000000000 Z
11
+ date: 2013-02-27 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: sinatra
16
- requirement: &70099405673020 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: '1.2'
22
20
  type: :runtime
23
21
  prerelease: false
24
- version_requirements: *70099405673020
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
25
27
  - !ruby/object:Gem::Dependency
26
28
  name: dragonfly
27
- requirement: &70099405672440 !ruby/object:Gem::Requirement
28
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
- - - ~>
31
+ - - "~>"
31
32
  - !ruby/object:Gem::Version
32
- version: 0.9.5
33
+ version: 0.9.14
33
34
  type: :runtime
34
35
  prerelease: false
35
- version_requirements: *70099405672440
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.14
36
41
  - !ruby/object:Gem::Dependency
37
42
  name: addressable
38
- requirement: &70099405671720 !ruby/object:Gem::Requirement
39
- none: false
43
+ requirement: !ruby/object:Gem::Requirement
40
44
  requirements:
41
- - - ~>
45
+ - - "~>"
42
46
  - !ruby/object:Gem::Version
43
47
  version: '2.2'
44
48
  type: :runtime
45
49
  prerelease: false
46
- version_requirements: *70099405671720
47
- - !ruby/object:Gem::Dependency
48
- name: httparty
49
- requirement: &70099405670520 !ruby/object:Gem::Requirement
50
- none: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.8.1
55
- type: :runtime
56
- prerelease: false
57
- version_requirements: *70099405670520
54
+ version: '2.2'
58
55
  - !ruby/object:Gem::Dependency
59
- name: activesupport
60
- requirement: &70099405669280 !ruby/object:Gem::Requirement
61
- none: false
56
+ name: httparty
57
+ requirement: !ruby/object:Gem::Requirement
62
58
  requirements:
63
- - - ! '>='
59
+ - - "~>"
64
60
  - !ruby/object:Gem::Version
65
- version: 2.0.0
61
+ version: '0.13'
66
62
  type: :runtime
67
63
  prerelease: false
68
- version_requirements: *70099405669280
69
- - !ruby/object:Gem::Dependency
70
- name: jeweler
71
- requirement: &70099405668340 !ruby/object:Gem::Requirement
72
- none: false
64
+ version_requirements: !ruby/object:Gem::Requirement
73
65
  requirements:
74
- - - ~>
66
+ - - "~>"
75
67
  - !ruby/object:Gem::Version
76
- version: '1.5'
77
- type: :development
78
- prerelease: false
79
- version_requirements: *70099405668340
68
+ version: '0.13'
80
69
  - !ruby/object:Gem::Dependency
81
- name: rack-test
82
- requirement: &70099405667520 !ruby/object:Gem::Requirement
83
- none: false
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
84
72
  requirements:
85
- - - ! '>='
73
+ - - ">="
86
74
  - !ruby/object:Gem::Version
87
- version: '0'
88
- type: :development
89
- prerelease: false
90
- version_requirements: *70099405667520
91
- - !ruby/object:Gem::Dependency
92
- name: rspec
93
- requirement: &70099405666620 !ruby/object:Gem::Requirement
94
- none: false
95
- requirements:
96
- - - ~>
75
+ version: 2.0.0
76
+ - - "<"
97
77
  - !ruby/object:Gem::Version
98
- version: '2.4'
99
- type: :development
78
+ version: '5'
79
+ type: :runtime
100
80
  prerelease: false
101
- version_requirements: *70099405666620
102
- - !ruby/object:Gem::Dependency
103
- name: webmock
104
- requirement: &70099405666020 !ruby/object:Gem::Requirement
105
- none: false
81
+ version_requirements: !ruby/object:Gem::Requirement
106
82
  requirements:
107
- - - ~>
83
+ - - ">="
108
84
  - !ruby/object:Gem::Version
109
- version: '1.6'
110
- type: :development
111
- prerelease: false
112
- version_requirements: *70099405666020
113
- - !ruby/object:Gem::Dependency
114
- name: imagesize
115
- requirement: &70099405681480 !ruby/object:Gem::Requirement
116
- none: false
117
- requirements:
118
- - - ~>
85
+ version: 2.0.0
86
+ - - "<"
119
87
  - !ruby/object:Gem::Version
120
- version: '0.1'
121
- type: :development
122
- prerelease: false
123
- version_requirements: *70099405681480
88
+ version: '5'
124
89
  description: A service for image manipulation - built as an extensible wrapper of
125
90
  Imagemagick which handles caching, c/o the Dragonfly gem.
126
91
  email: aidan.feldman@gmail.com
@@ -130,63 +95,46 @@ extra_rdoc_files:
130
95
  - LICENSE.txt
131
96
  - README.md
132
97
  files:
133
- - .document
134
- - .gemtest
135
- - .rspec
136
- - .travis.yml
98
+ - CONTRIBUTING.md
137
99
  - Gemfile
138
100
  - Gemfile.lock
139
- - HISTORY.md
140
101
  - LICENSE.txt
102
+ - Procfile
141
103
  - README.md
142
104
  - Rakefile
143
- - VERSION
144
- - config.ru
145
105
  - lib/dragonfly/data_storage/remote_data_store.rb
146
- - lib/images/lomo_mask.png
147
106
  - lib/magickly.rb
148
107
  - lib/magickly/app.rb
149
- - lib/public/imagemagick.png
150
- - lib/public/images/logo.jpg
151
- - lib/public/jquery-ui.smoothness.css
152
- - lib/public/magickly_demo.js
153
- - lib/public/style.css
108
+ - lib/magickly/version.rb
154
109
  - lib/shortcuts.rb
155
- - lib/views/analyzers.erb
156
- - lib/views/index.erb
157
- - magickly.gemspec
158
110
  - spec/requests/magickly_app_spec.rb
159
111
  - spec/spec_helper.rb
160
112
  - spec/support/imagemagick.png
161
113
  - spec/unit/magickly_spec.rb
162
114
  - spec/unit/remote_data_store_spec.rb
163
115
  - spec/unit/shortcut_spec.rb
164
- homepage: http://github.com/afeld/magickly
116
+ homepage: http://magickly.afeld.me
165
117
  licenses:
166
118
  - MIT
119
+ metadata: {}
167
120
  post_install_message:
168
121
  rdoc_options: []
169
122
  require_paths:
170
123
  - lib
171
124
  required_ruby_version: !ruby/object:Gem::Requirement
172
- none: false
173
125
  requirements:
174
- - - ! '>='
126
+ - - ">="
175
127
  - !ruby/object:Gem::Version
176
128
  version: '0'
177
- segments:
178
- - 0
179
- hash: 596109342780870765
180
129
  required_rubygems_version: !ruby/object:Gem::Requirement
181
- none: false
182
130
  requirements:
183
- - - ! '>='
131
+ - - ">="
184
132
  - !ruby/object:Gem::Version
185
133
  version: '0'
186
134
  requirements: []
187
135
  rubyforge_project:
188
- rubygems_version: 1.8.15
136
+ rubygems_version: 2.2.0
189
137
  signing_key:
190
- specification_version: 3
138
+ specification_version: 4
191
139
  summary: image manipulation as a (plugin-able) service
192
140
  test_files: []