Updated: Comment #N
Problem/Motivation
When the page cache is active, accessing a private file leads to a 500 response. The file content itself is still accessible though. The problem is likely that FinishResponseSubscriber
is executed for all responses (including private file downloads) while back in Drupal 7 comparable drupal_page_footer was not because private file downloads triggered an early exit (see file_transfer).
As a consequence the page cache is active for private file downloads in Drupal 8 while it was not on D7 and therefor we need to disable it explicitely on private file downloads.
Error log
Uncaught PHP Exception LogicException: "The content cannot be set on a BinaryFileResponse instance." at /tmp/drupal/core/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/BinaryFileResponse.php line 272
#0 Symfony\Component\HttpFoundation\BinaryFileResponse->setContent() called at [core/includes/bootstrap.inc:960]
#1 drupal_serve_page_from_cache() called at [core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php:105]
#2 Drupal\Core\EventSubscriber\FinishResponseSubscriber->onRespond()
#3 call_user_func() called at [core/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php:164]
#4 Symfony\Component\EventDispatcher\EventDispatcher->doDispatch() called at [core/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php:53]
#5 Symfony\Component\EventDispatcher\EventDispatcher->dispatch() called at [core/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php:167]
#6 Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch() called at [core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php:166]
#7 Symfony\Component\HttpKernel\HttpKernel->filterResponse() called at [core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php:148]
#8 Symfony\Component\HttpKernel\HttpKernel->handleRaw() called at [core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php:66]
#9 Symfony\Component\HttpKernel\HttpKernel->handle() called at [core/lib/Drupal/Core/HttpKernel.php:65]
#10 Drupal\Core\HttpKernel->handle() called at [core/lib/Drupal/Core/DrupalKernel.php:284]
#11 Drupal\Core\DrupalKernel->handle() called at [core/includes/bootstrap.inc:1478]
#12 drupal_handle_request() called at [index.php:15]
HTTP Request/Response:
Request URL:http://localhost:3000/system/files/private.txt
Request Method:GET
Status Code:500 Internal Server Error
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:de,en-US;q=0.8,en;q=0.6,fr;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Host:localhost:3000
Referer:http://localhost:3000/node/1
Response Headers
Cache-Control:must-revalidate, no-cache, post-check=0, pre-check=0, private
Connection:close
content-language:en
content-language:en
content-length:3467
Content-Type:text/plain; charset=UTF-8
date:Sat, 15 Mar 2014 15:17:34 GMT
date:Sat, 15 Mar 2014 15:17:34 GMT
etag:"1394896654"
etag:"1394896654"
Expires:Sun, 19 Nov 1978 05:00:00 GMT
last-modified:Sat, 15 Mar 2014 15:17:34 GMT
last-modified:Sat, 15 Mar 2014 15:17:34 GMT
Server:lighttpd/1.4.31
x-drupal-cache:MISS
x-generator:Drupal 8 (http://drupal.org)
X-Powered-By:PHP/5.4.26-1~dotdeb.1
x-ua-compatible:IE=edge,chrome=1
x-ua-compatible:IE=edge,chrome=1
Proposed resolution
- Add tests for private file downloads and private image style derivative when page cache is active. Also port them to D7 after they are committed to D8.
- Choose between two alternative approaches:
- Either disable the page cache selectively from within
FileDownloadController
andImageStyleDownloadController
(patch #7) - Or prevent caching of
BinaryFileResponse
altogether (patch #8)
- Either disable the page cache selectively from within
Remaining tasks
User interface changes
None
API changes
None