Location https://helix.wtgc.org/system/files/users/wtsi/a/ak2/library_branding/wt... (anonymous)

Message	Warning: Cannot modify header information - headers already sent by (output started at 
/www/htdocs/includes/file.inc:1965) in _drupal_session_delete_cookie() 
(line 466 of /www/www-live/drupal.sanger.ac.uk/htdocs/includes/session.inc).

function _drupal_session_delete_cookie($name, $secure = NULL) {
.....
466: setcookie($name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);


function file_transfer($uri, $headers) {
......
  drupal_send_headers();
  $scheme = file_uri_scheme($uri);
  // Transfer file in 1024 byte chunks to save memory usage.
  if ($scheme && file_stream_wrapper_valid_scheme($scheme) && $fd = fopen($uri, 'rb')) {
    while (!feof($fd)) {
1965: print fread($fd, 1024);

Why is this cookie being deleted after the headers and file contents for a file download have been sent for an anonymous user?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Marc Angles’s picture

Hi, we have kind of the exact same bug here.

Did you find an explanation to this one ?

StephenRobinson’s picture

glad someone else has got this issue, been left on the back burner as havent found a solution.

mikeytown2’s picture

Also getting this same error. Looks like the session is getting destroyed & causing this issue. I'll work on a patch.

Warning:
Cannot modify header information - headers already sent by (output started at includes/file.inc:1989)

LINE: 466
FUNCTION: _drupal_session_delete_cookie()
FILE: includes/session.inc

STACKTRACE:

Index Function called Caller line Caller file
9 menu_execute_active_handler 21 index.php
8 call_user_func_array 517 includes/menu.inc
7 image_style_deliver
6 file_transfer 873 modules/image/image.module
5 drupal_exit 1996 includes/file.inc
4 drupal_session_commit 2726 includes/common.inc
3 session_destroy 314 includes/session.inc
2 _drupal_session_destroy
1 _drupal_session_delete_cookie 444 includes/session.inc
0 setcookie 466 includes/session.inc
mikeytown2’s picture

Version: 7.24 » 7.x-dev
Status: Active » Needs review
FileSize
561 bytes
mikeytown2’s picture

Title: Warning: Cannot modify header information - headers already sent » Warning: Cannot modify header information - headers already sent (output started at includes/file.inc)
StephenRobinson’s picture

am testing this, get this alot as people link to images on my restricted internet externally

mikeytown2’s picture

Have you tested the patch to see if it fixes the problem for you?

StephenRobinson’s picture

Hi,
Been live for a few hours and have not seen the error again yet...
Stephen :)

mikeytown2’s picture

Status: Needs review » Reviewed & tested by the community

Marking this RTBC

David_Rothstein’s picture

Version: 7.x-dev » 8.x-dev
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs backport to D7

What are the steps to reproduce this - i.e. when/why is this getting called after headers have already been sent? It looks like the patch might be hiding the actual bug (which is that the cookie is supposed to be deleted, but isn't).

Drupal 8 also looks like it has equivalent code in Drupal\Core\Session\SessionHandler so there's a good chance the bug needs to be addressed there too.

mikeytown2’s picture

In our case, we have drupal serve images for other domains/servers. If a user gets logged out of drupal due to a session timeout and that request was the user generating an image then it can trigger this error.

Sending the file causes headers to be sent. I would suspect that advagg could cause a similar issue (as it generates static files as well) but due to css/js not being used on other domains/servers it doesn't cause this bug.

StephenRobinson’s picture

"In our case, we have drupal serve images for other domains/servers." me too, our librarians keep attaching images to journal site download apps, very annoying for a internal only restricted internet...

mikeytown2’s picture

Status: Needs work » Needs review
FileSize
795 bytes

Thanks David_Rothstein for pointing out that SessionHandler::deleteCookie does have similar code :)

I've attached a patch for D8 based off of #4

mikeytown2’s picture

The alternative to this would be to use drupal_save_session(FALSE); inside of file.inc. Not sure what the D8 equivalent would be.

StephenRobinson’s picture

I did manage this error Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at /www/www-live/drupal.sanger.ac.uk/htdocs/includes/file.inc:2058) in drupal_session_start() (line 292 of /www/htdocs/includes/session.inc).

only occurred when reverting a feature.

mikeytown2’s picture

Version: 8.x-dev » 7.x-dev
FileSize
384 bytes

D7 patch that uses drupal_save_session(FALSE); when transferring any file via php.

drakeston-admin’s picture

Title: Warning: Cannot modify header information - headers already sent (output started at includes/file.inc) » site
Version: 7.x-dev » 7.27
Category: Bug report » Support request

I am also having the same problem at my homepage of my site www.rumathi.com . the best way to solve it is to use drapul image cokiee 6.8

mikeytown2’s picture

Title: site » Warning: Cannot modify header information - headers already sent (output started at includes/file.inc)
Version: 7.27 » 8.x-dev
Category: Support request » Bug report
FileSize
384 bytes

In D8 I think this would happen in BinaryFileResponse::sendContent() which is inside of Symfony so I'm tempted to put it in ImageStyleDownloadController::deliver() and anywhere else BinaryFileResponse is used.

SessionManager::disable() seems to be where this happens; I think I'm using it correctly.

Note that the way file transfers happen in D8 this might not be necessary; this might be a D7 and below issue.

mikeytown2’s picture

Correct D8 patch

The last submitted patch, 18: drupal-2148759-16-no-session-on-file-transfer-D7.patch, failed testing.

mikeytown2’s picture

Patches pass tests on D7 & D8.

JvE’s picture

This appear to happen both at session_destroy and session_start.

For me it is session_start:

Warning: session_start(): Cannot send session cookie - headers already sent by (output started at includes/file.inc:1973) in drupal_session_start() (line 287 of /var/www/virtual/www.ntvg.nl/includes/session.inc).

In both cases I'm wondering why a session does not already exist.

slashrsm’s picture

Status: Needs review » Needs work
+++ b/core/modules/image/src/Controller/ImageStyleDownloadController.php
@@ -149,6 +149,12 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st
+      // Prevent writting to the session if PHP is going to transfer a file.
+      $container = \Drupal::getContainer();
+      $session_manager = $container->get('session_manager');
+      $session_manager->disable();
+

Let's inject session manager via create().

Same with ExportForm and FileDownloadController.

mikeytown2’s picture

Is this the right method - Config::create()? Haven't done much D8 code yet.

mikeytown2’s picture

@JvE Does #16 fix the issue for you?

slashrsm’s picture

@mikeytown2 - no, you need to add "session_manager" to create() function (there are already "lock" and "image.factory" there). This will send it to constructor of the class where you take it and save it into a class member. Then use it like this "$this->sessionManager->disable()" (assuming you saved it in a member variable called "$sessionManager").

mikeytown2’s picture

Can I get a link to an example? The API site doesn't list where the code is called from in SessionManager::disable() so I don't have a good working example on how to do this. You could also update https://www.drupal.org/node/218104 with the correct way to do this in D8 that would be helpful as well :)

JvE’s picture

@mikeytown2: Yes, #16 gets rid of the warning.
But I have the feeling it is simply hiding the symptom of a different fault somewhere.
As in, why would a session not yet exist at that point in the code? Anonymous users? Then why does drupal want to start a session after sending a file?

mikeytown2’s picture

@JvE drupal_set_message() will start a session so I don't think it's totally unreasonable for this to happen.

pachabhaiya’s picture

#16 works for me. I'm not seeing any warning as mentioned in this issue after applying patch #16.

AlexKirienko’s picture

I have faced similar issue in xmlsitemap module, which used modified file_transfer() function.
I have ported patch #16 and it works for me. Thank you.

https://www.drupal.org/node/2546646#comment-10190812

garbo’s picture

#16 fixes the error for my in D7 with the textimage module.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mikeytown2’s picture

Just a heads up that even with #16 applied I got this error:

Warning:
Cannot modify header information - headers already sent by (output started at /var/www/html/includes/common.inc:2658)


LINE: 1265
FUNCTION: drupal_send_headers()
FILE: /var/www/html/includes/bootstrap.inc

STACKTRACE:

  
Index Function called Caller line Caller file
9menu_execute_active_handler21index.php
8image_style_deliver517includes/menu.inc
7file_transfer911modules/image/image.module
6drupal_not_found1999includes/file.inc
5drupal_deliver_page727includes/common.inc
4drupal_deliver_html_page2589includes/common.inc
3drupal_page_footer2705includes/common.inc
2drupal_serve_page_from_cache2723includes/common.inc
1drupal_send_headers1384includes/bootstrap.inc
0header1265includes/bootstrap.inc

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

donquixote’s picture

I opened #2963530: "Cannot send session cookie" on image style generation. with steps to reproduce (on Drupal 7).

Problem, part I

The basic problem (in D7):
drupal_exit() is called in various page callbacks (*) after headers and content are printed.
file_transfer() is just one example.
The callers expect that drupal_exit() will NOT print additional headers.

However, if
- the session is in "lazy" mode (which happens on requests without a session cookie), AND
- some module writes to $_SESSION anyway (e.g. ip_geoloc).

Then drupal_exit() will send headers via
drupal_session_commit() -> drupal_session_start() -> session_start().

This would mean drupal_exit() is not fully suitable as a function for these page callbacks.

Problem, part II: Output buffering!

It is more complicated than that.
In most PHP installations, the initial output buffering level is 1 (the output_buffering setting is probably at 4096).
As long as output buffering is on level 1, the entire problem of "Headers already sent" does not exist!

One could write an example script /test.php like this, and it would be just fine:
https://3v4l.org/tn1fR

assert(1 === ob_get_level());
print 'before the header';
header('AAA:BBB');

However, the following script will produce the "Headers already sent" problem:
https://3v4l.org/1aM5E

assert(1 === ob_get_level());
ob_end_clean();
assert(0 === ob_get_level());
print 'before the header';
header('AAA:BBB');

Now file_transfer() is different from other page callbacks that call drupal_exit(), because file_transfer() also calls ob_end_clean() before anything else.
Interesting issue: #205227: If output_buffering = Off then ob_end_clean fails to delete buffer.

This means:

  • If your PHP installation has output_buffering enabled, then the problem we see here only affects requests that call file_transfer(), and a few others.
  • If your PHP installation has output_buffering disabled from the start, then the problem will occur on many other types of requests. I would even expect it to happen on regular page visits.

Solution

I considered a number of different options.

But in the end, I think the existing patch #18, or something similar, might be the best shot.

My first idea was to change drupal_exit() so that it never sends any headers.
Instead, always send the session cookie headers before the page callback (or never).
However, this does not work if we start with empty $_SESSION, and modules write to $_SESSION during page callback or during hook_exit().
Also, this would be completely unnecessary as long as output buffering is enabled.

The next idea was to keep output buffering enabled in file_transfer().
But this might cause memory problems (not sure).

So, something like #18.
But perhaps we should make sure that output_buffering is always on the same value, to make Drupal behave more reproducibly.

And perhaps provide a version of drupal_exit() that is guaranteed to never send any headers!

donquixote’s picture

@JvE (#28):
(my answer below applies to Drupal 7)

But I have the feeling it is simply hiding the symptom of a different fault somewhere.
As in, why would a session not yet exist at that point in the code? Anonymous users? Then why does drupal want to start a session after
sending a file?

There is a "lazy" session mode in drupal_session_initialize().

  // We use !empty() in the following check to ensure that blank session IDs
  // are not valid.
  if (!empty($_COOKIE[session_name()]) || ($is_https && variable_get('https', FALSE) && !empty($_COOKIE[substr(session_name(), 1)]))) {
    [..]
  }
  else {
    // Set a session identifier for this request. This is necessary because
    // we lazily start sessions at the end of this request, and some
    // processes (like drupal_get_token()) needs to know the future
    // session ID in advance.
    $GLOBALS['lazy_session'] = TRUE;
    $user = drupal_anonymous_user();
    // Less random sessions (which are much faster to generate) are used for
    // anonymous users than are generated in drupal_session_regenerate() when
    // a user becomes authenticated.
    session_id(drupal_random_key());
    if ($is_https && variable_get('https', FALSE)) {
      $insecure_session_name = substr(session_name(), 1);
      $session_id = drupal_random_key();
      $_COOKIE[$insecure_session_name] = $session_id;
    }
  }

This means that session_start() won't be called in bootstrap.
Instead, in drupal_exit() or drupal_page_footer(), drupal_session_commit() is called, which checks if anything is in $_SESSION, and if so, calls session_start().

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mstrelan’s picture

Status: Needs work » Postponed (maintainer needs more info)
Issue tags: +Bug Smash Initiative, +Needs steps to reproduce, +Needs issue summary update

Is this still applicable for Drupal 9 and 10? If so, we need steps to reproduce, ideally with a failing test. We should update the issue summary to use the standard template also.

quietone’s picture

Status: Postponed (maintainer needs more info) » Closed (outdated)

More information on this was asked for 8 months ago, specifically if this is still a problem, and none has been supplied.

Therefore, closing as outdated. If this is incorrect reopen the issue, by setting the status to 'Active', and add a comment explaining what still needs to be done.

Thanks!