Repository: caddyserver/caddy
File: modules/caddyhttp/encode/zstd/zstd.go (Go)

Code before:
	}
}

// UnmarshalCaddyfile sets up the handler from Caddyfile tokens.
func (z *Zstd) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next() // consume option name
	if !d.NextArg() {
		return nil
	}
	levelStr := d.Val()
	if ok, _ := zstd.EncoderLevelFromString(levelStr); !ok {
		return d.Errf("unexpected compression level, use one of '%s', '%s', '%s', '%s'",
			zstd.SpeedFastest,
			zstd.SpeedDefault,
			zstd.SpeedBetterCompression,
			zstd.SpeedBestCompression,
		)
	}

	z.Level = levelStr
	return nil
}

// Provision provisions z's configuration.
func (z *Zstd) Provision(ctx caddy.Context) error {
	_, z.level = zstd.EncoderLevelFromString(z.Level)
	return nil
}

// AcceptEncoding returns the name of the encoding as
// used in the Accept-Encoding request headers.
func (Zstd) AcceptEncoding() string { return "zstd" }

// NewEncoder returns a new Zstandard writer.
func (z Zstd) NewEncoder() encode.Encoder {
	// The default of 8MB for the window is
	// too large for many clients, so we limit
	// it to 128K to lighten their load.
	writer, _ := zstd.NewWriter(
		nil,
		zstd.WithWindowSize(128<<10),
		zstd.WithEncoderConcurrency(1),
		zstd.WithZeroFrames(true),
		zstd.WithEncoderLevel(z.level),
	)
	return writer
}

// Interface guards
var (
	_ encode.Encoding       = (*Zstd)(nil)

Review comment (suggestion):
We actually need to check if the level is correct here. Power users will use JSON to configure caddy plugins.

We need to check if the level string is valid in 2 places, `UnmarshalCaddyfile` and `Provision`, or `Validate` if you prefer to implementing another interface.

Also there needs to be a default value in case it's not set.

Code after:
	return caddy.ModuleInfo{
		ID:  "http.encoders.zstd",
		New: func() caddy.Module { return new(Zstd) },
	}
}

// UnmarshalCaddyfile sets up the handler from Caddyfile tokens.
func (z *Zstd) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next() // consume option name
	if !d.NextArg() {
		return nil
	}
	levelStr := d.Val()
	if ok, _ := zstd.EncoderLevelFromString(levelStr); !ok {
		return d.Errf("unexpected compression level, use one of '%s', '%s', '%s', '%s'",
			zstd.SpeedFastest,
			zstd.SpeedBetterCompression,
			zstd.SpeedBestCompression,
			zstd.SpeedDefault,
		)
	}
	z.Level = levelStr
	return nil
}

// Provision provisions z's configuration.
func (z *Zstd) Provision(ctx caddy.Context) error {
	if z.Level == "" {
		z.Level = zstd.SpeedDefault.String()
	}
	var ok bool
	if ok, z.level = zstd.EncoderLevelFromString(z.Level); !ok {
		return fmt.Errorf("unexpected compression level, use one of '%s', '%s', '%s', '%s'",
			zstd.SpeedFastest,
			zstd.SpeedDefault,
			zstd.SpeedBetterCompression,
			zstd.SpeedBestCompression,
		)
	}
	return nil
}

// AcceptEncoding returns the name of the encoding as
// used in the Accept-Encoding request headers.
func (Zstd) AcceptEncoding() string { return "zstd" }

// NewEncoder returns a new Zstandard writer.
func (z Zstd) NewEncoder() encode.Encoder {
	// The default of 8MB for the window is
	// too large for many clients, so we limit
	// it to 128K to lighten their load.