magickly 1.4.0 → 2.0.0

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.
@@ -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: []