1

Given a minimal example of a Coldfusion rest service (named "FileStore"):

component
  restpath = ""
  rest     = true
{
  remote void function getFile(
    required string path restargsource = "Path"
  )
    httpmethod = "GET"
    restpath   = "{path}"
  {
    var file = FileReadBinary( "/some/path/to/local/files/#path#" );
    var mimetype = customFunctionToGetMimeType( getFileFromPath( path ) );
    cfcontent( variable = file, type = mimetype );
  }
}

This will match paths:

/rest/FileStore/file1.pdf
/rest/FileStore/file2.jpg

But if you try sub-directories - i.e.

/rest/FileStore/subdir1/file3.xml
/rest/FileStore/subdir2/subsubdir1/file4.raw

It returns HTTP status 404 Not Found (as, I'm assuming, it cannot find a matching REST service).

Is there a way to get the rest path to match all sub-paths?

MT0
  • 143,790
  • 11
  • 59
  • 117

3 Answers3

0

Use URI Rewriting to perform a redirect remove the slashes from the path.

An example in Apache (taken from this answer) would be:

RewriteEngine on
RewriteRule ^(/rest/FileStore/[^/]*)/([^/]*/.*)$ $1__$2  [N]
RewriteRule ^(/rest/FileStore/[^/]*)/([^/]*)$    $1__$2  [R=302]

The first rule will replace the first slash (with __) if there are multiple slashes in the path (and repeat); the second rule will replace the final slash and perform a (temporary) redirect.

In the service you can then re-rewrite the path to include the slashes.

remote void function getFile(
  required string path restargsource = "Path"
)
  httpmethod = "GET"
  restpath   = "{path}"
{
  var actual_path = Replace( path, "__", "/", "ALL" );
  var file = FileReadBinary( "/some/path/to/local/files/#actual_path#" );
  var filename = getFileFromPath( actual_path );
  var mimetype = customFunctionToGetMimeType( filename );

  cfheader( name = "content-disposition", value = "inline; filename=#filename#" );
  cfcontent( variable = file, type = mimetype );
}

There are several issues with this:

  1. If you are navigating through files which contain relative path links to other files in different sub-directories then the URI rewriting breaks these links.
  2. If the original path contains the string used to replace slashes then this will break the file path.
Community
  • 1
  • 1
MT0
  • 143,790
  • 11
  • 59
  • 117
  • I added this answer for the method I am currently using - however, I'm looking for a better method - preferably one that does not rely on redirecting the URI. – MT0 Oct 16 '15 at 10:24
0

Write a REST service for each level of the subdirectory and, internally, point it back to the original service.

remote void function getSubdir1File(
  required string subdir1 restargsource = "Path",
  required string file   restargsource = "Path"
)
  httpmethod = "GET"
  restpath   = "{subdir1}/{file}"
{
  getFile( subdir1 & '/' & file );
}

remote void function getSubdir2File(
  required string subdir1 restargsource = "Path",
  required string subdir2 restargsource = "Path",
  required string file   restargsource = "Path"
)
  httpmethod = "GET"
  restpath   = "{subdir1}/{subdir2}/{file}"
{
  getFile( subdir1 & '/' & subdir2 & '/' & file );
}

Repeating ad-nauseum until you get to a sufficient depth that you've covered 99.9999%/sufficient of the use cases.

  1. This addresses the issues with URI rewriting (allows relative path links within files and for file names to use all non-slash characters).
  2. It is not DRY.
  3. If you get a file in a directory beyond the implemented depth then it will not be found. (Although it could be coupled with URI rewriting to allow the file to be found even if it does then break internal links for these limited cases.)
MT0
  • 143,790
  • 11
  • 59
  • 117
0

Jersey (JAX-RS), which is what ColdFusion appears to use under the hood for its REST services, allows regular expressions in its @PATH notation.

Using a regular expression to match all characters (restpath = "{path:.*}") then you can simply match all sub-paths:

component
  restpath = ""
  rest     = true
{
  remote void function getFile(
    required string path restargsource = "Path"
  )
    httpmethod = "GET"
    restpath   = "{path:.*}"
  {
    var file = FileReadBinary( "/some/path/to/local/files/#path#" );
    var mimetype = customFunctionToGetMimeType( getFileFromPath( path ) );
    cfcontent( variable = file, type = mimetype );
  }
}

Thanks to this answer for the inspiration

Community
  • 1
  • 1
MT0
  • 143,790
  • 11
  • 59
  • 117