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 prefix

If the app is mounted with a path prefix (such as when using in Rails), then we need to add this prefix to the urls:

app.url_path_prefix = '/media'

(or done in a configuration block).

app.fetch('my_uid').url                                  # "/media/BAhbBlsH..."

This is done for you when using Rails defaults.

You can override it using

app.fetch('my_uid').url(:path_prefix => '/images')       # "/images/BAhbBlsH..."

Host

You can also set a host for the urls

app.url_host = 'http://some.host'
app.fetch('my_uid').url                                  # "http://some.host/BAhb..."

app.fetch('my_uid').url(:host => 'http://localhost:80')  # "http://localhost:80/BAh..."

Suffix

You can set a suffix for the urls (for example if some other component behaves badly with urls that have no file extension).

Note that this has no effect on the response.

app.url_suffix = '.jpg'
app.fetch('some/uid').url                                # "...b21lL3VpZA.jpg"

You can also pass it a block, that yields the Job, for example:

app.url_suffix = proc{|job|
  "/#{job.uid_basename}#{job.encoded_extname || job.uid_extname}"
}

app.fetch('2007/painting.pdf').url                       # "...eS5ib2R5/painting.pdf"
app.fetch('2007/painting.pdf').encode(:png).url          # "...gZlOgbmc/painting.png"

And you can override it:

app.fetch('some/uid').url(:suffix => '/yellowbelly')     # "...b21lL3VpZA/yellowbelly"

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|
  "#{job.basename}_#{job.process_steps.first.name}.#{job.encoded_format || job.ext}"
}

This will for example give the following filenames for the following jobs:

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])
}

Rack-Mount:

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

Usher:

routes = Usher::Interface.for(:rack) do
  add('/text/:text').to app.endpoint{|params, app|
    app.generate(:text, params[:text])
  }
end

HTTP Router:

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.

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