pktlineeditor

package
v1.35.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package pktlineeditor provides a streaming editor for manipulating Git pkt-line protocol responses.

The editor allows manipulation of pkt-line headers without buffering multi-gigabyte packfile bodies. It uses a two-phase streaming approach:

  1. Buffer and transform the pkt-line header section (typically <1 MB)
  2. Stream the binary body directly without buffering (potentially gigabytes)

Usage

Create a transformed reader:

reader, delta, err := pktlineeditor.TransformReader(
    responseBody,
    pktlineeditor.InjectCapability("packfile-uris"),
    nil, // use default options
)
if err != nil {
    log.Printf("transformation failed, using fallback: %v", err)
}
// Adjust Content-Length header if needed: newLength = originalLength + delta
io.Copy(output, reader) // always safe to read, even on error

Transform functions can be composed:

transform := pktlineeditor.Compose(
    pktlineeditor.InjectCapability("packfile-uris"),
    pktlineeditor.FilterLines(func(line []byte) bool {
        return bytes.HasPrefix(line, []byte("debug:"))
    }),
)
reader, delta, err := pktlineeditor.TransformReader(responseBody, transform, nil)

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidPktLineLength = errors.New("invalid pkt-line length")

ErrInvalidPktLineLength is returned when a pkt-line length is invalid.

View Source
var ErrInvalidPosition = errors.New("invalid position for line injection")

ErrInvalidPosition is returned when attempting to inject lines at an invalid position.

View Source
var ErrMaxSizeExceeded = errors.New("peek size exceeds maximum buffer size")

ErrMaxSizeExceeded is returned when a peek operation requests more bytes than the maximum allowed size.

Functions

func TransformReader

func TransformReader(source io.Reader, transformer TransformFunc, opts *Options) (io.Reader, int64, error)

TransformReader creates a new reader that transforms pkt-line headers while streaming the body. It parses the header section, applies the transformation, then returns a reader that streams the transformed header followed by the unchanged body.

The delta return value indicates the change in total stream size caused by the transformation, calculated as (newHeaderSize - originalHeaderSize). This can be used to adjust Content-Length headers in HTTP responses. On error or fallback to original stream, delta will be 0.

IMPORTANT: This function has non-standard behavior - it ALWAYS returns a valid io.Reader, even when an error occurs. On error, the returned reader will stream the original data (including any bytes already buffered by the parser). This allows graceful fallback to the original stream without data loss. Callers should check the error for logging/testing purposes, but can always safely read from the returned reader.

Types

type Options

type Options struct {
	MaxHeaderSize int64 // Maximum header size (default: 10 MB)
}

Options for configuring the pkt-line editor.

type PackfileURI

type PackfileURI struct {
	URI  string // The URI where the packfile can be fetched
	Hash string // The 40-character hexadecimal SHA-1 hash of the packfile
}

PackfileURI represents a packfile URI with its corresponding hash.

type Section

type Section struct {
	Name  string   // Section name (e.g., "shallow-info", "acknowledgments", "wanted-refs", "packfile-uris") - stored without newline
	Lines [][]byte // Lines in the section (WITH trailing newline if present in original data)
}

Section represents a Git protocol v2 response section. Each section has a name (e.g., "shallow-info", "acknowledgments") and lines of data.

type TransformFunc

type TransformFunc func(sections []Section, hasPackfileSection bool) ([]Section, error)

TransformFunc receives Git protocol v2 sections and returns transformed sections. Lines are represented as raw payloads WITHOUT pkt-line encoding. IMPORTANT: Lines preserve trailing newlines if present in the original data. When creating new lines, transformers should include trailing newlines to match Git protocol conventions.

The hasPackfileSection parameter indicates whether the response includes a packfile section. During negotiation, the server may not send a packfile (negotiation ongoing), so transforms should check this flag before injecting sections like packfile-uris.

func Compose

func Compose(transforms ...TransformFunc) TransformFunc

Compose combines multiple TransformFunc into a single function that applies them in sequence. Transformations are applied left-to-right. If any transformation returns an error, the composition stops and returns that error.

func FilterLines

func FilterLines(sectionName string, shouldRemove func([]byte) bool) TransformFunc

FilterLines returns a TransformFunc that removes lines matching a predicate from a specific section. The sectionName specifies which section to filter. The shouldRemove function returns true for lines that should be removed.

func InjectCapability

func InjectCapability(capability string) TransformFunc

InjectCapability returns a TransformFunc that adds a capability to info/refs response. The capability is injected into the first ref advertisement line that contains capabilities. Format: "<hash> <ref>\x00<capabilities>". nolint:gocognit

func InjectPackfileURIs

func InjectPackfileURIs(uris ...PackfileURI) TransformFunc

InjectPackfileURIs returns a TransformFunc that adds a packfile-uris section. The section is appended after existing sections and before the packfile section. If a packfile-uris section already exists, the new URIs are appended to it. If hasPackfileSection is false (negotiation ongoing), no injection occurs. Protocol v2 format:

  • Section header: "packfile-uris"
  • Each URI line: "<hash> <uri>" where hash is a 40-character hexadecimal SHA-1
  • Delimiter packet: 0001 (added automatically by serializeSections)

func RemovePackfileURIsSection

func RemovePackfileURIsSection() TransformFunc

RemovePackfileURIsSection returns a TransformFunc that removes the packfile-uris section if present.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL