这是indexloc提供的服务,不要输入任何密码
Skip to content

Missing header Content-Length in output of head handler #781

@hiddenmarten

Description

@hiddenmarten

Issue Summary

I created a simple HEAD handler using the Humago adapter that should return two headers: Content-Length and Last-Modified. However, when I make a HEAD request, only the Last-Modified header appears, while Content-Length is missing.

Code Example

Below is the complete code to reproduce the issue:

package main

import (
	"context"
	"fmt"
	"github.com/danielgtaylor/huma/v2/adapters/humago"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/danielgtaylor/huma/v2"
)

func main() {
	// Create a new API instance with a title and version.
	mux := http.NewServeMux()
	api := humago.New(mux, huma.DefaultConfig("Siben", "1.0.0"))

	// Register a HEAD endpoint at /files.
	huma.Head(api, "/files/{path...}", headHandler)

	// Start the server on port 8080.
	log.Fatal(http.ListenAndServe(":8080", mux))
}

// HeadInput represents the input for the HEAD request.
type HeadInput struct {
	Path string `path:"path"`
}

// HeadOutput represents the headers returned by the HEAD request.
type HeadOutput struct {
	ContentLength int64  `header:"Content-Length"`
	LastModified  string `header:"Last-Modified"`
}

func headHandler(ctx context.Context, in *HeadInput) (*HeadOutput, error) {
	// Open the file and retrieve file information.
	file, err := os.Open(in.Path)
	if err != nil {
		return nil, fmt.Errorf("failed to open file: %w", err)
	}
	stat, err := file.Stat()
	if err != nil {
		return nil, fmt.Errorf("failed to get file stat: %w", err)
	}

	return &HeadOutput{
		ContentLength: stat.Size(),
		LastModified:  stat.ModTime().Format(time.RFC3339),
	}, nil
}

Observed Behavior

When making a HEAD request (using curl -I), the response only includes the Last-Modified header:

└──╼ $ curl -I localhost:8080/files/custom-gcl
HTTP/1.1 204 No Content
Last-Modified: 2025-03-29T09:26:21+01:00
Date: Sat, 29 Mar 2025 12:32:22 GMT

Workaround

If I modify the model to use custom header names (e.g., prefixing with Custom-), both headers are returned as expected:

type HeadOutput struct {
	ContentLength int64  `header:"Custom-Content-Length"`
	LastModified  string `header:"Custom-Last-Modified"`
}

With this change, the response becomes:

└──╼ $ curl -I localhost:8080/files/custom-gcl
HTTP/1.1 204 No Content
Custom-Content-Length: 45213664
Custom-Last-Modified: 2025-03-29T09:26:21+01:00
Date: Sat, 29 Mar 2025 12:32:57 GMT

Request for Assistance

I have searched the code but have not found the cause of this behavior. Could someone help me understand why the Content-Length header is omitted unless a custom prefix is used? Once clarified, I'll raise a PR with the proposed fix.


Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions