[Bug]: SeekableHttpStream Relies on Connection Close Instead of Content-Length, Causing 60s Timeout
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 36.9k
- Forks
- 5.2k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 713
Description
⚠️ This issue respects the following points: ⚠️
- This is a bug, not a question or a configuration/webserver/proxy issue.
- This issue is not already reported on Github OR Nextcloud Community Forum (I've searched it).
- Nextcloud Server is up to date. See Maintenance and Release Schedule for supported versions.
- I agree to follow Nextcloud's Code of Conduct.
Bug description
When using Nextcloud with S3-compatible object storage that does not send the Connection: close HTTP header, all appdata file requests (avatars, previews, theming assets) experience a 60-second timeout before completing.
The issue occurs because Nextcloud's SeekableHttpStream wrapper relies on EOF (End-of-File) signals from the server to know when to stop reading. When the S3 provider sends all data but keeps the HTTP connection open (per HTTP/1.1 keep-alive default), PHP's feof() waits indefinitely for the server to close the connection. This eventually times out after default_socket_timeout (60 seconds by default).
What works:
- Regular file uploads/downloads via WebDAV (uses Sabre DAV in
3rdparty/with direct S3 streams that don't depend on connection close signal, not affected) - Object storage providers that send
Connection: closeheader (MinIO, AWS S3)
What doesn't work:
- Appdata file reads (avatars, previews, theming) from S3 providers without
Connection: closeheader
Root cause:
The SeekableHttpStream::stream_read() method calls fread($handle, $count) which can request more bytes than remain in the response (e.g., requesting 8192 bytes when only 84 bytes remain). When the server doesn't close the connection, fread() waits for the full $count bytes or timeout, whichever comes first.
Evidence:
Comparative HTTP response headers show that AWS S3 and MinIO include Connection: close, while some S3-compatible providers do not, resulting in the timeout behavior.
Steps to reproduce
- Configure Nextcloud to use S3-compatible object storage that does not send
Connection: closeheader in HTTP responses - Configure
'objectstore'inconfig/config.phpwith the S3 provider credentials - Access any appdata file via the web interface:
- Navigate to user avatar:
https://your-nextcloud/index.php/avatar/{username}/64 - Or access any page.
- Navigate to user avatar:
Expected behavior
Appdata files (avatars, previews, theming assets) should load instantly (under 1 second) regardless of whether the S3-compatible storage provider sends the Connection: close header or not.
The SeekableHttpStream wrapper should behave like Sabre DAV (in 3rdparty/) which calculates completion based on Content-Length and bytes read, rather than depending on the server to signal EOF via connection closure. This makes it compatible with all S3-compatible storage providers.
Nextcloud Server version
33
Operating system
None
PHP engine version
None
Web server
None
Database engine version
None
Is this bug present after an update or on a fresh install?
None
Are you using the Nextcloud Server Encryption module?
None
What user-backends are you using?
- Default user-backend (database)
- LDAP/ Active Directory
- SSO - SAML
- Other
Configuration report
List of activated Apps
Nextcloud Signing status
Nextcloud Logs
Additional info
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Locate the SeekableHttpStream implementation and inspect stream_read(), focusing on how fread() determines completion when Content-Length is available. Compare its behavior with the Sabre DAV streams in 3rdparty/, then reproduce with an appdata avatar or preview request against an S3-compatible provider that omits Connection: close. Done means appdata files load without waiting for the 60-second timeout.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 64/100