nextcloud / nextcloud/server

[Bug]: SeekableHttpStream Relies on Connection Close Instead of Content-Length, Causing 60s Timeout

Open
#58,276 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

0. Needs triage 33-feedback bug feature: object storage performance 🚀
Dominant language
PHP
Stars
36.9k
Forks
5.2k
Avg merge
2d 3h
Merged PRs (30d)
713

Description

⚠️ This issue respects the following points: ⚠️
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: close header (MinIO, AWS S3)

What doesn't work:

  • Appdata file reads (avatars, previews, theming) from S3 providers without Connection: close header

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
  1. Configure Nextcloud to use S3-compatible object storage that does not send Connection: close header in HTTP responses
  2. Configure 'objectstore' in config/config.php with the S3 provider credentials
  3. Access any appdata file via the web interface:
    • Navigate to user avatar: https://your-nextcloud/index.php/avatar/{username}/64
    • Or access any page.
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.