mirror of
https://github.com/tailscale/tailscale.git
synced 2026-11-09 02:53:09 -05:00
Adds tsweb/compserve: content negotiation for precompressed static variants, with a transcode-to-identity fallback for clients that do not accept an encoding (including when the raw file is absent), and CompressWriter, which live-compresses dynamic responses with zstd in its fastest mode, streamed incrementally with no buffering. Negotiation is q-value and wildcard aware (gzip;q=0 previously matched gzip). client/web serves its prebuilt embedded assets through compserve, replacing brotli with zstd; the embedded FS is wrapped in tsweb/vcstime for conditional-request mod times. tsweb/compserve/gzip.go keeps transitional serving of gzip variants from pre-zstd file systems (such as the currently published web-client-prebuilt module): passthrough to gzip-accepting clients, transcoded to identity otherwise; it becomes inert once a zstd-only module is published. util/zstdframe gains pooled GetDecoder and GetStreamingEncoder (concurrency=1). util/precompress is now a build-time tool, generating zstd variants only. cmd/tsconnect and cmd/build-webclient consume the new precompress/compserve split. tsweb.AcceptsEncoding and tsweb/tswebutil are removed; negotiation lives in compserve and the deprecated shim had no callers. go.mod bumps web-client-prebuilt. Also fixes a transcoding bug where http.ServeContent's size probe via the promoted zstd.Decoder.WriteTo could report a zero length, serving empty bodies. Updates tailscale/corp#20099 Signed-off-by: James Tucker <james@tailscale.com>
44 lines
1.0 KiB
Go
44 lines
1.0 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package compserve
|
|
|
|
import (
|
|
"compress/gzip"
|
|
"io"
|
|
"io/fs"
|
|
)
|
|
|
|
// Gzip serves gzip-precompressed variants ("*.gz"). It exists for
|
|
// transitional compatibility with file systems built before zstd-only
|
|
// asset generation, such as web-client-prebuilt modules published before
|
|
// cmd/build-webclient stopped writing gzip; file systems built since
|
|
// contain no .gz variants and never select it.
|
|
var Gzip = Encoding{
|
|
Token: "gzip",
|
|
Ext: ".gz",
|
|
Decompress: decompressGzip,
|
|
}
|
|
|
|
// decompressGzip wraps f in a streaming gzip decompressor, taking
|
|
// ownership of f.
|
|
func decompressGzip(f fs.File) (io.ReadCloser, error) {
|
|
zr, err := gzip.NewReader(f)
|
|
if err != nil {
|
|
f.Close()
|
|
return nil, err
|
|
}
|
|
return &gzipFile{f: f, Reader: zr}, nil
|
|
}
|
|
|
|
// gzipFile is a gzip.Reader reading from f; Close closes both.
|
|
type gzipFile struct {
|
|
f fs.File
|
|
*gzip.Reader
|
|
}
|
|
|
|
func (g *gzipFile) Close() error {
|
|
g.Reader.Close()
|
|
return g.f.Close()
|
|
}
|