Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Bug] Range Request failure causes context canceled errors during tar.gz downloads #35302

Closed
Labels
@younsl

Description

Description

Summary

.tar.gz files (as small as 12MB) fail to download from Gitea release pages due to HTTP Range Request handling issues. The download succeeds initially (206 Partial Content) but immediately fails on subsequent chunks with "context canceled" error, resulting in 401 Unauthorized responses.

Environment

  • Gitea Version: v1.24.2-rootless
  • Platform: Kubernetes (EKS 1.32)
  • Deployment: Helm chart
  • Database: PostgreSQL HA
  • Cache: Valkey (Redis compatible)
  • Load Balancer: AWS NLB with SSL termination
  • Authentication: Username/Password (no OAuth)

Expected Behavior

.tar.gz files should download completely without interruption when accessed through release download URLs, regardless of size.

Actual Behavior

  1. Browser initiates HTTP Range Request for .tar.gz files (12MB in this case)
  2. First chunk downloads successfully (206 Partial Content, ~190ms)
  3. Within 10-30ms, subsequent chunk requests fail with "context canceled"
  4. Session verification fails → 401 Unauthorized response (~7ms)
  5. Download fails in browser with "Network Error"
  6. Multiple retries eventually succeed (sometimes after 3-5 minutes)

Reproduction Steps

  1. Create a release with a .tar.gz file (12MB in this case)
  2. Navigate to release page in Chrome/Edge browser
  3. Click download link for .tar.gz file
  4. Observe download failure in browser
  5. Check Gitea logs for "GetUserByID: context canceled" errors

Log Evidence

Pattern 1: First failure (07:59:01)

2025年08月18日T07:59:01.290779720Z gitea 2025年08月18日 07:59:01 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.1:18329, 206 Partial Content in 192.5ms @ repo/repo.go:318(repo.RedirectDownload)
2025年08月18日T07:59:01.320181025Z gitea 2025年08月18日 07:59:01 services/auth/session.go:51:(*Session).Verify() [E] GetUserByID: context canceled
2025年08月18日T07:59:01.320228848Z gitea 2025年08月18日 07:59:01 routers/web/web.go:121:Routes.webAuth.10() [E] Failed to verify user: context canceled
2025年08月18日T07:59:01.322235910Z gitea 2025年08月18日 07:59:01 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.1:18329, 401 Unauthorized in 6.8ms @ web/web.go:118(web.Routes.webAuth)

Pattern 2: Second retry failure (07:59:12)

2025年08月18日T07:59:12.250175593Z gitea 2025年08月18日 07:59:12 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.2:57323, 206 Partial Content in 193.7ms @ repo/repo.go:318(repo.RedirectDownload)
2025年08月18日T07:59:12.262348544Z gitea 2025年08月18日 07:59:12 services/auth/session.go:51:(*Session).Verify() [E] GetUserByID: context canceled
2025年08月18日T07:59:12.262387879Z gitea 2025年08月18日 07:59:12 routers/web/web.go:121:Routes.webAuth.10() [E] Failed to verify user: context canceled
2025年08月18日T07:59:12.264366790Z gitea 2025年08月18日 07:59:12 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.2:57323, 401 Unauthorized in 6.8ms @ web/web.go:118(web.Routes.webAuth)

Pattern 3: Third retry failure (08:01:17)

2025年08月18日T08:01:17.477449999Z gitea 2025年08月18日 08:01:17 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.3:3633, 206 Partial Content in 189.9ms @ repo/repo.go:318(repo.RedirectDownload)
2025年08月18日T08:01:17.488702742Z gitea 2025年08月18日 08:01:17 services/auth/session.go:51:(*Session).Verify() [E] GetUserByID: context canceled
2025年08月18日T08:01:17.488750103Z gitea 2025年08月18日 08:01:17 routers/web/web.go:121:Routes.webAuth.10() [E] Failed to verify user: context canceled
2025年08月18日T08:01:17.491089433Z gitea 2025年08月18日 08:01:17 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.3:3633, 401 Unauthorized in 6.6ms @ web/web.go:118(web.Routes.webAuth)

Pattern 4: Final success (08:03:06)

In this case, Browser switches from Range Request (206 Partial Content) to normal download (200 OK) and succeeds. Subsequent requests are cached (304 Not Modified).

2025年08月18日T08:03:06.000000000Z gitea 2025年08月18日 08:03:06 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.1:46502, 200 OK in 1051.9ms @ repo/repo.go:318(repo.RedirectDownload)
2025年08月18日T08:03:47.000000000Z gitea 2025年08月18日 08:03:47 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.2:24190, 304 Not Modified in 193.4ms @ repo/repo.go:318(repo.RedirectDownload)
2025年08月18日T08:04:33.000000000Z gitea 2025年08月18日 08:04:33 HTTPRequest [I] router: completed GET /OrgName/repo_name/releases/download/v1.0.35/build-artifacts-v1.0.35.tar.gz for 10.0.0.2:24190, 304 Not Modified in 196.4ms @ repo/repo.go:318(repo.RedirectDownload)

HTTP Request Type Analysis

Range Request vs Normal Request identification:

  • Range Request (partial download): Response code 206 Partial Content

    • Browser sends Range: bytes=0-1048575 header
    • Server responds with partial file content
    • Used by browsers for large files to enable resume capability
  • Normal Request (full download): Response code 200 OK

    • No Range header sent
    • Server responds with complete file
    • Traditional single-request download

Failure Pattern: 206 Partial Contentcontext canceled401 Unauthorized
Success Pattern: 200 OK (browser fallback to normal download after Range Request failures)

Timeline Summary

07:59:01 - tar.gz download failure (Range Request: 206 Partial Content → 401 Unauthorized)
07:59:12 - tar.gz retry failure (Range Request: 206 Partial Content → 401 Unauthorized) 
08:01:17 - tar.gz download failure (Range Request: 206 Partial Content → 401 Unauthorized)
08:03:06 - tar.gz download success (Normal Request: 200 OK, 1051ms)
08:03:47~08:04:33 - cached responses (304 Not Modified)

Key observations:

  • Consistent timing: Each failure follows the same pattern - 206 response (~190ms) → context canceled (~10ms later) → 401 response (~7ms)
  • Different client IPs: 10.0.0.1, 10.0.0.2, 10.0.0.3 (indicating different browser sessions/connections)
  • Eventually succeeds: After multiple failures, download works with 200 OK status

Root Cause Analysis

The issue appears to be in the session verification middleware at services/auth/session.go:51.

Sequence of events:

  1. Browser sends Range Request: Range: bytes=0-1048575
  2. Gitea responds with 206 Partial Content (first chunk)
  3. Browser immediately sends next Range Request: Range: bytes=1048576-2097151
  4. Problem: The HTTP context from the first request is already canceled
  5. GetUserByID is called with canceled context → "context canceled" error
  6. Session verification fails → 401 Unauthorized

Why only .tar.gz files?

  • Browser automatically uses Range Requests for compressed files (even as small as 12MB)
  • ZIP files may have different MIME handling
  • Other file types may not trigger Range Request behavior

Root cause hypothesis:
Gitea appears to prematurely terminate the HTTP context after responding to the first HTTP Range Request chunk (206 Partial Content), causing subsequent Range Request chunks to fail session verification when GetUserByID is called with an already-canceled context. This context lifecycle management issue specifically affects HTTP Range Request handling, explaining why normal requests (200 OK) succeed while Range Requests consistently fail at the session middleware level.

Affected Code

The error occurs in session verification:

// services/auth/session.go:51
user, err := user_model.GetUserByID(ctx, sess.Get("uid").(int64))
if err != nil {
 // Return the err as-is to keep current signed-in session, in case the err is something like context.Canceled
 if !user_model.IsErrUserNotExist(err) {
 log.Error("GetUserByID: %v", err) // ← This logs "context canceled"
 return nil, err
 }
}

Additional Context

  • Issue is specific to rootless Gitea image
  • Problem occurs with NLB direct access (no ingress controller)
  • Related to context lifecycle management in HTTP Range Request handling
  • Multiple successful downloads eventually work after retries

Related Issues

This appears to be related to but distinct from:

The specific combination of HTTP Range Request + Context Cancellation + Session Verification seems to be a unique case not covered by existing issues.

Suggested Fix

Consider implementing proper context handling for HTTP Range Requests in the session verification middleware, ensuring that each Range Request gets its own valid context rather than inheriting a potentially canceled context from previous requests.

Gitea Version

v1.24.2-rootless

Can you reproduce the bug on the Gitea demo site?

No

Log Gist

No response

Screenshots

No response

Git Version

No response

Operating System

Amazon Linux 2023年8月20日250721 (amd64)

How are you running Gitea?

Official gitea helm chart v12.3.1 on EKS v1.32

Database

PostgreSQL

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

        AltStyle によって変換されたページ (->オリジナル) /