Skip to content

Local driver FsStream (/api/fs/put) fails with strconv.ParseInt error when Content-Length header is absent #9606

Description

@g2thub

Describe the bug

PUT /api/fs/put (used by the web UI's "create new file" button) fails with a 400 error whenever the incoming HTTP request does not carry an explicit Content-Length header (e.g. a zero-byte body sent without that header, or a request proxied through Cloudflare Tunnel / any reverse proxy that drops/transforms the header for empty bodies).

The error returned is:

{"code":400,"message":"strconv.ParseInt: parsing \"\": invalid syntax","data":null}

Root cause

In server/handles/fsup.go, FsStream reads the Content-Length header directly from gin.Context and parses it with strconv.ParseInt, with no fallback for a missing/empty header:

sizeStr := c.GetHeader("Content-Length")
size, err := strconv.ParseInt(sizeStr, 10, 64)
if err != nil {
    common.ErrorResp(c, err, 400)
    return
}

If Content-Length is not present (returns ""), strconv.ParseInt("", 10, 64) always fails, and the whole upload/create-file request is rejected with a generic parse error instead of falling back to c.Request.ContentLength (which Go's net/http already parses reliably, including for HTTP/2 requests where Content-Length is not delivered as a literal header at all) or defaulting to 0 for an empty body.

Steps to reproduce

  1. Run Alist (tested on v3.62.0 and v3.63.0, linux/arm64) with a Local storage mounted.
  2. Send a PUT request to /api/fs/put with a valid File-Path header and an empty body, but without an explicit Content-Length header, e.g.:
PUT /api/fs/put HTTP/1.1
Host: 127.0.0.1:5244
File-Path: /mydrive/test.txt
Authorization: <token>

  1. Observe the response:
{"code":400,"message":"strconv.ParseInt: parsing \"\": invalid syntax","data":null}
  1. This also reproduces reliably through Cloudflare Tunnel (cloudflared tunnel --url http://127.0.0.1:5244) when using the web UI's "New file" feature to create an empty file, because Cloudflare's HTTP/2-to-HTTP/1.1 proxying does not always forward a literal Content-Length: 0 header for the resulting request.

Uploading a file with actual content (non-zero body length) works fine in all cases, and creating a folder is unaffected. Only creating a new empty file via the web UI / raw API call without a Content-Length header is broken.

Expected behavior

Creating an empty file should succeed (treating a missing Content-Length as size 0), consistent with how folder creation behaves, and consistent with the fact that c.Request.ContentLength is already populated by Go's net/http/http2 stack independent of the literal header being present.

Suggested fix

Use c.Request.ContentLength instead of (or as a fallback for) parsing the header string, e.g.:

size := c.Request.ContentLength
if size < 0 {
    size = 0
}

Environment

  • Alist version: v3.62.0 and v3.63.0 (both reproduce)
  • OS/Arch: Debian 13 (trixie), linux/arm64
  • Storage driver: Local
  • Reverse proxy: reproduced both directly (raw TCP request without Content-Length) and through Cloudflare Tunnel (quick tunnel, http2 protocol)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions