Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Outputting file content with headers won't work #2079

Closed
outime opened this issue Aug 12, 2013 · 5 comments
Closed

Outputting file content with headers won't work #2079

outime opened this issue Aug 12, 2013 · 5 comments

Comments

@outime
Copy link

outime commented Aug 12, 2013

Scenario: web service where users can upload their photos. Pictures are stored under /app/storage/ (i.e. not /public/). Direct access to the images is not allowed because some database stuff needs to be done before outputting the actual image.

How it works:

  1. User enters http://example.com/image/123.jpg
  2. Router catches the request:
  Route::get('img/{image}', 'FileController@showImage');
  1. Controller checks that file exists, does all the required database tasks and output the image with the required headers:
return Response::make(File::get($filePath), 200, array('Content-Type' => $mime, 'Content-Length' => File::size($filePath)));

All the arguments have been checked and returns the correct values (including $mime, which has been set before).
4. It won't work. For some reason, the size from File::size() is correct and the Content-Length is using that exact value, but the actual amount of data sent to the output is a bit smaller (browser will complain about not getting all the promised content).

How I tried to fix it:

  1. Checked all the possible environmental variables which could cause the issue (file permissions, web server, PHP support ...). Tried in different installations and the exact same issue is being reproduced.
  2. Tried to manually set the headers and output without using the Response object. This works, as it outputs the correct image:
header("Content-Type: $mime");
header('Content-Length: ' . File::size($filePath));
print $fileContent;

Headers using header():

HTTP/1.1 200 OK
Date: Mon, 12 Aug 2013 00:00:00 GMT
Server: Apache
Content-Length: 663932
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: image/png

Headers using Response object (content = different data):

HTTP/1.1 200 OK
Date: Mon, 12 Aug 2013 00:00:00 GMT
Server: Apache
*Cache-Control: no-cache*
*Set-Cookie: laravel_session=udk0NVIcpD665V5gzAeQA3; expires=Mon, 12-Aug-2013 02:50:24 GMT; path=/; httponly*
Content-Length: 663932
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: image/png

The only difference is that couple headers, which obviously is not the problem (I even tried to send the exact same ones using header() and the output was correct). The underlying cause could be something related with the session management, but I did not found any way to disable sessions for one specific route (which would not be a practical thing, but just for testing).

@Unprofound
Copy link

I think you should use Response::stream instead of Response::make

Response::stream(function() use($fileContent) {
  echo $fileContent;
}, 200, $headers);

Give that a shot, I have done something similar to return encrypted audio files where I had to unencrypt the file contents first.

@outime
Copy link
Author

outime commented Aug 14, 2013

That worked flawlessly, thank you very much.

I was not aware of the Response::stream method as it does not appear in the documentation (http://laravel.com/docs/requests). I think I will leave a note to update that section to at least mention this.

@outime outime closed this as completed Aug 14, 2013
@Unprofound
Copy link

Yeah, it is not in the documents. If you dig around in the code ( as I tend to do ) there are plenty of things not clearly documented. Perhaps this section of the docs needs to be updated. http://laravel.com/docs/responses#special-responses to include how to stream file content.

@xmarcos
Copy link

xmarcos commented Oct 5, 2013

Here is the StreamedResponse documentation in case you need more details.

@emayk
Copy link

emayk commented Jan 3, 2014

@xmarcos thanks,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants