Description: Cherokee is a flexible, very fast, lightweight Web server. It is implemented entirely in C, and has no dependencies beyond a standard C library. It is embeddable and extensible with plug-ins. It supports on-the-fly configuration by reading files or strings, TLS/SSL (via GNUTLS or OpenSSL), virtual hosts, authentication, cache friendly features, PHP, custom error management, and much more.
Keywords: cherokee web server httpd http

## Index → Modules → Handlers

## Handler: Hidden Downloads

The Hidden Downloads handler implements secure download mechanisms. This module allows to handle temporal URLs to serve hidden files.

### Parameters

Parameters | Type | Description
--- | --- | ---
`secret` | String | Required. Share secret between the handler and the script.
`timeout` | number | Optional. How long - in seconds - the URL will be valid.

### Technical Description

The idea behind this handler is plain and simple. It will only serve a file if the URL has been generated by a dynamic execution script that you’ve previously written. If the script allows the user to access the file, it will generate a special encoded URL that Cherokee will handle through the Hidden Downloads module.

If the URL is invalid, is modified or expires, Cherokee will not serve the file.

The encoding scheme is quite straightforward. It is basically the result of MD5-hash of: a shared secret string between Cherokee and the script, the relative path to the requested file (relative to the rule document root), and the current time:

    '/' HEX (MD5 (Secret + URL + HEX(time))) '/' HEX(time) '/' URL

Here you have a reference implementation in Python:

     def secure_download (prefix, url, secret):
        import time, hashlib
        t = '%08x' % (time.time())
        return "/%s/%s/%s" % (hashlib.md5(secret + url + t).hexdigest(), t, url)

The same function written in PHP would be:

    function secure_download ($prefix, $url, $secret) {
      $time = sprintf('%08x', time());
      return "$prefix/".md5($secret.$url.$time)."/$time$url";
    }

It is important to notice that the URLs are only valid for a period of time. If an URL expires, the server will return an error instead of the file content. By default URLs last 60 seconds.

### Examples

Lets imagine you have a few ISO files that you want to distribute among a certain group of people.

First, and most importantly, the ISO files ought to be outside of the WWW directory root; otherwise, anybody would be able to download them. Let’s imagine those ISO files are located under: `/mnt/isos/`, and the server document root is located in `/var/www/`.

Now it is time to configure the `/downloads` web directory, so it is handled by Hidden Downloads. We set a shared secret string (`Abracadabra`), and the document root where the real ISO files are located (`/mnt/isos`):

Next step is to write the logic that will decide what is the user given access to. For instance, check out this example:

     SECRET = "Abracadabra"
     PREFIX = "/downloads"

     def secure_download (url):
        import time, hashlib
        t = '%08x' % (time.time())
        return PREFIX + "/%s/%s/%s" % (hashlib.md5(SECRET + url + t).hexdigest(), t, url)

     if logged:
        print '<a href="%s">Download</a>' % (secure_download (url))
     else:
        print 'Sorry, you have to log in first.'

According to this example, if a user tried to access `/bar/foo/example.iso` and access were granted, he would get a link to an URL like this:

    /downloads/ac003ebbb88c4fc9a75687223c72c6da/49b40a43/bar/foo/example.iso

Since the `/download` web directory is configured with this "Hidden Downloads" handler, it will check the URL to ensure that it is valid and has not expired. Then, if everything was right, it would send the `/mnt/isos/bar/foo/example.iso` file to the client.