XSendFile won't serve the files in Apache 2.2 XSendFile won't serve the files in Apache 2.2 apache apache

XSendFile won't serve the files in Apache 2.2


Do not set a Content-Length yourself. This will only confuse handlers such as mod_wsgi in this case.mod_xsendfile will itself set the correct Content-Length.

On Windows you must not only provide the drive letter, the drive letter must be actually in upper-case (IIRC)!

I have a working test configuration like so:

<Directory "E:/">  XSendFile on  XSendFilePath E:/localhosts</Directory>

One of my working test scripts in E:/Apache2.2/htdocs/ looks like this:

<?php  header('X-SendFile: E:/localhosts/archive.tar.bz2');  header('Content-type: application/octet-stream');  header('Content-disposition: attachment; filename="blob"');?>

XSendFileAllowAbove was removed a while back in favor of XSendFilePath


I've had a whole lot of trouble most of the times I had to configure XSendfile path.

Here is me testing several scenarios on Windows to see what was wrong (jump to the end of this post to see the conclusion ad recommendations):

<?php/* X-SENDFILE * This can be a b*tch to configure. So I'm writing various scenarios here so that I can rely on them in the future. * Example use: after re-installing XAMPP, after changing config file, in a new script, after some time without using it... * Tested on Windows 7 + XAMPP (Apache/2.4.3, PHP/5.4.7) + mod_xsendfile 1.0-P1 for Apache 2.4.x Win32 *//** Environment Debug **///echo dirname(__FILE__);   die();//echo $_SERVER['DOCUMENT_ROOT'];   die();/** The damn fucking path, with comments **/// Local file in execution directory.// Tested with: *no* XSendFilePath inside of the Apache config// Result: works fine.//header("X-Sendfile: " . 'localfile.zip' );// Local file in execution directory + relative path// Tested with: *no* XSendFilePath inside of the Apache config// Result: works fine.//header("X-Sendfile: " . '../xsendfile/localfile.zip' );// Local file in execution directory + absolute pathS// Tested with: *no* XSendFilePath inside of the Apache config// Result: works fine and a lot of flexibility on the slash and letter drive format combinations *BUT* case-sensitive//header("X-Sendfile: " . 'D:\Dropbox\XAMPP\web\tests\Languages\Apache\xsendfile\localfile.zip' );  // works fine//header("X-Sendfile: " . '\Dropbox\XAMPP\web\tests\Languages\Apache\xsendfile\localfile.zip' );    // works fine//header("X-Sendfile: " . 'D:/Dropbox/XAMPP/web/tests/Languages/Apache/xsendfile/localfile.zip' );  // works fine//header("X-Sendfile: " . '/Dropbox/XAMPP/web/tests/Languages/Apache/xsendfile/localfile.zip' );    // works fine//header("X-Sendfile: " . '/dropbox/XAMPP/web/tests/Languages/Apache/xsendfile/localfile.zip' );    // FAILS (case-sensitive)// File in the XSendFilePath directory + Absolute path// Tested with: XSendFilePath D:\Dropbox\XAMPP\web -- Mind the backward slashes// Result: FAILS! error.log => [Wed Feb 20 19:08:02.617971 2013] [:error] [pid 15096:tid 1768] (20023)The given path was above the root path: [client ::1:56658] xsendfile: unable to find file: D:\\Dropbox\\XAMPP\\web\\xsfile.zip//header("X-Sendfile: " . 'D:\Dropbox\XAMPP\web\xsfile.zip' );// File in the XSendFilePath directory + Absolute path// Tested with: XSendFilePath D:/Dropbox/XAMPP/web <== mind the forward slashes this time// Result: WORKS! Conclusion: XSendFilePath needs use forward slashes on Windows AND we don't need any trailing slash in it.header("X-Sendfile: " . 'D:\Dropbox\XAMPP\web\xsfile.zip' );/** We might wanna test also: * - How does backward slashes in both XSendfilePath and the header combine? * - The use of subdirectories. * //** The rest of the headers (until otherwise stated, nothing special) **/header("Content-Type: application/zip");header("Content-Disposition: attachment; filename=\"" . 'blah.zip' . "\"");header("Content-Transfer-Encoding: binary");header("Pragma: public");header("Expires: 0");header("Cache-Control: must-revalidate, post-check=0, pre-check=0");header("Cache-Control: public");header("Content-Description: File Transfer");/** Tell the script to stop (so the file download may start) **/die();?>

So, basically, for X-Sendfile on Windows, make sure that:

  • You use forward slashes in your Apache configuration for XSendfilePath (mandatory);
  • Respect the case in your paths, even though we're on Windows (mandatory);
  • Use absolute paths everywhere (recommended)
  • No trailing slashes for XSendfilePath (recommended)

Hope it helps someone! Fabien