Documentation
¶
Overview ¶
Package zstd writes RFC 8878 Zstandard frames, calculating cache metadata over the encoded representation while it is emitted, and reads them back.
Host Go uses github.com/klauspost/compress/zstd. TinyGo uses this package's own bounded encoder and decoder, which can also be selected on host Go with the shared force_tinygo_logic build tag. Both implementations expose the same API. The encoders calculate Result's SHA-256 digest over bytes successfully written and write nothing to the destination until the caller writes, flushes, or closes. The decoders accept any frame without a dictionary, report failures with the same errors, and refuse windows beyond WithMaxWindow, 8 MiB by default.
Writer and Reader are poolable through Reset, which is how the fasthttp fork in this repository compresses responses under TinyGo.
Index ¶
Examples ¶
Constants ¶
const ContentEncoding = "zstd"
ContentEncoding is the HTTP content-coding token for Zstandard.
Variables ¶
var ( // ErrClosed reports use of a Writer or Reader after Close. ErrClosed = errors.New("zstd: use after close") )
var ( // ErrCorrupt reports input that is not valid Zstandard: a bad magic // number, a malformed block, a match reaching outside the output, a // content size or checksum that does not match. Errors that wrap it say // where the input went wrong. Input that simply ends early is reported as // io.ErrUnexpectedEOF instead. ErrCorrupt = errors.New("zstd: corrupt input") // ErrWindowTooLarge reports a frame that declares a window larger than // the decoder accepts; see WithMaxWindow. It is checked before the frame // is decoded, so it costs no memory. ErrWindowTooLarge = errors.New("zstd: frame window exceeds the limit") // ErrOutputTooLarge reports content longer than WithMaxOutput allows. ErrOutputTooLarge = errors.New("zstd: decoded content exceeds the limit") // ErrDictionaryRequired reports a frame compressed against a dictionary, // which this package does not support. ErrDictionaryRequired = errors.New("zstd: frame requires a dictionary") )
Functions ¶
func DecodeAll ¶ added in v1.3.3
func DecodeAll(dst, src []byte, options ...DecoderOption) ([]byte, error)
DecodeAll decodes every frame in src and appends the content to dst. Skippable frames are skipped, and empty input decodes to nothing. On error, what the returned slice holds beyond dst is unspecified.
Example ¶
package main
import (
"fmt"
"github.com/shibukawa/tinygodriver/compress/zstd"
)
func main() {
encoded, _, err := zstd.EncodeAll([]byte("request body"))
if err != nil {
panic(err)
}
// Bound what a few bytes of untrusted input may expand to.
body, err := zstd.DecodeAll(nil, encoded, zstd.WithMaxOutput(1<<20))
if err != nil {
panic(err)
}
fmt.Println(string(body))
}
Output: request body
Types ¶
type DecoderOption ¶ added in v1.3.3
type DecoderOption interface {
// contains filtered or unexported methods
}
DecoderOption configures DecodeAll and NewReader.
func WithMaxOutput ¶ added in v1.3.3
func WithMaxOutput(n int64) DecoderOption
WithMaxOutput limits the decoded content to n bytes across all frames; longer content fails with ErrOutputTooLarge, after a Reader has returned the first n bytes. Zero, the default, sets no limit. Without one, a few kilobytes of input can decode to gigabytes, so set it for input from untrusted sources.
func WithMaxWindow ¶ added in v1.3.3
func WithMaxWindow(n int) DecoderOption
WithMaxWindow sets the largest window a frame may declare, from 1 KiB to 1 GiB. The default is 8 MiB, the limit RFC 9659 sets for HTTP. A Reader keeps up to twice the window in memory, so this is what bounds its footprint; a larger frame fails with ErrWindowTooLarge before it is decoded.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option configures both the host-Go and TinyGo encoders.
type Reader ¶ added in v1.3.3
type Reader struct {
// contains filtered or unexported fields
}
Reader decompresses a stream of Zstandard frames, skipping skippable ones. Reader is not safe for concurrent use.
func NewReader ¶ added in v1.3.3
func NewReader(r io.Reader, options ...DecoderOption) (*Reader, error)
NewReader returns a Reader that decompresses r. Unlike compress/gzip's NewReader it reads nothing until the first Read, so it cannot fail on the stream's content; it fails only on an invalid option. r may be nil, for a Reader that a pool will Reset before use; reading it first fails.
Example ¶
package main
import (
"bytes"
"fmt"
"io"
"github.com/shibukawa/tinygodriver/compress/zstd"
)
func main() {
encoded, _, err := zstd.EncodeAll([]byte("streamed body"))
if err != nil {
panic(err)
}
r, err := zstd.NewReader(bytes.NewReader(encoded))
if err != nil {
panic(err)
}
defer r.Close()
body, err := io.ReadAll(r)
if err != nil {
panic(err)
}
fmt.Println(string(body))
}
Output: streamed body
func (*Reader) Close ¶ added in v1.3.3
Close releases the Reader's decoder. It does not close the underlying reader. Read reports ErrClosed until Reset.
type Result ¶
Result describes an encoded representation. SHA256 covers exactly Size bytes written to the destination, including the Zstandard frame headers.
func EncodeAll ¶
EncodeAll encodes src, returning the frame and its cache metadata. The digest is produced while the frame is written; the encoded bytes are not traversed a second time.
Example ¶
package main
import (
"fmt"
"github.com/shibukawa/tinygodriver/compress/zstd"
)
func main() {
encoded, result, err := zstd.EncodeAll([]byte("response body"))
if err != nil {
panic(err)
}
fmt.Println(len(encoded) == int(result.Size))
fmt.Println(zstd.ContentEncoding)
}
Output: true zstd
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer emits one Zstandard frame through github.com/klauspost/compress/zstd. Writer is not safe for concurrent use. Close must succeed before Result can be read.
func NewWriter ¶
NewWriter starts a host-Go Zstandard stream. Constructing a Writer writes nothing to the destination, so an encoder built and then abandoned leaves the destination untouched. TinyGo and builds using the force_tinygo_logic tag select the bounded TinyGo encoder instead.
func (*Writer) Flush ¶ added in v1.0.4
Flush emits the buffered input as complete blocks so that everything written so far can be decoded, and returns once those bytes reach the destination. It does not end the frame and it does not flush the destination itself. Flushing before a block fills reduces the compression ratio.
func (*Writer) Reset ¶ added in v1.2.4
Reset starts a new frame writing to w, keeping the encoder and its window so that a pooled Writer does not rebuild them. The ETag setting chosen at NewWriter is retained, nothing reaches w until the caller writes, flushes, or closes, and a nil w leaves the Writer in the error state NewWriter would have reported.