For serving static files the web server it the best option... :-) |
<!--toc--> |
|
However, cppcms can be used to serve static files so that the same permission logic can be used as other dynamic contents. |
## Introduction |
|
-------------------------------- |
For serving static files the web server it the best option, lighttpd, nginx or Apache would do much better job then you probably can. |
|
However, cppcms can be used to serve static files so that the same permission logic can be used as other dynamic contents. |
|
This is quite different. To handle this kind of situation |
you should be aware of two very important factors: |
When serving static files you should be aware of two very important factors: |
|
|
1. Security |
2. Performance |
|
## Security |
|
|
Let's start from the first. I assume you want to let user |
to download certain files that you are controlling. |
|
For url like |
|
/some/files/[...] <- these are allows. |
|
Things you DO NOT EVER-EVER-EVER do: |
|
class my_server { |
|
my_server(...) |
{ |
... |
|
dispatcher().assign("/some/files/(.*)",&my_server::serve_file,this,1) |
|
} |
|
|
|
void serve_file(std::string file_name) |
{ |
|
std::ifstream f(("some_dir_name/" + file_name).c_str()); |
if(!f) { |
response().status(404) |
/some/files/[...] <- these are allowed |
|
} |
else { |
response().content_type("application/octet-stream") |
Things you should **never do:** |
|
response().out() << f.rdbuf(); |
class my_server { |
|
my_server(...) |
{ |
dispatcher().assign("/some/files/(.*)",&my_server::serve_file,this,1) |
} |
void serve_file(std::string file_name) |
{ |
|
std::ifstream f(("some_dir_name/" + file_name).c_str()); |
if(!f) { |
response().status(404) |
} |
else { |
response().content_type("application/octet-stream") |
response().out() << f.rdbuf(); |
} |
} |
... |
} |
|
} |
|
... |
} |
|
|
Because attacker cat create path |
|
/some/files/../../../etc/some_secret.txt |
Because attacker can create path |
|
And read it... |
/some/files/../../../etc/some_secret.txt |
|
It would be VERY BAD. |
And read it... It would be **very bad**. |
|
|
If you want to serve a file create a very strict **WHITE** list |
of allowed names like: |
If you want to serve a file create a very strict **white** list of allowed names like: |
|
|
/some/files/([a-z_0-9\.]\.txt) |
/some/files/([a-z_0-9\.]+\.txt) |
|
Or even better convert the name to sha1 representation and save |
files using cryptographic hash. |
Or even better convert the name to sha1 or md5 representation and save files using names generated |
from their hash. |
|
Like: |
For example: |
|
name = some_dir_per_user + "/" + cppcms::util::md5hex(file_name) + ".dat"; |
|
std::ifstream f(name.c_str()); |
|
|
## Performance |
|
For small files (several K or even MB) |
|
|
response().out() << f.rdbuf(); |
response().out() << f.rdbuf(); |
|
Is fine and works very well. |
|
For the big files it is better to use headers like X-Send-File that are |
supported by lighttpd, apache and nginx. |
|
http://redmine.lighttpd.net/projects/1/wiki/X-LIGHTTPD-send-file |
<http://redmine.lighttpd.net/projects/1/wiki/X-LIGHTTPD-send-file> |
|
So instead of calling |
|
|
response().content_type("application/octet-stream") |
|
response().out() << f.rdbuf(); |
response().content_type("application/octet-stream") |
response().out() << f.rdbuf(); |
|
You call: |
|
response().content_type("application/octet-stream") |
|
response().set_header("X-Lighttpd-Send-File",pysical_file_name); |
response().content_type("application/octet-stream") |
response().set_header("X-Lighttpd-Send-File",pysical_file_name); |
|
|
This is specially critical for big files were the |
|
server may for example save the entire FastCGI output |
to temporary file and before serving it (Nginx) or |
cache entire (huge) buffer in the memory (Lighttpd) |
|
|
|
More then that X-SendFile usually much more effective as |
it allows to the web server not to transfer buffers |
to the memory. |
`X-SendFile` usually much more effective than |
serving files via FastCGI as it reduces the data transfer |
over IPC and sometimes does not even copy file |
data to the user space. |
|
|
|
---------------- |