Hey all,

I see this on occasion in our Watchdog logs. It appears to happen only to certain users, and I haven't found a common thread yet, but it is persistent.

After a uc_file notice of "User has started a download" variety, I get this:

Cannot modify header information - headers already sent by (output started at /sites/all/modules/ubercart/uc_file/uc_file.pages.inc:321) in /includes/common.inc on line 328.

I looked those up, and 328 is the header() command for drupal_goto(). The uc_file.pages.inc file only calls drupal_goto() at the end of a transfer, upon completion, redirects the user to their purchased-files page, which is where I think the issue stems from. I also think it only occurs when a user is using a download manager (which we allow, since some of our files are gigantic) and they are downloading from multiple IPs at once.

I noticed that the D5 version of uc_file actually never did this, and that explains why we're only seeing this since moving to D6.

Thoughts? I'm thinking of commenting that line out for now, but perhaps there's a better placement for the _uc_file_download_redirect() function in uc_file.pages.inc.

CommentFileSizeAuthor
#8 uc_file.pages_.inc_.redirect.patch378 bytestr

Comments

tr’s picture

Does this help? http://drupal.org/node/1424

Interestingly, uc_file.pages.inc has a blank line at the end, which is one of the stated causes in the book page.

torgospizza’s picture

Interesting thought, but I tried that and it didn't work. Removed the last two blank lines in uc_file.pages.inc, but I'm still receiving the exact same errors. The only time I hadn't seen any of these errors was after commenting out the call to redirect at the end of the transfer.

Interestingly, the log record for the header problem actually shows up before the record for the download ("User has started download of file") but I think this is simply the result of a race condition. (I could be wrong, of course.) (EDIT: The error is actually after the initial log for the download initiation. D'oh.)

tr’s picture

I'm seeing the same error with my file downloads. For me, the log record for the header problem shows up after the record for the download.

Out of curiosity, are you implementing hook_file_transfer_alter() ?

torgospizza’s picture

Ah you're right, it is after. Mea culpa.

Nope, we're not altering the transfer anywhere. This is straight OOTB uc_file.module's download transfer function.

tr’s picture

OK, well at least that narrows it down - it's not something I'm doing in my code :-) I'm not using a download manager, so that rules out the "only occurs when a user is using a download manager" theory.

However, I think you're on to something with the drupal_goto(). Curiously, the drupal_goto() doesn't do anything. Try it - instead of redirecting to user/%/purchased-files change the source code to redirect somewhere else. Nothing ever happens, the user will stay on user/%/purchased-files. This is because the MENU_CALLBACK is handling the GET request from the browser, and is sending the file in response with headers that indicate it's a download not a page to be displayed in the browser. There has been no request for a *normal* page, so having drupal_goto() generate http 302 headers to send to ?? doesn't make any sense. By the time drupal_goto() is called, the file download has already been flushed.

So I think commenting out drupal_goto() in _uc_file_download_redirect() is the way to go. I've done that on my test server and will watch to see if that eliminates the error message.

But it sure would be nice to have the ability to redirect at the end of the download - that's what I was trying to get working all day yesterday!

torgospizza’s picture

Yeah, it makes sense to redirect when a download is finished, but I'm not 100% sure there is any real way to do it the way the download is being handled. That's why there's also a disclaimer about the download totals only updating when you click but reloading the page gets you the actual values. Something like that.

I have had that line commented out for a while and the error has disappeared. It still doesn't help some of our DSL users getting their large files, but we're working on that :)

tr’s picture

I just discovered the PHP function headers_sent(), so I modified the uc_file code so that before calling drupal_goto() it first checks if it's too late to send the headers, and if it is too late then print out the headers (just for debugging) instead of calling drupal_goto():

--- uc_file.pages.inc.orig      Tue Jan  5 19:42:58 2010
+++ uc_file.pages.inc   Fri Jan  8 10:18:10 2010
@@ -356,6 +356,12 @@ function _uc_file_download_redirect($uid
   }
   // Redirect users back to their file page.
   else {
-    drupal_goto('user/'. $uid .'/purchased-files');
+    if (!headers_sent($filename, $linenumber)) {
+      drupal_goto('user/'. $uid .'/purchased-files');
+    }
+    else {
+      $headers = headers_list();
+      drupal_set_message('<pre>Headers sent from '. $filename .' on line number '. $linenumber .'</pre>');
+      drupal_set_message('<pre>Headers: '. print_r($headers, TRUE) .'</pre>');
+    }
   }
 }

The error in the original post disappears with this change because the headers have ALWAYS been sent at this point, so this check is equivalent to commenting out drupal_goto(). Basically, after the first print(fread($fp, UC_FILE_BYTE_SIZE)); in _uc_file_download_transfer() it's too late to send another header.

I think we can conclude the theory about drupal_goto() was right. It's too late to call it here, and it has no effect other than generating an error in the watchdog if it is called.

What should be the permanent fix? Is there any way at all to force a redirect after download? Maybe by adding another header early on? Or do we just comment out the drupal_goto() and forget about trying to redirect?

tr’s picture

Status: Active » Needs review
StatusFileSize
new378 bytes

The attached patch, developed in discussion with torgosPizza, checks to see if the headers have already been sent before calling drupal_goto(). This eliminates the error for both of us.

Island Usurper’s picture

Status: Needs review » Fixed

Yeah, a quick Google search didn't show me anything that could easily make a redirect happen after the file had been sent. Even if we tried to send the redirect header before the file data, I'm sure something would get confused because we're trying to serve a page and a file in the same request.

Committed.

tr’s picture

(I did test setting the Location header at the top of the file data, but as expected the browser just redirects, discarding everything that comes after the header. That behavior is not mandated by the HTTP spec, but in practice that's what happens with all browsers.)

hedac’s picture

for me when a user is trying to download a file same headers already sent message appears... but in line 315
uc_file.pages.inc:315
in my code Ubercart 2.2 line 315 is in flush();

              // Push the data to the client.
              print(fread($fp, UC_FILE_BYTE_SIZE));
line315 >  flush();
              ob_flush();
torgospizza’s picture

Did you try the patch from this issue?

hedac’s picture

I didn't apply the patch... I'm going to try the patch now
it's a minor issue since the file downloads correctly and the user can't see the error .. only the admin. but it would be better if it's done correctly.

I removed the last blank line of the file
now the error appears in line 335

hedac’s picture

ok the message doesn't appear now that I applied the patch at #8
sorry for the trouble :)
Thanks

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

j0rd’s picture

Still getting these errors for anonymous users downloading files

access denied 01.08.11 download/55/8dc918101a283d1fc3f4ee0d37a7d661 Anonymous
php 01.08.11 Cannot modify header information - headers ... Anonymous

ronsnow’s picture

Version: 6.x-2.x-dev » 7.x-3.0
Status: Closed (fixed) » Active

We need to be able to redirect the user after the download of the file. Effectively the above suggestion of commenting out the drupal_goto to avoid the watchdog error ignores that the redirect does not occur, nor do drupal set message because the page is not refreshed. To see drupal set messages, the user has to manually do a page refresh or bring up another web page.

Has anyone been able to fix this problem so that a redirect can occur to a target webpage after the download is complete. The problem is that the headers are set for the download file to occur. Is there a way to close off those headers for the download and re-establish headers for a webpage?

I have not found a solution after much searching.....

tr’s picture

Version: 7.x-3.0 » 6.x-2.x-dev
Status: Active » Closed (fixed)

This issue was about a specific bug which was fixed two years ago.

A new feature request should be opened if you want to help develop a redirect after download capability. (I think I eventually ended up doing that with jQuery.)