I've run into a strange issue, and I'm at a loss as to my next steps in debugging. I'm hoping the community can pitch in some ideas.
I'm using the following stack:
PHP 7.2.34-21+ubuntu16.04.1+deb.sury.org+1 (fpm-fcgi) (built: May 1 2021 11:52:36)
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.34-21+ubuntu16.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies
Server version: Apache/2.4.39 (Ubuntu)
Wordpress 4.9.16
On AWS services. Obviously, there's some overhead due to the framework but I can dumb the code down to something along the lines of this :
// Framework stuff + file handling logic
$data = 'Imagine this is a 1000-byte binary message (pdf).';
// Headers, 335 bytes large
header('date: Sat, 03 Jul 2021 05:06:41 GMT');
header('server: Apache/2.4');
header('expires: Wed, 11 Jan 1984 05:00:00 GMT');
header('cache-control: no-cache, must-revalidate, max-age=0');
header('content-disposition: inline; filename=window-sticker.pdf');
header('strict-transport-security: max-age=1209600;');
header('content-length: 1000'); // Actually use strlen($data); for this
header('x-ua-compatible: IE=edge');
header('cache-control: public');
header('content-type: application/pdf');
echo $data;
exit();
Now here's the kicker. This works fine on a bunch of other sites, that as far as I can tell use the same apache sites-enabled
configuration and similar .htaccess
files. But it might still be a server/network/etc.. type error so I could be missing something.
I have this one site, however, where this code breaks in the following way:
- Tools that don't enforce
content-length
download/display this perfectly fine (chrome for instance). - Tools that do keep track of
content-length
fail or throw a notice (safari, curl). Curl gives me :
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7ff13c008200)
> GET /redacted/path/to/controller?p=abcdef HTTP/2
> Host: www.redacted-somesite.com
> User-Agent: curl/7.64.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
0 0 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0< HTTP/2 200
< date: Sun, 04 Jul 2021 17:36:24 GMT
< server: Apache/2.4
< expires: Wed, 11 Jan 1984 05:00:00 GMT
< cache-control: no-cache, must-revalidate, max-age=0
< content-disposition: inline; filename=window-sticker.pdf
< strict-transport-security: max-age=1209600;
< content-length: 1000
< x-ua-compatible: IE=edge
< cache-control: public
< content-type: application/pdf
<
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* stopped the pause stream!
0 1000 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0
* Connection #0 to host www.redacted-somesite.com left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* Closing connection 0
Things I have checked:
- The content length IS correctly set, the body is the same size as what is set in that header.
- The data IS being output since tools like chrome can get the full file
- Removing the
content-length
header makes this work in all tools.
And here we are, I'm not sure why things are failing. My current theory is that somehow, for this site some silent error might be writing to the buffer before the headers are sent out. But when I check the binary data sent from the server in a hex tool, it's an exact match.. So I'm at a loss. Maybe there's some compression layer screwing with me?
Any ideas would be amazing.
Thanks!