Henry Van Styn
and 2 contributors


Catalyst::Controller::SimpleCAS - General-purpose content-addressed storage (CAS) for Catalyst


 use Catalyst::Controller::SimpleCAS;

See the SYNOPSIS of Catalyst::Plugin::SimpleCAS for the standard use/examples.


This controller provides a simple content-addressed storage backend for Catalyst applications. The concept of content-addressed storage ("CAS") is to store arbitrary content in a simple indexed key/value database where the "key" is the SHA1 checksum of the "value". This is the same design and theory used by Git.

This module was originally developed for and within RapidApp before being extracted into its own module. This module provides server-side functionality which can be used for any Catalyst application, however, it is up to the developer to write the associated front-end interfaces to consume its API (unless you are using RapidApp to begin with). RapidApp already has a number of built-in features and interfaces which rely on this module for backend storage, including, cas_link (file attachment columns) and cas_img (image columns) column profiles, as well as the ability to insert images and file links directly within rich template content and html columns using WYSIWYG editors.

The type of content this module is designed to store are simple files (with some extra handling for images specifically). For the purposes of security, we rely on the assumption that knowing the checksum of the content is equivalent to being authorized to view that content. So the checksums are also considered the authorization tokens to access the data, so keeping the checksums themselves secure is the only way to keep the associated data/content secret. If you understand what this means AND you feel that this is insufficient security, don't use this module (or, extend it and add whatever additional security/authorization/permission checks you feel are necessary)

Starting in version 1.000 of this module, Catalyst::Plugin::SimpleCAS is now provided and is the way RapidApp consumes and uses this module, and is the standard way to use this module in any Catalyst application, for most scenarios. The plugin simply injects a single controller instance of Catalyst::Controller::SimpleCAS as 'SimpleCAS' which is all that is needed for most setups. The only reason to use the controller class directly would be if you needed multiple controllers in the same app, or if you wanted to subclass or do something else fancy.

The ATTRUBUTES listed below can be configured in your Catalyst config in the normal manner using the C'<Controller::SimpleCAS'> config key (assuming you used Catalyst::Plugin::SimpleCAS with the default controller_namespace of 'SimpleCAS'). No options are required, with the defaults being sufficient in most cases (including the way this module is used by RapidApp).



Object class to use for the Store backend. Defaults to Catalyst::Controller::SimpleCAS::Store::File


Directory/path to be used by the Store. Defaults to cas_store/ within the Catalyst home directory. This is a convenience param to supply to the Store, which becomes store_dir for the default Catalyst::Controller::SimpleCAS::Store::File store class.

The rationale behind the name 'store_path' instead of 'store_dir' as it becomes in the default store is the notion that a single "path" argument is all that most Stores need, and different stores may treat this value as something other than a filesystem directory, so it was intentionally given the more ambiguous name. For most users that will use basic/default options, these details aren't important.


Optional options (HashRef) to supply when contructing the Store. This is only needed for custom Stores which need more options beyond store_path.


Actual object instance of the Store. By default this object is built using the store_class (by calling new()) with the store_path supplied to the constructor.


Name of an optional Catalyst View to forward to to render JSON responses, with the pre-encoded JSON set in the stash key 'jsonData'. If not set, the encoded JSON is simply set in response body with the Content-Type set to application/json.

If the view name RapidApp::View is loaded (which is the case when RapidApp is loaded), it is used as the default. This is needed to support special round-trip encodings for "Insert Image" and other ExtJS-based upload interfaces.



Upload new content to the CAS and return the sha1 checksum in the body to be able to access it later. Because of the CAS design, the system automatically deduplicates, and will only ever store a single copy of a given unique piece of content in the Store.


Fetch existing content from the CAS according its sha1 checksum.


  GET /simplecas/fetch_content/fdb379f7e9c8d0a1fcd3b5ee4233d88c5a4a023e

The system attempts to identify the content type and sets the MIME type accordingly. Additionally, an optional filename argument can be also be supplied in the URL

  GET /simplecas/fetch_content/fdb379f7e9c8d0a1fcd3b5ee4233d88c5a4a023e/somefile.txt

The main reason this is supported is simply for more human-friendly URLs. The name is not stored or validated in any way. If supplied, this does nothing other than being used to set the content-disposition:

  Content-Disposition: attachment; filename="somefile.txt"

When there is no filename second arg supplied, the content-disposition is set like this:

  Content-Disposition: inline;filename="fdb379f7e9c8d0a1fcd3b5ee4233d88c5a4a023e"


Works like upload_content, but returns a JSON packet with additional metadata/information in the body.


Works like upload_file, but with some image-specific functionality, including client-supplied max width and height values supplied as the first and second args, respectively. For example, a POST upload with Filedata containing an image, and declared max size of 800x600 uses a URL like:

  POST /simplecas/upload_image/800/600

When the image is larger than the max width or height, if the optional dependency Image::Resize is available (which requires GD) it is used to resize the image, preserving height/width proportions accordingly, and the new, resized image is what is stored in the CAS. Otherwise, the image is not resized, but resized dimensions are returned in the JSON packet so the client can generate an img tag for display.

Originally, Image::Resize was a standard dependency, but this can be a PITA to get installed with all of the dependencies of GD.


This does nothing but accept a standard POST/Filedata upload and return it as base64 in a JSON packet within the JSON/object key echo_content.


This is the base action of the Catalyst Chain behind this asset controller. So far it still is a fixed position, but we will allow in a later version to set the Chained base to any other action via configuration.

You could override specific URLs inside the SimpleCAS with own controllers, you just chain to this base controller, but we would strongly advice to put those outside functionalities next to this controller.



Convenience method to fetch the content (as a raw string/scalar) associated with a cas_id string which can be simply be the 40-character checksum by itself, or the checksum with a filename as generated by RapidApp's cas_link and cas_img column profiles.

This method is provided as sugar for the purposes of interacting with the CAS from backend scripts/code, rather than via HTTP requests to the controller actions.


Like fetch but returns the content as a filehandle (i.e. IO::File, or whatever IO object the given Store returns).


Convenience method to add content to the CAS and return the checksum. Content argument can be supplied as a simple Scalar (i.e. raw string/data), a ScalarRef, a filehandle (i.e. an object which derives from IO::Handle or otherwise is an object with an appropriate 'getlines' method, or a filesystem path.

This method is provided as sugar for the purposes of interacting with the CAS from backend scripts/code, rather than via HTTP requests to the controller actions.


Not usually called directly


Not usually called directly


Not usually called directly


Not usually called directly


Not usually called directly





Henry Van Styn <vanstyn@cpan.org>


This software is copyright (c) 2014 by IntelliTree Solutions llc.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.