URLs
We can get urls for any kind of job:
app = Dragonfly[:images]
app.fetch('my_uid').process(:flip).url # "/BAhbBlsH..."
app.generate(:text, 'hello').thumb('500x302').gif.url # "/BAhbCFsHOgZ..."
Path format
The format of the standard urls can be configured using url_format
:
app.configure do |c|
c.url_format = '/:job'
end
(or call app.server.url_format=
directly).
url_format = '/:job/:basename.:format'
:
media = app.fetch('my_uid')
media.url # "/BAhbBlsHOgZmSSIJbWlsawY6BkVU"
media.name = 'milk.txt'
media.url # "/BAhbBlsHOgZmSSIJbWlsawY6BkVU/milk.txt"
media.encode(:pdf).url # "/BAhbB1sHOgZ...RbBzoGZToIcGRm/milk.pdf"
media.url(:format => 'bang') # "/BAhbBlsHOgZmSSIJbWlsawY6BkVU/milk.bang"
media.url(:some => 'thing') # "/BAhbBlsHOgZmSSIJbWlsawY6BkVU/milk.txt?some=thing"
url_format = '/some-prefix/:job'
:
media = app.fetch('my_uid')
media.url # "/some-prefix/BAhbBlsHOgZmSSIJbWlsawY6BkVU"
url_format = '/blah'
:
media = app.fetch('my_uid')
media.url # "/blah?job=BAhbBlsHOgZmSSIJbWlsawY6BkVU"
When using Models, any magic attributes will be used in url generation, e.g.
app.server.url_format = '/frogs/:job/:basename-:width.:format'
with
class Frog
image_accessor :face # columns face_uid, face_name and face_width
end
gives
frog = Frog.new :face => Pathname.new('froggie.jpg') # image with width 400
frog.face.url # "/frogs/BAhbBlsHOgZmSSIIc2RmBjoGRVQ/froggie-400.jpg"
Host
You can also set a host for the urls
app.configure{|c| c.url_host = 'http://some.host' } # or directly on app.server
app.fetch('my_uid').url # "http://some.host/BAhb..."
app.fetch('my_uid').url(:host => 'http://localhost:80') # "http://localhost:80/BAh..."
Content-Disposition
You can manually set the content-disposition of the response:
app.content_disposition = :attachment # should be :inline or :attachment (or :hidden)
:attachment
tells the browser to download it, :inline
tells it to display in-browser if possible.
You can also use a block:
app.content_disposition = proc{|job, request|
if job.format == :jpg || request['d'] == 'inline' # request is a Rack::Request object
:inline
else
:attachment
end
}
Downloaded filename
To specify the filename the browser uses for 'Save As' dialogues:
app.content_filename = proc{|job, request|
if job.process_steps.any?
"#{job.basename}_#{job.process_steps.first.name}.#{job.format}"
else
"#{job.basename}.#{job.format}"
end
}
This will for example give the following filenames for the following jobs:
app.fetch('some/tree.png') # -> 'tree.png'
app.fetch('some/tree.png').process(:greyscale) # -> 'tree_greyscale.png'
app.fetch('some/tree.png').process(:greyscale).gif # -> 'tree_greyscale.gif'
By default the original filename is used, with a modified extension if it's been encoded.
Routed Endpoints
You can also use a number of Rack-based routers and create Dragonfly endpoints.
If we have an app set up for using ImageMagick:
app = Dragonfly[:images].configure_with(:imagemagick)
Then to get the url '/text/hello' to display the text "hello"...
Rails 3 (routes.rb):
match '/text/:text' => app.endpoint { |params, app|
app.generate(:text, params[:text])
}
Routes = Rack::Mount::RouteSet.new do |set|
set.add_route app.endpoint{|params, a| a.generate(:text, params[:text]) },
:path_info => %r{/text/(?:<text>.+)}
# ...
end
routes = Usher::Interface.for(:rack) do
add('/text/:text').to app.endpoint { |params, app|
app.generate(:text, params[:text])
}
end
r = HttpRouter.new
r.add('/text/:text').to app.endpoint { |params, app|
app.generate(:text, params[:text])
}
In each case the url will need to be generated by the router of choice, or manually.
NOTE: Ruby treats curly braces slightly differently to do
...end
so be aware of this when using the above examples.
Simple Endpoints
Job objects can also be turned straight into Rack endpoints using to_app
, e.g. in Rails 3:
match '/beach' => app.fetch_file('~/some/image.png').thumb('100x100#').jpg.to_app
Denial-of-service attacks
Although the standard urls are fairly cryptic, a malicious person who knows the Dragonfly source code could potentially work out how to generate urls to spam your server with heavy requests, e.g. resize to 100000 by 100000 pixels.
Therefore the app can be protected by requiring the presence of a "DOS-protection" SHA in the urls:
app.configure do |c|
c.protect_from_dos_attacks = true
c.secret = 'You should supply some random secret here'
end
Then the standard generated urls will have a SHA query parameter attached:
app.fetch('my_uid').url # "/BAhbBlsHOgZmIghzZGY?s=df76ba27"
Any requests without the correct SHA parameter result in a 400 (bad parameters) error response.
You can also validate for a correct SHA using routed endpoints:
match '/text/:text' => app.endpoint{|params, app|
app.generate(:text, params[:text]).validate_sha!(params[:sha])
}
... where obviously you need to pass in a 'sha' parameter to the url, which can be found using
app.generate(:text, 'some text').sha
Overriding responses
You can override/add headers using response_headers
:
app.configure do |c|
c.response_headers['X-Something'] = 'Custom header' # set directly..
c.response_headers['summink'] = proc{|job, request| # ...or via a callback
job.image? ? 'image yo' : 'not an image'
}
end
You can intercept the response from the dragonfly server by throwing :halt
with a Rack response array from inside the before_serve
callback:
app.configure do |c|
c.server.before_serve do |job, env|
throw :halt, [200, {'Content-type' => 'text/plain'}, ['hello']]
end
end