Merge branch 'public-single-node' into pmm-6401-read-prometheus-data-files
|
@ -2,39 +2,70 @@ package remote_read_integration
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/prometheus"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/native/stream"
|
||||
parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/vmimport"
|
||||
)
|
||||
|
||||
// LabelValues represents series from api/v1/series response
|
||||
type LabelValues map[string]string
|
||||
|
||||
// Response represents response from api/v1/series
|
||||
type Response struct {
|
||||
Status string `json:"status"`
|
||||
Series []LabelValues `json:"data"`
|
||||
}
|
||||
|
||||
// RemoteWriteServer represents fake remote write server with database
|
||||
type RemoteWriteServer struct {
|
||||
server *httptest.Server
|
||||
series []vm.TimeSeries
|
||||
server *httptest.Server
|
||||
series []vm.TimeSeries
|
||||
expectedSeries []vm.TimeSeries
|
||||
}
|
||||
|
||||
// NewRemoteWriteServer prepares test remote write server
|
||||
func NewRemoteWriteServer(t *testing.T) *RemoteWriteServer {
|
||||
rws := &RemoteWriteServer{series: make([]vm.TimeSeries, 0)}
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/api/v1/import", rws.getWriteHandler(t))
|
||||
mux.Handle("/health", rws.handlePing())
|
||||
mux.Handle("/api/v1/series", rws.seriesHandler())
|
||||
mux.Handle("/api/v1/export/native", rws.exportNativeHandler())
|
||||
mux.Handle("/api/v1/import/native", rws.importNativeHandler(t))
|
||||
rws.server = httptest.NewServer(mux)
|
||||
return rws
|
||||
}
|
||||
|
||||
// Close closes the server.
|
||||
// Close closes the server
|
||||
func (rws *RemoteWriteServer) Close() {
|
||||
rws.server.Close()
|
||||
}
|
||||
|
||||
func (rws *RemoteWriteServer) ExpectedSeries(series []vm.TimeSeries) {
|
||||
// Series saves generated series for fake database
|
||||
func (rws *RemoteWriteServer) Series(series []vm.TimeSeries) {
|
||||
rws.series = append(rws.series, series...)
|
||||
}
|
||||
|
||||
// ExpectedSeries saves expected results to check in the handler
|
||||
func (rws *RemoteWriteServer) ExpectedSeries(series []vm.TimeSeries) {
|
||||
rws.expectedSeries = append(rws.expectedSeries, series...)
|
||||
}
|
||||
|
||||
// URL returns server url
|
||||
func (rws *RemoteWriteServer) URL() string {
|
||||
return rws.server.URL
|
||||
}
|
||||
|
@ -68,13 +99,14 @@ func (rws *RemoteWriteServer) getWriteHandler(t *testing.T) http.Handler {
|
|||
rows.Reset()
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tss, rws.series) {
|
||||
if !reflect.DeepEqual(tss, rws.expectedSeries) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Fatalf("datasets not equal, expected: %#v; \n got: %#v", rws.series, tss)
|
||||
t.Fatalf("datasets not equal, expected: %#v; \n got: %#v", rws.expectedSeries, tss)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -84,3 +116,146 @@ func (rws *RemoteWriteServer) handlePing() http.Handler {
|
|||
_, _ = w.Write([]byte("OK"))
|
||||
})
|
||||
}
|
||||
|
||||
func (rws *RemoteWriteServer) seriesHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var labelValues []LabelValues
|
||||
for _, ser := range rws.series {
|
||||
metricNames := make(LabelValues)
|
||||
if ser.Name != "" {
|
||||
metricNames["__name__"] = ser.Name
|
||||
}
|
||||
for _, p := range ser.LabelPairs {
|
||||
metricNames[p.Name] = p.Value
|
||||
}
|
||||
labelValues = append(labelValues, metricNames)
|
||||
}
|
||||
|
||||
resp := Response{
|
||||
Status: "success",
|
||||
Series: labelValues,
|
||||
}
|
||||
|
||||
err := json.NewEncoder(w).Encode(resp)
|
||||
if err != nil {
|
||||
log.Printf("error send series: %s", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (rws *RemoteWriteServer) exportNativeHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
now := time.Now()
|
||||
err := prometheus.ExportNativeHandler(now, w, r)
|
||||
if err != nil {
|
||||
log.Printf("error export series via native protocol: %s", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func (rws *RemoteWriteServer) importNativeHandler(t *testing.T) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
common.StartUnmarshalWorkers()
|
||||
defer common.StopUnmarshalWorkers()
|
||||
|
||||
var gotTimeSeries []vm.TimeSeries
|
||||
|
||||
err := stream.Parse(r.Body, false, func(block *stream.Block) error {
|
||||
mn := &block.MetricName
|
||||
var timeseries vm.TimeSeries
|
||||
timeseries.Name = string(mn.MetricGroup)
|
||||
timeseries.Timestamps = append(timeseries.Timestamps, block.Timestamps...)
|
||||
timeseries.Values = append(timeseries.Values, block.Values...)
|
||||
|
||||
for i := range mn.Tags {
|
||||
tag := &mn.Tags[i]
|
||||
timeseries.LabelPairs = append(timeseries.LabelPairs, vm.LabelPair{
|
||||
Name: string(tag.Key),
|
||||
Value: string(tag.Value),
|
||||
})
|
||||
}
|
||||
|
||||
gotTimeSeries = append(gotTimeSeries, timeseries)
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("error parse stream blocks: %s", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// got timeseries should be sorted
|
||||
// because they are processed independently
|
||||
sort.SliceStable(gotTimeSeries, func(i, j int) bool {
|
||||
iv, jv := gotTimeSeries[i], gotTimeSeries[j]
|
||||
switch {
|
||||
case iv.Values[0] != jv.Values[0]:
|
||||
return iv.Values[0] < jv.Values[0]
|
||||
case iv.Timestamps[0] != jv.Timestamps[0]:
|
||||
return iv.Timestamps[0] < jv.Timestamps[0]
|
||||
default:
|
||||
return iv.Name < jv.Name
|
||||
}
|
||||
})
|
||||
|
||||
if !reflect.DeepEqual(gotTimeSeries, rws.expectedSeries) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Fatalf("datasets not equal, expected: %#v;\n got: %#v", rws.expectedSeries, gotTimeSeries)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// GenerateVNSeries generates test timeseries
|
||||
func GenerateVNSeries(start, end, numOfSeries, numOfSamples int64) []vm.TimeSeries {
|
||||
var ts []vm.TimeSeries
|
||||
j := 0
|
||||
for i := 0; i < int(numOfSeries); i++ {
|
||||
if i%3 == 0 {
|
||||
j++
|
||||
}
|
||||
|
||||
timeSeries := vm.TimeSeries{
|
||||
Name: fmt.Sprintf("vm_metric_%d", j),
|
||||
LabelPairs: []vm.LabelPair{
|
||||
{Name: "job", Value: strconv.Itoa(i)},
|
||||
},
|
||||
}
|
||||
|
||||
ts = append(ts, timeSeries)
|
||||
}
|
||||
|
||||
for i := range ts {
|
||||
t, v := generateTimeStampsAndValues(i, start, end, numOfSamples)
|
||||
ts[i].Timestamps = t
|
||||
ts[i].Values = v
|
||||
}
|
||||
|
||||
return ts
|
||||
}
|
||||
|
||||
func generateTimeStampsAndValues(idx int, startTime, endTime, numOfSamples int64) ([]int64, []float64) {
|
||||
delta := (endTime - startTime) / numOfSamples
|
||||
|
||||
var timestamps []int64
|
||||
var values []float64
|
||||
t := startTime
|
||||
for t != endTime {
|
||||
v := 100 * int64(idx)
|
||||
timestamps = append(timestamps, t*1000)
|
||||
values = append(values, float64(v))
|
||||
t = t + delta
|
||||
}
|
||||
|
||||
return timestamps, values
|
||||
}
|
||||
|
|
|
@ -2,118 +2,295 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/backoff"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/native"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/stepper"
|
||||
remote_read_integration "github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/testdata/servers_integration_test"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmctl/vm"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/promql"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmstorage"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
|
||||
)
|
||||
|
||||
// If you want to run this test:
|
||||
// 1. run two instances of victoriametrics and define -httpListenAddr for both or just for second instance
|
||||
// 2. define srcAddr and dstAddr const with your victoriametrics addresses
|
||||
// 3. define matchFilter const with your importing data
|
||||
// 4. define timeStartFilter
|
||||
// 5. run each test one by one
|
||||
|
||||
const (
|
||||
matchFilter = `{job="avalanche"}`
|
||||
timeStartFilter = "2020-01-01T20:07:00Z"
|
||||
timeEndFilter = "2020-08-01T20:07:00Z"
|
||||
srcAddr = "http://127.0.0.1:8428"
|
||||
dstAddr = "http://127.0.0.1:8528"
|
||||
storagePath = "TestStorage"
|
||||
retentionPeriod = "100y"
|
||||
)
|
||||
|
||||
// This test simulates close process if user abort it
|
||||
func Test_vmNativeProcessor_run(t *testing.T) {
|
||||
t.Skip()
|
||||
|
||||
processFlags()
|
||||
vmstorage.Init(promql.ResetRollupResultCacheIfNeeded)
|
||||
defer func() {
|
||||
vmstorage.Stop()
|
||||
if err := os.RemoveAll(storagePath); err != nil {
|
||||
log.Fatalf("cannot remove %q: %s", storagePath, err)
|
||||
}
|
||||
}()
|
||||
|
||||
type fields struct {
|
||||
filter native.Filter
|
||||
rateLimit int64
|
||||
dst *native.Client
|
||||
src *native.Client
|
||||
filter native.Filter
|
||||
dst *native.Client
|
||||
src *native.Client
|
||||
backoff *backoff.Backoff
|
||||
s *stats
|
||||
rateLimit int64
|
||||
interCluster bool
|
||||
cc int
|
||||
matchName string
|
||||
matchValue string
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
silent bool
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
closer func(cancelFunc context.CancelFunc)
|
||||
wantErr bool
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
vmSeries func(start, end, numOfSeries, numOfSamples int64) []vm.TimeSeries
|
||||
expectedSeries []vm.TimeSeries
|
||||
start string
|
||||
end string
|
||||
numOfSamples int64
|
||||
numOfSeries int64
|
||||
chunk string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "simulate syscall.SIGINT",
|
||||
name: "step minute on minute time range",
|
||||
start: "2022-11-25T11:23:05+02:00",
|
||||
end: "2022-11-27T11:24:05+02:00",
|
||||
numOfSamples: 2,
|
||||
numOfSeries: 3,
|
||||
chunk: stepper.StepMinute,
|
||||
fields: fields{
|
||||
filter: native.Filter{
|
||||
Match: matchFilter,
|
||||
TimeStart: timeStartFilter,
|
||||
filter: native.Filter{},
|
||||
backoff: backoff.New(),
|
||||
rateLimit: 0,
|
||||
interCluster: false,
|
||||
cc: 1,
|
||||
matchName: "__name__",
|
||||
matchValue: ".*",
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
silent: true,
|
||||
},
|
||||
vmSeries: remote_read_integration.GenerateVNSeries,
|
||||
expectedSeries: []vm.TimeSeries{
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "0"}},
|
||||
Timestamps: []int64{1669368185000, 1669454615000},
|
||||
Values: []float64{0, 0},
|
||||
},
|
||||
rateLimit: 0,
|
||||
dst: &native.Client{
|
||||
Addr: dstAddr,
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "1"}},
|
||||
Timestamps: []int64{1669368185000, 1669454615000},
|
||||
Values: []float64{100, 100},
|
||||
},
|
||||
src: &native.Client{
|
||||
Addr: srcAddr,
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "2"}},
|
||||
Timestamps: []int64{1669368185000, 1669454615000},
|
||||
Values: []float64{200, 200},
|
||||
},
|
||||
},
|
||||
closer: func(cancelFunc context.CancelFunc) {
|
||||
time.Sleep(time.Second * 5)
|
||||
cancelFunc()
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "simulate correct work",
|
||||
fields: fields{
|
||||
filter: native.Filter{
|
||||
Match: matchFilter,
|
||||
TimeStart: timeStartFilter,
|
||||
},
|
||||
rateLimit: 0,
|
||||
dst: &native.Client{
|
||||
Addr: dstAddr,
|
||||
},
|
||||
src: &native.Client{
|
||||
Addr: srcAddr,
|
||||
},
|
||||
},
|
||||
closer: func(cancelFunc context.CancelFunc) {},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "simulate correct work with chunking",
|
||||
name: "step month on month time range",
|
||||
start: "2022-09-26T11:23:05+02:00",
|
||||
end: "2022-11-26T11:24:05+02:00",
|
||||
numOfSamples: 2,
|
||||
numOfSeries: 3,
|
||||
chunk: stepper.StepMonth,
|
||||
fields: fields{
|
||||
filter: native.Filter{
|
||||
Match: matchFilter,
|
||||
TimeStart: timeStartFilter,
|
||||
TimeEnd: timeEndFilter,
|
||||
Chunk: stepper.StepMonth,
|
||||
filter: native.Filter{},
|
||||
backoff: backoff.New(),
|
||||
rateLimit: 0,
|
||||
interCluster: false,
|
||||
cc: 1,
|
||||
matchName: "__name__",
|
||||
matchValue: ".*",
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
silent: true,
|
||||
},
|
||||
vmSeries: remote_read_integration.GenerateVNSeries,
|
||||
expectedSeries: []vm.TimeSeries{
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "0"}},
|
||||
Timestamps: []int64{1664184185000},
|
||||
Values: []float64{0},
|
||||
},
|
||||
rateLimit: 0,
|
||||
dst: &native.Client{
|
||||
Addr: dstAddr,
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "0"}},
|
||||
Timestamps: []int64{1666819415000},
|
||||
Values: []float64{0},
|
||||
},
|
||||
src: &native.Client{
|
||||
Addr: srcAddr,
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "1"}},
|
||||
Timestamps: []int64{1664184185000},
|
||||
Values: []float64{100},
|
||||
},
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "1"}},
|
||||
Timestamps: []int64{1666819415000},
|
||||
Values: []float64{100},
|
||||
},
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "2"}},
|
||||
Timestamps: []int64{1664184185000},
|
||||
Values: []float64{200},
|
||||
},
|
||||
{
|
||||
Name: "vm_metric_1",
|
||||
LabelPairs: []vm.LabelPair{{Name: "job", Value: "2"}},
|
||||
Timestamps: []int64{1666819415000},
|
||||
Values: []float64{200},
|
||||
},
|
||||
},
|
||||
closer: func(cancelFunc context.CancelFunc) {},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx, cancelFn := context.WithCancel(context.Background())
|
||||
p := &vmNativeProcessor{
|
||||
filter: tt.fields.filter,
|
||||
rateLimit: tt.fields.rateLimit,
|
||||
dst: tt.fields.dst,
|
||||
src: tt.fields.src,
|
||||
src := remote_read_integration.NewRemoteWriteServer(t)
|
||||
dst := remote_read_integration.NewRemoteWriteServer(t)
|
||||
|
||||
defer func() {
|
||||
src.Close()
|
||||
dst.Close()
|
||||
}()
|
||||
|
||||
start, err := time.Parse(time.RFC3339, tt.start)
|
||||
if err != nil {
|
||||
t.Fatalf("Error parse start time: %s", err)
|
||||
}
|
||||
|
||||
tt.closer(cancelFn)
|
||||
end, err := time.Parse(time.RFC3339, tt.end)
|
||||
if err != nil {
|
||||
t.Fatalf("Error parse end time: %s", err)
|
||||
}
|
||||
|
||||
if err := p.run(ctx, true); (err != nil) != tt.wantErr {
|
||||
tt.fields.filter.Match = fmt.Sprintf("%s=%q", tt.fields.matchName, tt.fields.matchValue)
|
||||
tt.fields.filter.TimeStart = tt.start
|
||||
tt.fields.filter.TimeEnd = tt.end
|
||||
|
||||
rws := tt.vmSeries(start.Unix(), end.Unix(), tt.numOfSeries, tt.numOfSamples)
|
||||
|
||||
src.Series(rws)
|
||||
dst.ExpectedSeries(tt.expectedSeries)
|
||||
|
||||
if err := fillStorage(rws); err != nil {
|
||||
t.Fatalf("error add series to storage: %s", err)
|
||||
}
|
||||
|
||||
tt.fields.src = &native.Client{
|
||||
AuthCfg: nil,
|
||||
Addr: src.URL(),
|
||||
ExtraLabels: []string{},
|
||||
DisableHTTPKeepAlive: false,
|
||||
}
|
||||
tt.fields.dst = &native.Client{
|
||||
AuthCfg: nil,
|
||||
Addr: dst.URL(),
|
||||
ExtraLabels: []string{},
|
||||
DisableHTTPKeepAlive: false,
|
||||
}
|
||||
|
||||
p := &vmNativeProcessor{
|
||||
filter: tt.fields.filter,
|
||||
dst: tt.fields.dst,
|
||||
src: tt.fields.src,
|
||||
backoff: tt.fields.backoff,
|
||||
s: tt.fields.s,
|
||||
rateLimit: tt.fields.rateLimit,
|
||||
interCluster: tt.fields.interCluster,
|
||||
cc: tt.fields.cc,
|
||||
}
|
||||
|
||||
if err := p.run(tt.args.ctx, tt.args.silent); (err != nil) != tt.wantErr {
|
||||
t.Errorf("run() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
deleted, err := deleteSeries(tt.fields.matchName, tt.fields.matchValue)
|
||||
if err != nil {
|
||||
t.Fatalf("error delete series: %s", err)
|
||||
}
|
||||
if int64(deleted) != tt.numOfSeries {
|
||||
t.Fatalf("expected deleted series %d; got deleted series %d", tt.numOfSeries, deleted)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func processFlags() {
|
||||
flag.Parse()
|
||||
for _, fv := range []struct {
|
||||
flag string
|
||||
value string
|
||||
}{
|
||||
{flag: "storageDataPath", value: storagePath},
|
||||
{flag: "retentionPeriod", value: retentionPeriod},
|
||||
} {
|
||||
// panics if flag doesn't exist
|
||||
if err := flag.Lookup(fv.flag).Value.Set(fv.value); err != nil {
|
||||
log.Fatalf("unable to set %q with value %q, err: %v", fv.flag, fv.value, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fillStorage(series []vm.TimeSeries) error {
|
||||
var mrs []storage.MetricRow
|
||||
for _, series := range series {
|
||||
var labels []prompb.Label
|
||||
for _, lp := range series.LabelPairs {
|
||||
labels = append(labels, prompb.Label{Name: []byte(lp.Name), Value: []byte(lp.Value)})
|
||||
}
|
||||
if series.Name != "" {
|
||||
labels = append(labels, prompb.Label{Name: []byte("__name__"), Value: []byte(series.Name)})
|
||||
}
|
||||
mr := storage.MetricRow{}
|
||||
mr.MetricNameRaw = storage.MarshalMetricNameRaw(mr.MetricNameRaw[:0], labels)
|
||||
|
||||
timestamps := series.Timestamps
|
||||
values := series.Values
|
||||
for i, value := range values {
|
||||
mr.Timestamp = timestamps[i]
|
||||
mr.Value = value
|
||||
mrs = append(mrs, mr)
|
||||
}
|
||||
}
|
||||
|
||||
if err := vmstorage.AddRows(mrs); err != nil {
|
||||
return fmt.Errorf("unexpected error in AddRows: %s", err)
|
||||
}
|
||||
vmstorage.Storage.DebugFlush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteSeries(name, value string) (int, error) {
|
||||
tfs := storage.NewTagFilters()
|
||||
if err := tfs.Add([]byte(name), []byte(value), false, true); err != nil {
|
||||
return 0, fmt.Errorf("unexpected error in TagFilters.Add: %w", err)
|
||||
}
|
||||
return vmstorage.DeleteSeries(nil, []*storage.TagFilters{tfs})
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ The following tip changes can be tested by building VictoriaMetrics components f
|
|||
|
||||
## tip
|
||||
|
||||
* FEATURE: log metrics with truncated labels if the length of label value in the ingested metric exceeds `-maxLabelValueLen`. This should simplify debugging for this case.
|
||||
|
||||
## [v1.89.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.89.1)
|
||||
|
||||
Released at 2023-03-12
|
||||
|
|
|
@ -13,3 +13,4 @@ sort: 26
|
|||
7. [Multi-regional setup with VictoriaMetrics: Dedicated regions for monitoring](https://docs.victoriametrics.com/guides/multi-regional-setup-dedicated-regions.html)
|
||||
8. [How to delete or replace metrics in VictoriaMetrics](https://docs.victoriametrics.com/guides/guide-delete-or-replace-metrics.html)
|
||||
9. [How to monitor kubernetes cluster using Managed VictoriaMetrics](https://docs.victoriametrics.com/managed-victoriametrics/how-to-monitor-k8s.html)
|
||||
10. [How to configure vmgateway for multi-tenant access using Grafana and OpenID Connect](https://docs.victoriametrics.com/guides/grafana-vmgateway-openid-configuration.html)
|
||||
|
|
194
docs/guides/grafana-vmgateway-openid-configuration.md
Normal file
|
@ -0,0 +1,194 @@
|
|||
# How to configure vmgateway for multi-tenant access using Grafana and OpenID Connect
|
||||
|
||||
Using [Grafana](https://grafana.com/) with [vmgateway](https://docs.victoriametrics.com/vmgateway.html) is a great way to provide [multi-tenant](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#multitenancy) access to your metrics.
|
||||
vmgateway provides a way to authenticate users using [JWT tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) issued by an external identity provider.
|
||||
Those tokens can include information about the user and the tenant they belong to, which can be used
|
||||
to restrict access to metrics to only those that belong to the tenant.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* Identity service that can issue [JWT tokens](https://en.wikipedia.org/wiki/JSON_Web_Token)
|
||||
* [Grafana](https://grafana.com/)
|
||||
* VictoriaMetrics single-node or cluster version
|
||||
* [vmgateway](https://docs.victoriametrics.com/vmgateway.html)
|
||||
|
||||
## Configure identity service
|
||||
|
||||
The identity service must be able to issue JWT tokens with the following `vm_access` claim:
|
||||
|
||||
```json
|
||||
{
|
||||
"vm_access": {
|
||||
"tenant_id": {
|
||||
"account_id": 0,
|
||||
"project_id": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See details about all supported options in the [vmgateway documentation](https://docs.victoriametrics.com/vmgateway.html#access-control).
|
||||
|
||||
### Configuration example for Keycloak
|
||||
|
||||
[Keycloak](https://www.keycloak.org/) is an open source identity service that can be used to issue JWT tokens.
|
||||
|
||||
1. Log in with admin credentials to your Keycloak instance
|
||||
2. Go to `Clients` -> `Create`.
|
||||
Use `OpenID Connect` as `Client Type`.
|
||||
Specify `grafana` as `Client ID`.
|
||||
Click `Next`.
|
||||
<img src="grafana-vmgateway-openid-configuration/create-client-1.png" width="800">
|
||||
3. Enable `Client authentication`.
|
||||
Enable `Authorization`.
|
||||
<img src="grafana-vmgateway-openid-configuration/create-client-2.png" width="800">
|
||||
Click `Next`.
|
||||
4. Add Grafana URL as `Valid Redirect URIs`. For example, `http://localhost:3000/`.
|
||||
<img src="grafana-vmgateway-openid-configuration/create-client-3.png" width="800">
|
||||
Click `Save`.
|
||||
5. Go to `Clients` -> `grafana` -> `Credentials`.
|
||||
<img src="grafana-vmgateway-openid-configuration/client-secret.png" width="800">
|
||||
Copy the value of `Client secret`. It will be used later in Grafana configuration.
|
||||
6. Go to `Clients` -> `grafana` -> `Client scopes`.
|
||||
Click at `grafana-dedicated` -> `Add mapper`.
|
||||
<img src="grafana-vmgateway-openid-configuration/create-mapper-1.png" width="800">
|
||||
<img src="grafana-vmgateway-openid-configuration/create-mapper-2.png" width="800">
|
||||
Configure the mapper as follows
|
||||
- `Mapper Type` as `User Attribute`.
|
||||
- `Name` as `vm_access`.
|
||||
- `Token Claim Name` as `vm_access`.
|
||||
- `User Attribute` as `vm_access`.
|
||||
- `Claim JSON Type` as `JSON`.
|
||||
Enable `Add to ID token` and `Add to access token`.
|
||||
<img src="grafana-vmgateway-openid-configuration/create-mapper-3.png" width="800">
|
||||
Click `Save`.
|
||||
7. Go to `Users` -> select user to configure claims -> `Attributes`.
|
||||
Specify `vm_access` as `Key`.
|
||||
Specify `{"tenant_id" : {"account_id": 0, "project_id": 0 }}` as `Value`.
|
||||
<img src="grafana-vmgateway-openid-configuration/user-attributes.png" width="800">
|
||||
Click `Save`.
|
||||
|
||||
## Configure grafana
|
||||
|
||||
To forward JWT tokens Grafana must be configured to use OpenID Connect authentication as follows:
|
||||
|
||||
```ini
|
||||
[auth.generic_oauth]
|
||||
enabled = true
|
||||
allow_sign_up = true
|
||||
name = keycloak
|
||||
client_id = {CLIENT_ID_FROM_IDENTITY_PROVIDER}
|
||||
client_secret = {SECRET_FROM_IDENTITY_PROVIDER}
|
||||
scopes = openid profile email
|
||||
auth_url = http://localhost:3001/realms/{KEYCLOACK_REALM}/protocol/openid-connect/auth
|
||||
token_url = http://localhost:3001/realms/{KEYCLOACK_REALM}/protocol/openid-connect/token
|
||||
api_url = http://localhost:3001/realms/{KEYCLOACK_REALM}/protocol/openid-connect/userinfo
|
||||
```
|
||||
|
||||
After restarting Grafana with the new config you should be able to log in using your identity provider.
|
||||
|
||||
## Start vmgateway
|
||||
|
||||
### Multi-tenant access for VictoriaMetrics cluster
|
||||
|
||||
Now starting vmgateway with enabled authentication is as simple as adding the `-enable.auth=true` flag.
|
||||
In order to enable multi-tenant access, you must also specify the `-clusterMode=true` flag.
|
||||
|
||||
```console
|
||||
./bin/vmgateway -eula \
|
||||
-enable.auth=true \
|
||||
-clusterMode=true \
|
||||
-write.url=http://localhost:8480 \
|
||||
-read.url=http://localhost:8481
|
||||
```
|
||||
|
||||
With this configuration vmgateway will use the `vm_access` claim from the JWT token to restrict access to metrics.
|
||||
For example, if the JWT token contains the following `vm_access` claim:
|
||||
|
||||
```json
|
||||
{
|
||||
"vm_access": {
|
||||
"tenant_id": {
|
||||
"account_id": 0,
|
||||
"project_id": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
> Note: in case `project_id` is not specified, default value `0` is used.
|
||||
|
||||
Then vmgateway will proxy request to an endpoint with the following path:
|
||||
|
||||
```console
|
||||
http://localhost:8480/select/0:0/
|
||||
```
|
||||
|
||||
This allows to restrict access to specific tenants without having to create separate datasources in Grafana,
|
||||
or manually managing access at another proxy level.
|
||||
|
||||
### Multi-tenant access for single-node VictoriaMetrics
|
||||
|
||||
In order to use multi-tenant access with single-node VictoriaMetrics, you can use token claims such as `extra_labels`
|
||||
or `extra_filters` filled dynamically by using Identity Provider's user information.
|
||||
vmgateway uses those claims and [enhanced Prometheus querying API](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#prometheus-querying-api-enhancements)
|
||||
to provide additional filtering capabilities.
|
||||
|
||||
For example, the following claims can be used to restrict user access to specific metrics:
|
||||
|
||||
```json
|
||||
{
|
||||
"vm_access": {
|
||||
"extra_labels": {
|
||||
"team": "dev"
|
||||
},
|
||||
"extra_filters": ["{env=~\"aws|gcp\",cluster!=\"production\"}"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will add the following query args to the proxied request:
|
||||
|
||||
- `extra_labels=team=dev`
|
||||
- `extra_filters={env=~"aws|gcp",cluster!="production"}`
|
||||
|
||||
With this configuration VictoriaMetrics will add the following filters to every query: `{team="dev", env=~"aws|gcp", cluster!="production"}`.
|
||||
So when user will try to query `vm_http_requests_total` query will be transformed to `vm_http_requests_total{team="dev", env=~"aws|gcp", cluster!="production"}`.
|
||||
|
||||
### Token signature verification
|
||||
|
||||
It is also possible to enable [JWT token signature verification](https://docs.victoriametrics.com/vmgateway.html#jwt-signature-verification) at
|
||||
vmgateway.
|
||||
To do this by using OpenID Connect discovery endpoint you need to specify the `-auth.oidcDiscoveryEndpoints` flag. For example:
|
||||
|
||||
```console
|
||||
./bin/vmgateway -eula \
|
||||
-enable.auth=true \
|
||||
-clusterMode=true \
|
||||
-write.url=http://localhost:8480 \
|
||||
-read.url=http://localhost:8481
|
||||
-auth.oidcDiscoveryEndpoints=http://localhost:3001/realms/master/.well-known/openid-configuration
|
||||
```
|
||||
|
||||
Now vmgateway will print the following message on startup:
|
||||
|
||||
```console
|
||||
2023-03-13T14:45:31.552Z info VictoriaMetrics/app/vmgateway/main.go:154 using 2 keys for JWT token signature verification
|
||||
```
|
||||
|
||||
That means that vmgateway has successfully fetched the public keys from the OpenID Connect discovery endpoint.
|
||||
|
||||
It is also possible to provide the public keys directly via the `-auth.publicKeys` flag. See the [vmgateway documentation](https://docs.victoriametrics.com/vmgateway.html#jwt-signature-verification) for details.
|
||||
|
||||
## Use Grafana to query metrics
|
||||
|
||||
Create a new Prometheus datasource in Grafana with the following URL `http://<vmgateway>:8431`.
|
||||
URL should point to the vmgateway instance.
|
||||
|
||||
You can also use VictoriaMetrics [Grafana datasource](https://github.com/VictoriaMetrics/grafana-datasource) plugin.
|
||||
See installation instructions [here](https://github.com/VictoriaMetrics/grafana-datasource#installation).
|
||||
|
||||
Enable `Forward OAuth identity` flag.
|
||||
<img src="grafana-vmgateway-openid-configuration/grafana-ds.png" width="800">
|
||||
|
||||
Now you can use Grafana to query metrics from the specified tenant.
|
||||
Users with `vm_access` claim will be able to query metrics from the specified tenant.
|
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 35 KiB |
18
go.mod
|
@ -14,19 +14,19 @@ require (
|
|||
github.com/VictoriaMetrics/metrics v1.23.1
|
||||
github.com/VictoriaMetrics/metricsql v0.56.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.16
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.56
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.17
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.57
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6
|
||||
github.com/cespare/xxhash/v2 v2.2.0
|
||||
github.com/cheggaaa/pb/v3 v3.1.2
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/fatih/color v1.14.1 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/go-kit/kit v0.12.0
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/googleapis/gax-go/v2 v2.7.1
|
||||
github.com/influxdata/influxdb v1.11.0
|
||||
github.com/klauspost/compress v1.16.0
|
||||
github.com/klauspost/compress v1.16.3
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/oklog/ulid v1.3.1
|
||||
|
@ -54,10 +54,10 @@ require (
|
|||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.219 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.221 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 // indirect
|
||||
|
@ -107,7 +107,7 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/goleak v1.2.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230314191032-db074128a8ec // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
|
@ -115,6 +115,6 @@ require (
|
|||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||
google.golang.org/grpc v1.53.0 // indirect
|
||||
google.golang.org/protobuf v1.29.0 // indirect
|
||||
google.golang.org/protobuf v1.29.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
36
go.sum
|
@ -86,20 +86,20 @@ github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu
|
|||
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo=
|
||||
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.44.219 h1:YOFxTUQZvdRzgwb6XqLFRwNHxoUdKBuunITC7IFhvbc=
|
||||
github.com/aws/aws-sdk-go v1.44.219/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.221 h1:yndn4uvLolKXPoXIwKHhO5XtwlTnJfXLBKXs84C5+hQ=
|
||||
github.com/aws/aws-sdk-go v1.44.221/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6 h1:Y773UK7OBqhzi5VDXMi1zVGsoj+CVHs2eaC2bDsLwi0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.16 h1:4r7gsCu8Ekwl5iJGE/GmspA2UifqySCCkyyyPFeWs3w=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.16/go.mod h1:XjM6lVbq7UgELp9NjXBrb1DQY/ownlWsvDhEQksemJc=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.16 h1:GgToSxaENX/1zXIGNFfiVk4hxryYJ5Vt4Mh8XLAL7Lc=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.16/go.mod h1:KP7aFJhfwPFgx9aoVYL2nYHjya5WBD98CWaadpgmnpY=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 h1:5qyqXASrX2zy5cTnoHHa4N2c3Lc94GH7gjnBP3GwKdU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24/go.mod h1:neYVaeKr5eT7BzwULuG2YbLhzWZ22lpjKdCybR7AXrQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.56 h1:kFDCPqqVvb9vYcW82L7xYfrBGpuxXQ/8A/zYVayRQK4=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.56/go.mod h1:FoSBuessadgy8Cqp9gQF8U5rzi1XVQhiEJ6su2/kBEE=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.17 h1:jwTkhULSrbr/SQA8tfdYqZxpG8YsRycmIXxJcbrqY5E=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.17/go.mod h1:Lj3E7XcxJnxMa+AYo89YiL68s1cFJRGduChynYU67VA=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.17 h1:IubQO/RNeIVKF5Jy77w/LfUvmmCxTnk2TP1UZZIMiF4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.17/go.mod h1:K9xeFo1g/YPMguMUD69YpwB4Nyi6W/5wn706xIInJFg=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0 h1:/2Cb3SK3xVOQA7Xfr5nCWCo5H3UiNINtsVvVdk8sQqA=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0/go.mod h1:neYVaeKr5eT7BzwULuG2YbLhzWZ22lpjKdCybR7AXrQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.57 h1:ubKS0iZH5veiqb44qeHzaoKNPvCZQeBVFw4JDhfeWjk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.57/go.mod h1:dRBjXtcjmYglxVHpdoGGVWvZumDC27I2GLDGI0Uw4RQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 h1:y+8n9AGDjikyXoMBTRaHHHSaFEB8267ykmvyPodJfys=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 h1:r+Kv+SEJquhAZXaJ7G4u44cIwXV3f8K+N482NNAzJZA=
|
||||
|
@ -163,8 +163,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||
github.com/envoyproxy/go-control-plane v0.10.3 h1:xdCVXxEe0Y3FQith+0cj2irwZudqGYvecuLB1HtdexY=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY=
|
||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
|
@ -315,8 +315,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
|
||||
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
|
||||
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
@ -481,8 +481,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 h1:LGJsf5LRplCck6jUCH3dBL2dmycNruWNF5xugkSlfXw=
|
||||
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/exp v0.0.0-20230314191032-db074128a8ec h1:pAv+d8BM2JNnNctsLJ6nnZ6NqXT8N4+eauvZSb3P0I0=
|
||||
golang.org/x/exp v0.0.0-20230314191032-db074128a8ec/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -761,8 +761,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.29.0 h1:44S3JjaKmLEE4YIkjzexaP+NzZsudE3Zin5Njn/pYX0=
|
||||
google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
|
||||
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
@ -486,7 +486,7 @@ func MarshalMetricNameRaw(dst []byte, labels []prompb.Label) []byte {
|
|||
label.Name = label.Name[:maxLabelNameLen]
|
||||
}
|
||||
if len(label.Value) > maxLabelValueLen {
|
||||
atomic.AddUint64(&TooLongLabelValues, 1)
|
||||
trackTruncatedLabels(labels, label)
|
||||
label.Value = label.Value[:maxLabelValueLen]
|
||||
}
|
||||
if len(label.Value) == 0 {
|
||||
|
@ -534,7 +534,7 @@ func trackDroppedLabels(labels, droppedLabels []prompb.Label) {
|
|||
select {
|
||||
case <-droppedLabelsLogTicker.C:
|
||||
// Do not call logger.WithThrottler() here, since this will result in increased CPU usage
|
||||
// because labelsToString() will be called with each trackDroppedLAbels call.
|
||||
// because labelsToString() will be called with each trackDroppedLabels call.
|
||||
logger.Warnf("dropping %d labels for %s; dropped labels: %s; either reduce the number of labels for this metric "+
|
||||
"or increase -maxLabelsPerTimeseries=%d command-line flag value",
|
||||
len(droppedLabels), labelsToString(labels), labelsToString(droppedLabels), maxLabelsPerTimeseries)
|
||||
|
@ -542,7 +542,21 @@ func trackDroppedLabels(labels, droppedLabels []prompb.Label) {
|
|||
}
|
||||
}
|
||||
|
||||
func trackTruncatedLabels(labels []prompb.Label, truncated *prompb.Label) {
|
||||
atomic.AddUint64(&TooLongLabelValues, 1)
|
||||
select {
|
||||
case <-truncatedLabelsLogTicker.C:
|
||||
// Do not call logger.WithThrottler() here, since this will result in increased CPU usage
|
||||
// because labelsToString() will be called with each trackTruncatedLabels call.
|
||||
logger.Warnf("truncated label value as it exceeds configured maximal label value length: max %d, actual %d;"+
|
||||
" truncated label: %s; original labels: %s; either reduce the label value length or increase -maxLabelValueLen=%d;",
|
||||
maxLabelValueLen, len(truncated.Value), truncated.Name, labelsToString(labels), maxLabelValueLen)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
var droppedLabelsLogTicker = time.NewTicker(5 * time.Second)
|
||||
var truncatedLabelsLogTicker = time.NewTicker(5 * time.Second)
|
||||
|
||||
func labelsToString(labels []prompb.Label) string {
|
||||
labelsCopy := append([]prompb.Label{}, labels...)
|
||||
|
|
4
vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md
generated
vendored
|
@ -1,3 +1,7 @@
|
|||
# v1.18.17 (2023-03-14)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
||||
# v1.18.16 (2023-03-10)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
|
2
vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go
generated
vendored
|
@ -3,4 +3,4 @@
|
|||
package config
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.18.16"
|
||||
const goModuleVersion = "1.18.17"
|
||||
|
|
4
vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md
generated
vendored
|
@ -1,3 +1,7 @@
|
|||
# v1.13.17 (2023-03-14)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
||||
# v1.13.16 (2023-03-10)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
|
2
vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go
generated
vendored
|
@ -3,4 +3,4 @@
|
|||
package credentials
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.13.16"
|
||||
const goModuleVersion = "1.13.17"
|
||||
|
|
4
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md
generated
vendored
|
@ -1,3 +1,7 @@
|
|||
# v1.13.0 (2023-03-14)
|
||||
|
||||
* **Feature**: Add flag to disable IMDSv1 fallback
|
||||
|
||||
# v1.12.24 (2023-03-10)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
|
10
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_client.go
generated
vendored
|
@ -174,6 +174,16 @@ type Options struct {
|
|||
// The logger writer interface to write logging messages to.
|
||||
Logger logging.Logger
|
||||
|
||||
// Configure IMDSv1 fallback behavior. By default, the client will attempt
|
||||
// to fall back to IMDSv1 as needed for backwards compatibility. When set to [aws.FalseTernary]
|
||||
// the client will return any errors encountered from attempting to fetch a token
|
||||
// instead of silently using the insecure data flow of IMDSv1.
|
||||
//
|
||||
// See [configuring IMDS] for more information.
|
||||
//
|
||||
// [configuring IMDS]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html
|
||||
EnableFallback aws.Ternary
|
||||
|
||||
// provides the caching of API tokens used for operation calls. If unset,
|
||||
// the API token will not be retrieved for the operation.
|
||||
tokenProvider *tokenProvider
|
||||
|
|
2
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go
generated
vendored
|
@ -3,4 +3,4 @@
|
|||
package imds
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.12.24"
|
||||
const goModuleVersion = "1.13.0"
|
||||
|
|
82
vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/token_provider.go
generated
vendored
|
@ -4,12 +4,14 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/smithy-go"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"net/http"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
smithy "github.com/aws/smithy-go"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
@ -68,7 +70,7 @@ func (t *tokenProvider) HandleFinalize(
|
|||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
if !t.enabled() {
|
||||
if t.fallbackEnabled() && !t.enabled() {
|
||||
// short-circuits to insecure data flow if token provider is disabled.
|
||||
return next.HandleFinalize(ctx, input)
|
||||
}
|
||||
|
@ -115,23 +117,15 @@ func (t *tokenProvider) HandleDeserialize(
|
|||
}
|
||||
|
||||
if resp.StatusCode == http.StatusUnauthorized { // unauthorized
|
||||
err = &retryableError{Err: err}
|
||||
t.enable()
|
||||
err = &retryableError{Err: err, isRetryable: true}
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
type retryableError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (*retryableError) RetryableError() bool { return true }
|
||||
|
||||
func (e *retryableError) Error() string { return e.Err.Error() }
|
||||
|
||||
func (t *tokenProvider) getToken(ctx context.Context) (tok *apiToken, err error) {
|
||||
if !t.enabled() {
|
||||
if t.fallbackEnabled() && !t.enabled() {
|
||||
return nil, &bypassTokenRetrievalError{
|
||||
Err: fmt.Errorf("cannot get API token, provider disabled"),
|
||||
}
|
||||
|
@ -147,7 +141,7 @@ func (t *tokenProvider) getToken(ctx context.Context) (tok *apiToken, err error)
|
|||
|
||||
tok, err = t.updateToken(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get API token, %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tok, nil
|
||||
|
@ -167,17 +161,19 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
|
|||
TokenTTL: t.tokenTTL,
|
||||
})
|
||||
if err != nil {
|
||||
// change the disabled flag on token provider to true, when error is request timeout error.
|
||||
var statusErr interface{ HTTPStatusCode() int }
|
||||
if errors.As(err, &statusErr) {
|
||||
switch statusErr.HTTPStatusCode() {
|
||||
|
||||
// Disable get token if failed because of 403, 404, or 405
|
||||
// Disable future get token if failed because of 403, 404, or 405
|
||||
case http.StatusForbidden,
|
||||
http.StatusNotFound,
|
||||
http.StatusMethodNotAllowed:
|
||||
|
||||
t.disable()
|
||||
if t.fallbackEnabled() {
|
||||
logger := middleware.GetLogger(ctx)
|
||||
logger.Logf(logging.Warn, "falling back to IMDSv1: %v", err)
|
||||
t.disable()
|
||||
}
|
||||
|
||||
// 400 errors are terminal, and need to be upstreamed
|
||||
case http.StatusBadRequest:
|
||||
|
@ -192,8 +188,17 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
|
|||
atomic.StoreUint32(&t.disabled, 1)
|
||||
}
|
||||
|
||||
// Token couldn't be retrieved, but bypass this, and allow the
|
||||
// request to continue.
|
||||
if !t.fallbackEnabled() {
|
||||
// NOTE: getToken() is an implementation detail of some outer operation
|
||||
// (e.g. GetMetadata). It has its own retries that have already been exhausted.
|
||||
// Mark the underlying error as a terminal error.
|
||||
err = &retryableError{Err: err, isRetryable: false}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Token couldn't be retrieved, fallback to IMDSv1 insecure flow for this request
|
||||
// and allow the request to proceed. Future requests _may_ re-attempt fetching a
|
||||
// token if not disabled.
|
||||
return nil, &bypassTokenRetrievalError{Err: err}
|
||||
}
|
||||
|
||||
|
@ -206,21 +211,21 @@ func (t *tokenProvider) updateToken(ctx context.Context) (*apiToken, error) {
|
|||
return tok, nil
|
||||
}
|
||||
|
||||
type bypassTokenRetrievalError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *bypassTokenRetrievalError) Error() string {
|
||||
return fmt.Sprintf("bypass token retrieval, %v", e.Err)
|
||||
}
|
||||
|
||||
func (e *bypassTokenRetrievalError) Unwrap() error { return e.Err }
|
||||
|
||||
// enabled returns if the token provider is current enabled or not.
|
||||
func (t *tokenProvider) enabled() bool {
|
||||
return atomic.LoadUint32(&t.disabled) == 0
|
||||
}
|
||||
|
||||
// fallbackEnabled returns false if EnableFallback is [aws.FalseTernary], true otherwise
|
||||
func (t *tokenProvider) fallbackEnabled() bool {
|
||||
switch t.client.options.EnableFallback {
|
||||
case aws.FalseTernary:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// disable disables the token provider and it will no longer attempt to inject
|
||||
// the token, nor request updates.
|
||||
func (t *tokenProvider) disable() {
|
||||
|
@ -235,3 +240,22 @@ func (t *tokenProvider) enable() {
|
|||
t.tokenMux.Unlock()
|
||||
atomic.StoreUint32(&t.disabled, 0)
|
||||
}
|
||||
|
||||
type bypassTokenRetrievalError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *bypassTokenRetrievalError) Error() string {
|
||||
return fmt.Sprintf("bypass token retrieval, %v", e.Err)
|
||||
}
|
||||
|
||||
func (e *bypassTokenRetrievalError) Unwrap() error { return e.Err }
|
||||
|
||||
type retryableError struct {
|
||||
Err error
|
||||
isRetryable bool
|
||||
}
|
||||
|
||||
func (e *retryableError) RetryableError() bool { return e.isRetryable }
|
||||
|
||||
func (e *retryableError) Error() string { return e.Err.Error() }
|
||||
|
|
4
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/CHANGELOG.md
generated
vendored
|
@ -1,3 +1,7 @@
|
|||
# v1.11.57 (2023-03-14)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
||||
# v1.11.56 (2023-03-10)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
|
2
vendor/github.com/aws/aws-sdk-go-v2/feature/s3/manager/go_module_metadata.go
generated
vendored
|
@ -3,4 +3,4 @@
|
|||
package manager
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.11.56"
|
||||
const goModuleVersion = "1.11.57"
|
||||
|
|
64
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
|
@ -20,16 +20,16 @@ type RequestRetryer interface{}
|
|||
// A Config provides service configuration for service clients. By default,
|
||||
// all clients will use the defaults.DefaultConfig structure.
|
||||
//
|
||||
// // Create Session with MaxRetries configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// MaxRetries: aws.Int(3),
|
||||
// }))
|
||||
// // Create Session with MaxRetries configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// MaxRetries: aws.Int(3),
|
||||
// }))
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// Region: aws.String("us-west-2"),
|
||||
// })
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// Region: aws.String("us-west-2"),
|
||||
// })
|
||||
type Config struct {
|
||||
// Enables verbose error printing of all credential chain errors.
|
||||
// Should be used when wanting to see all errors while attempting to
|
||||
|
@ -192,6 +192,23 @@ type Config struct {
|
|||
//
|
||||
EC2MetadataDisableTimeoutOverride *bool
|
||||
|
||||
// Set this to `false` to disable EC2Metadata client from falling back to IMDSv1.
|
||||
// By default, EC2 role credentials will fall back to IMDSv1 as needed for backwards compatibility.
|
||||
// You can disable this behavior by explicitly setting this flag to `false`. When false, the EC2Metadata
|
||||
// client will return any errors encountered from attempting to fetch a token instead of silently
|
||||
// using the insecure data flow of IMDSv1.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.Must(session.NewSession(aws.NewConfig()
|
||||
// .WithEC2MetadataEnableFallback(false)))
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
//
|
||||
// See [configuring IMDS] for more information.
|
||||
//
|
||||
// [configuring IMDS]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html
|
||||
EC2MetadataEnableFallback *bool
|
||||
|
||||
// Instructs the endpoint to be generated for a service client to
|
||||
// be the dual stack endpoint. The dual stack endpoint will support
|
||||
// both IPv4 and IPv6 addressing.
|
||||
|
@ -283,16 +300,16 @@ type Config struct {
|
|||
// NewConfig returns a new Config pointer that can be chained with builder
|
||||
// methods to set multiple configuration values inline without using pointers.
|
||||
//
|
||||
// // Create Session with MaxRetries configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess := session.Must(session.NewSession(aws.NewConfig().
|
||||
// WithMaxRetries(3),
|
||||
// ))
|
||||
// // Create Session with MaxRetries configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess := session.Must(session.NewSession(aws.NewConfig().
|
||||
// WithMaxRetries(3),
|
||||
// ))
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, aws.NewConfig().
|
||||
// WithRegion("us-west-2"),
|
||||
// )
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, aws.NewConfig().
|
||||
// WithRegion("us-west-2"),
|
||||
// )
|
||||
func NewConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
@ -432,6 +449,13 @@ func (c *Config) WithEC2MetadataDisableTimeoutOverride(enable bool) *Config {
|
|||
return c
|
||||
}
|
||||
|
||||
// WithEC2MetadataEnableFallback sets a config EC2MetadataEnableFallback value
|
||||
// returning a Config pointer for chaining.
|
||||
func (c *Config) WithEC2MetadataEnableFallback(v bool) *Config {
|
||||
c.EC2MetadataEnableFallback = &v
|
||||
return c
|
||||
}
|
||||
|
||||
// WithSleepDelay overrides the function used to sleep while waiting for the
|
||||
// next retry. Defaults to time.Sleep.
|
||||
func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
|
||||
|
@ -576,6 +600,10 @@ func mergeInConfig(dst *Config, other *Config) {
|
|||
dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride
|
||||
}
|
||||
|
||||
if other.EC2MetadataEnableFallback != nil {
|
||||
dst.EC2MetadataEnableFallback = other.EC2MetadataEnableFallback
|
||||
}
|
||||
|
||||
if other.SleepDelay != nil {
|
||||
dst.SleepDelay = other.SleepDelay
|
||||
}
|
||||
|
|
10
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
|
@ -57,13 +57,13 @@ type EC2Metadata struct {
|
|||
// New creates a new instance of the EC2Metadata client with a session.
|
||||
// This client is safe to use across multiple goroutines.
|
||||
//
|
||||
//
|
||||
// Example:
|
||||
// // Create a EC2Metadata client from just a session.
|
||||
// svc := ec2metadata.New(mySession)
|
||||
//
|
||||
// // Create a EC2Metadata client with additional configuration
|
||||
// svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody))
|
||||
// // Create a EC2Metadata client from just a session.
|
||||
// svc := ec2metadata.New(mySession)
|
||||
//
|
||||
// // Create a EC2Metadata client with additional configuration
|
||||
// svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
|
|
25
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/token_provider.go
generated
vendored
|
@ -1,6 +1,7 @@
|
|||
package ec2metadata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
@ -33,11 +34,15 @@ func newTokenProvider(c *EC2Metadata, duration time.Duration) *tokenProvider {
|
|||
return &tokenProvider{client: c, configuredTTL: duration}
|
||||
}
|
||||
|
||||
// check if fallback is enabled
|
||||
func (t *tokenProvider) fallbackEnabled() bool {
|
||||
return t.client.Config.EC2MetadataEnableFallback == nil || *t.client.Config.EC2MetadataEnableFallback
|
||||
}
|
||||
|
||||
// fetchTokenHandler fetches token for EC2Metadata service client by default.
|
||||
func (t *tokenProvider) fetchTokenHandler(r *request.Request) {
|
||||
|
||||
// short-circuits to insecure data flow if tokenProvider is disabled.
|
||||
if v := atomic.LoadUint32(&t.disabled); v == 1 {
|
||||
if v := atomic.LoadUint32(&t.disabled); v == 1 && t.fallbackEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -49,23 +54,21 @@ func (t *tokenProvider) fetchTokenHandler(r *request.Request) {
|
|||
output, err := t.client.getToken(r.Context(), t.configuredTTL)
|
||||
|
||||
if err != nil {
|
||||
// only attempt fallback to insecure data flow if IMDSv1 is enabled
|
||||
if !t.fallbackEnabled() {
|
||||
r.Error = awserr.New("EC2MetadataError", "failed to get IMDSv2 token and fallback to IMDSv1 is disabled", err)
|
||||
return
|
||||
}
|
||||
|
||||
// change the disabled flag on token provider to true,
|
||||
// when error is request timeout error.
|
||||
// change the disabled flag on token provider to true and fallback
|
||||
if requestFailureError, ok := err.(awserr.RequestFailure); ok {
|
||||
switch requestFailureError.StatusCode() {
|
||||
case http.StatusForbidden, http.StatusNotFound, http.StatusMethodNotAllowed:
|
||||
atomic.StoreUint32(&t.disabled, 1)
|
||||
t.client.Config.Logger.Log(fmt.Sprintf("WARN: failed to get session token, falling back to IMDSv1: %v", requestFailureError))
|
||||
case http.StatusBadRequest:
|
||||
r.Error = requestFailureError
|
||||
}
|
||||
|
||||
// Check if request timed out while waiting for response
|
||||
if e, ok := requestFailureError.OrigErr().(awserr.Error); ok {
|
||||
if e.Code() == request.ErrCodeRequestError {
|
||||
atomic.StoreUint32(&t.disabled, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
42
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
|
@ -9118,6 +9118,9 @@ var awsPartition = partition{
|
|||
endpointKey{
|
||||
Region: "ap-southeast-3",
|
||||
}: endpoint{},
|
||||
endpointKey{
|
||||
Region: "ap-southeast-4",
|
||||
}: endpoint{},
|
||||
endpointKey{
|
||||
Region: "ca-central-1",
|
||||
}: endpoint{},
|
||||
|
@ -21664,6 +21667,9 @@ var awsPartition = partition{
|
|||
endpointKey{
|
||||
Region: "eu-central-1",
|
||||
}: endpoint{},
|
||||
endpointKey{
|
||||
Region: "eu-central-2",
|
||||
}: endpoint{},
|
||||
endpointKey{
|
||||
Region: "eu-north-1",
|
||||
}: endpoint{},
|
||||
|
@ -31030,6 +31036,24 @@ var awsusgovPartition = partition{
|
|||
Region: "us-gov-east-1",
|
||||
},
|
||||
},
|
||||
endpointKey{
|
||||
Region: "us-gov-east-1",
|
||||
Variant: fipsVariant,
|
||||
}: endpoint{
|
||||
Hostname: "access-analyzer.us-gov-east-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-gov-east-1",
|
||||
},
|
||||
},
|
||||
endpointKey{
|
||||
Region: "us-gov-east-1-fips",
|
||||
}: endpoint{
|
||||
Hostname: "access-analyzer.us-gov-east-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-gov-east-1",
|
||||
},
|
||||
Deprecated: boxedTrue,
|
||||
},
|
||||
endpointKey{
|
||||
Region: "us-gov-west-1",
|
||||
}: endpoint{
|
||||
|
@ -31038,6 +31062,24 @@ var awsusgovPartition = partition{
|
|||
Region: "us-gov-west-1",
|
||||
},
|
||||
},
|
||||
endpointKey{
|
||||
Region: "us-gov-west-1",
|
||||
Variant: fipsVariant,
|
||||
}: endpoint{
|
||||
Hostname: "access-analyzer.us-gov-west-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-gov-west-1",
|
||||
},
|
||||
},
|
||||
endpointKey{
|
||||
Region: "us-gov-west-1-fips",
|
||||
}: endpoint{
|
||||
Hostname: "access-analyzer.us-gov-west-1.amazonaws.com",
|
||||
CredentialScope: credentialScope{
|
||||
Region: "us-gov-west-1",
|
||||
},
|
||||
Deprecated: boxedTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
"acm": service{
|
||||
|
|
2
vendor/github.com/aws/aws-sdk-go/aws/version.go
generated
vendored
|
@ -5,4 +5,4 @@ package aws
|
|||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "1.44.219"
|
||||
const SDKVersion = "1.44.221"
|
||||
|
|
19
vendor/github.com/fatih/color/color_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Opt-in for ansi color support for current process.
|
||||
// https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#output-sequences
|
||||
var outMode uint32
|
||||
out := windows.Handle(os.Stdout.Fd())
|
||||
if err := windows.GetConsoleMode(out, &outMode); err != nil {
|
||||
return
|
||||
}
|
||||
outMode |= windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
_ = windows.SetConsoleMode(out, outMode)
|
||||
}
|
15
vendor/github.com/klauspost/compress/README.md
generated
vendored
|
@ -16,6 +16,21 @@ This package provides various compression algorithms.
|
|||
|
||||
# changelog
|
||||
|
||||
* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
|
||||
* zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
|
||||
* gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767
|
||||
* s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766
|
||||
* zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773
|
||||
* huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774
|
||||
|
||||
* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0)
|
||||
* s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support. https://github.com/klauspost/compress/pull/685
|
||||
* s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752
|
||||
* s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755
|
||||
* s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
|
||||
* s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
|
||||
* s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
|
||||
|
||||
* Jan 21st, 2023 (v1.15.15)
|
||||
* deflate: Improve level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/739
|
||||
* zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
|
||||
|
|
4
vendor/github.com/klauspost/compress/fse/decompress.go
generated
vendored
|
@ -260,7 +260,9 @@ func (s *Scratch) buildDtable() error {
|
|||
// If the buffer is over-read an error is returned.
|
||||
func (s *Scratch) decompress() error {
|
||||
br := &s.bits
|
||||
br.init(s.br.unread())
|
||||
if err := br.init(s.br.unread()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var s1, s2 decoder
|
||||
// Initialize and decode first state and symbol.
|
||||
|
|
61
vendor/github.com/klauspost/compress/gzhttp/README.md
generated
vendored
|
@ -215,6 +215,67 @@ has been reached. In this case it will assume that the minimum size has been rea
|
|||
|
||||
If nothing has been written to the response writer, nothing will be flushed.
|
||||
|
||||
## BREACH mitigation
|
||||
|
||||
[BREACH](http://css.csail.mit.edu/6.858/2020/readings/breach.pdf) is a specialized attack where attacker controlled data
|
||||
is injected alongside secret data in a response body. This can lead to sidechannel attacks, where observing the compressed response
|
||||
size can reveal if there are overlaps between the secret data and the injected data.
|
||||
|
||||
For more information see https://breachattack.com/
|
||||
|
||||
It can be hard to judge if you are vulnerable to BREACH.
|
||||
In general, if you do not include any user provided content in the response body you are safe,
|
||||
but if you do, or you are in doubt, you can apply mitigations.
|
||||
|
||||
`gzhttp` can apply [Heal the Breach](https://ieeexplore.ieee.org/document/9754554), or improved content aware padding.
|
||||
|
||||
```Go
|
||||
// RandomJitter adds 1->n random bytes to output based on checksum of payload.
|
||||
// Specify the amount of input to buffer before applying jitter.
|
||||
// This should cover the sensitive part of your response.
|
||||
// This can be used to obfuscate the exact compressed size.
|
||||
// Specifying 0 will use a buffer size of 64KB.
|
||||
// 'paranoid' will use a slower hashing function, that MAY provide more safety.
|
||||
// If a negative buffer is given, the amount of jitter will not be content dependent.
|
||||
// This provides *less* security than applying content based jitter.
|
||||
func RandomJitter(n, buffer int, paranoid bool) option
|
||||
...
|
||||
```
|
||||
|
||||
The jitter is added as a "Comment" field. This field has a 1 byte overhead, so actual extra size will be 2 -> n+1 (inclusive).
|
||||
|
||||
A good option would be to apply 32 random bytes, with default 64KB buffer: `gzhttp.RandomJitter(32, 0, false)`.
|
||||
|
||||
Note that flushing the data forces the padding to be applied, which means that only data before the flush is considered for content aware padding.
|
||||
|
||||
The *padding* in the comment is the text `Padding-Padding-Padding-Padding-Pad....`
|
||||
|
||||
The *length* is `1 + crc32c(payload) MOD n` or `1 + sha256(payload) MOD n` (paranoid), or just random from `crypto/rand` if buffer < 0.
|
||||
|
||||
### Paranoid?
|
||||
|
||||
The padding size is determined by the remainder of a CRC32 of the content.
|
||||
|
||||
Since the payload contains elements unknown to the attacker, there is no reason to believe they can derive any information
|
||||
from this remainder, or predict it.
|
||||
|
||||
However, for those that feel uncomfortable with a CRC32 being used for this can enable "paranoid" mode which will use SHA256 for determining the padding.
|
||||
|
||||
The hashing itself is about 2 orders of magnitude slower, but in overall terms will maybe only reduce speed by 10%.
|
||||
|
||||
Paranoid mode has no effect if buffer is < 0 (non-content aware padding).
|
||||
|
||||
### Examples
|
||||
|
||||
Adding the option `gzhttp.RandomJitter(32, 50000)` will apply from 1 up to 32 bytes of random data to the output.
|
||||
|
||||
The number of bytes added depends on the content of the first 50000 bytes, or all of them if the output was less than that.
|
||||
|
||||
Adding the option `gzhttp.RandomJitter(32, -1)` will apply from 1 up to 32 bytes of random data to the output.
|
||||
Each call will apply a random amount of jitter. This should be considered less secure than content based jitter.
|
||||
|
||||
This can be used if responses are very big, deterministic and the buffer size would be too big to cover where the mutation occurs.
|
||||
|
||||
## License
|
||||
|
||||
[Apache 2.0](LICENSE)
|
||||
|
|
152
vendor/github.com/klauspost/compress/gzhttp/compress.go
generated
vendored
|
@ -2,8 +2,15 @@ package gzhttp
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"math"
|
||||
"math/bits"
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -67,6 +74,9 @@ type GzipResponseWriter struct {
|
|||
setContentType bool // Add content type, if missing and detected.
|
||||
suffixETag string // Suffix to add to ETag header if response is compressed.
|
||||
dropETag bool // Drop ETag header if response is compressed (supersedes suffixETag).
|
||||
sha256Jitter bool // Use sha256 for jitter.
|
||||
randomJitter string // Add random bytes to output as header field.
|
||||
jitterBuffer int // Maximum buffer to accumulate before doing jitter.
|
||||
|
||||
contentTypeFilter func(ct string) bool // Only compress if the response is one of these content-types. All are accepted if empty.
|
||||
}
|
||||
|
@ -97,6 +107,9 @@ func (w *GzipResponseWriter) Write(b []byte) (int, error) {
|
|||
if w.minSize > wantBuf {
|
||||
wantBuf = w.minSize
|
||||
}
|
||||
if w.jitterBuffer > 0 && w.jitterBuffer > wantBuf {
|
||||
wantBuf = w.jitterBuffer
|
||||
}
|
||||
toAdd := len(b)
|
||||
if len(w.buf)+toAdd > wantBuf {
|
||||
toAdd = wantBuf - len(w.buf)
|
||||
|
@ -112,7 +125,7 @@ func (w *GzipResponseWriter) Write(b []byte) (int, error) {
|
|||
ct := hdr.Get(contentType)
|
||||
if cl == 0 || cl >= w.minSize && (ct == "" || w.contentTypeFilter(ct)) {
|
||||
// If the current buffer is less than minSize and a Content-Length isn't set, then wait until we have more data.
|
||||
if len(w.buf) < w.minSize && cl == 0 {
|
||||
if len(w.buf) < w.minSize && cl == 0 || (w.jitterBuffer > 0 && len(w.buf) < w.jitterBuffer) {
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
|
@ -131,7 +144,7 @@ func (w *GzipResponseWriter) Write(b []byte) (int, error) {
|
|||
|
||||
// If the Content-Type is acceptable to GZIP, initialize the GZIP writer.
|
||||
if w.contentTypeFilter(ct) {
|
||||
if err := w.startGzip(); err != nil {
|
||||
if err := w.startGzip(remain); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(remain) > 0 {
|
||||
|
@ -156,8 +169,10 @@ func (w *GzipResponseWriter) Write(b []byte) (int, error) {
|
|||
return len(b), nil
|
||||
}
|
||||
|
||||
var castagnoliTable = crc32.MakeTable(crc32.Castagnoli)
|
||||
|
||||
// startGzip initializes a GZIP writer and writes the buffer.
|
||||
func (w *GzipResponseWriter) startGzip() error {
|
||||
func (w *GzipResponseWriter) startGzip(remain []byte) error {
|
||||
// Set the GZIP header.
|
||||
w.Header().Set(contentEncoding, "gzip")
|
||||
|
||||
|
@ -199,6 +214,49 @@ func (w *GzipResponseWriter) startGzip() error {
|
|||
if len(w.buf) > 0 {
|
||||
// Initialize the GZIP response.
|
||||
w.init()
|
||||
|
||||
// Set random jitter based on CRC or SHA-256 of current buffer.
|
||||
// Before first write.
|
||||
if len(w.randomJitter) > 0 {
|
||||
var jitRNG uint32
|
||||
if w.jitterBuffer > 0 {
|
||||
if w.sha256Jitter {
|
||||
h := sha256.New()
|
||||
h.Write(w.buf)
|
||||
// Use only up to "w.jitterBuffer", otherwise the output depends on write sizes.
|
||||
if len(remain) > 0 && len(w.buf) < w.jitterBuffer {
|
||||
remain := remain
|
||||
if len(remain)+len(w.buf) > w.jitterBuffer {
|
||||
remain = remain[:w.jitterBuffer-len(w.buf)]
|
||||
}
|
||||
h.Write(remain)
|
||||
}
|
||||
var tmp [sha256.Size]byte
|
||||
jitRNG = binary.LittleEndian.Uint32(h.Sum(tmp[:0]))
|
||||
} else {
|
||||
h := crc32.Update(0, castagnoliTable, w.buf)
|
||||
// Use only up to "w.jitterBuffer", otherwise the output depends on write sizes.
|
||||
if len(remain) > 0 && len(w.buf) < w.jitterBuffer {
|
||||
remain := remain
|
||||
if len(remain)+len(w.buf) > w.jitterBuffer {
|
||||
remain = remain[:w.jitterBuffer-len(w.buf)]
|
||||
}
|
||||
h = crc32.Update(h, castagnoliTable, remain)
|
||||
}
|
||||
jitRNG = bits.RotateLeft32(h, 19) ^ 0xab0755de
|
||||
}
|
||||
} else {
|
||||
// Get from rand.Reader
|
||||
var tmp [4]byte
|
||||
_, err := rand.Read(tmp[:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("gzhttp: %w", err)
|
||||
}
|
||||
jitRNG = binary.LittleEndian.Uint32(tmp[:])
|
||||
}
|
||||
jit := w.randomJitter[:1+jitRNG%uint32(len(w.randomJitter)-1)]
|
||||
w.gw.(writer.GzipWriterExt).SetHeader(writer.Header{Comment: jit})
|
||||
}
|
||||
n, err := w.gw.Write(w.buf)
|
||||
|
||||
// This should never happen (per io.Writer docs), but if the write didn't
|
||||
|
@ -259,15 +317,21 @@ func (w *GzipResponseWriter) Close() error {
|
|||
if w.ignore {
|
||||
return nil
|
||||
}
|
||||
|
||||
if w.gw == nil {
|
||||
// GZIP not triggered yet, write out regular response.
|
||||
err := w.startPlain()
|
||||
// Returns the error if any at write.
|
||||
if err != nil {
|
||||
err = fmt.Errorf("gziphandler: write to regular responseWriter at close gets error: %q", err.Error())
|
||||
var (
|
||||
ct = w.Header().Get(contentType)
|
||||
ce = w.Header().Get(contentEncoding)
|
||||
cr = w.Header().Get(contentRange)
|
||||
)
|
||||
// fmt.Println(len(w.buf) == 0, len(w.buf) < w.minSize, len(w.Header()[HeaderNoCompression]) != 0, ce != "", cr != "", !w.contentTypeFilter(ct))
|
||||
if len(w.buf) == 0 || len(w.buf) < w.minSize || len(w.Header()[HeaderNoCompression]) != 0 || ce != "" || cr != "" || !w.contentTypeFilter(ct) {
|
||||
// GZIP not triggered, write out regular response.
|
||||
return w.startPlain()
|
||||
}
|
||||
err := w.startGzip(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
err := w.gw.Close()
|
||||
|
@ -310,7 +374,7 @@ func (w *GzipResponseWriter) Flush() {
|
|||
|
||||
// See if we should compress...
|
||||
if len(w.Header()[HeaderNoCompression]) == 0 && ce == "" && cr == "" && cl >= w.minSize && w.contentTypeFilter(ct) {
|
||||
w.startGzip()
|
||||
w.startGzip(nil)
|
||||
} else {
|
||||
w.startPlain()
|
||||
}
|
||||
|
@ -392,6 +456,9 @@ func NewWrapper(opts ...option) (func(http.Handler) http.HandlerFunc, error) {
|
|||
suffixETag: c.suffixETag,
|
||||
buf: gw.buf,
|
||||
setContentType: c.setContentType,
|
||||
randomJitter: c.randomJitter,
|
||||
jitterBuffer: c.jitterBuffer,
|
||||
sha256Jitter: c.sha256Jitter,
|
||||
}
|
||||
if len(gw.buf) > 0 {
|
||||
gw.buf = gw.buf[:0]
|
||||
|
@ -408,6 +475,7 @@ func NewWrapper(opts ...option) (func(http.Handler) http.HandlerFunc, error) {
|
|||
} else {
|
||||
h.ServeHTTP(gw, r)
|
||||
}
|
||||
w.Header().Del(HeaderNoCompression)
|
||||
} else {
|
||||
h.ServeHTTP(newNoGzipResponseWriter(w), r)
|
||||
w.Header().Del(HeaderNoCompression)
|
||||
|
@ -455,6 +523,9 @@ type config struct {
|
|||
setContentType bool
|
||||
suffixETag string
|
||||
dropETag bool
|
||||
jitterBuffer int
|
||||
randomJitter string
|
||||
sha256Jitter bool
|
||||
}
|
||||
|
||||
func (c *config) validate() error {
|
||||
|
@ -466,7 +537,16 @@ func (c *config) validate() error {
|
|||
if c.minSize < 0 {
|
||||
return fmt.Errorf("minimum size must be more than zero")
|
||||
}
|
||||
|
||||
if len(c.randomJitter) >= math.MaxUint16 {
|
||||
return fmt.Errorf("random jitter size exceeded")
|
||||
}
|
||||
if len(c.randomJitter) > 0 {
|
||||
gzw, ok := c.writer.New(io.Discard, c.level).(writer.GzipWriterExt)
|
||||
if !ok {
|
||||
return errors.New("the custom compressor does not allow setting headers for random jitter")
|
||||
}
|
||||
gzw.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -496,8 +576,9 @@ func SetContentType(b bool) option {
|
|||
|
||||
// Implementation changes the implementation of GzipWriter
|
||||
//
|
||||
// The default implementation is writer/stdlib/NewWriter
|
||||
// which is backed by standard library's compress/zlib
|
||||
// The default implementation is backed by github.com/klauspost/compress
|
||||
// To support RandomJitter, the GzipWriterExt must also be
|
||||
// supported by the returned writers.
|
||||
func Implementation(writer writer.GzipWriterFactory) option {
|
||||
return func(c *config) {
|
||||
c.writer = writer
|
||||
|
@ -625,6 +706,31 @@ func DropETag() option {
|
|||
}
|
||||
}
|
||||
|
||||
// RandomJitter adds 1->n random bytes to output based on checksum of payload.
|
||||
// Specify the amount of input to buffer before applying jitter.
|
||||
// This should cover the sensitive part of your response.
|
||||
// This can be used to obfuscate the exact compressed size.
|
||||
// Specifying 0 will use a buffer size of 64KB.
|
||||
// 'paranoid' will use a slower hashing function, that MAY provide more safety.
|
||||
// See README.md for more information.
|
||||
// If a negative buffer is given, the amount of jitter will not be content dependent.
|
||||
// This provides *less* security than applying content based jitter.
|
||||
func RandomJitter(n, buffer int, paranoid bool) option {
|
||||
return func(c *config) {
|
||||
if n > 0 {
|
||||
c.sha256Jitter = paranoid
|
||||
c.randomJitter = strings.Repeat("Padding-", 1+(n/8))[:n+1]
|
||||
c.jitterBuffer = buffer
|
||||
if c.jitterBuffer == 0 {
|
||||
c.jitterBuffer = 64 << 10
|
||||
}
|
||||
} else {
|
||||
c.randomJitter = ""
|
||||
c.jitterBuffer = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// acceptsGzip returns true if the given HTTP request indicates that it will
|
||||
// accept a gzipped response.
|
||||
func acceptsGzip(r *http.Request) bool {
|
||||
|
@ -702,10 +808,23 @@ func parseEncodings(s string) (codings, error) {
|
|||
return c, nil
|
||||
}
|
||||
|
||||
var errEmptyEncoding = errors.New("empty content-coding")
|
||||
|
||||
// parseCoding parses a single coding (content-coding with an optional qvalue),
|
||||
// as might appear in an Accept-Encoding header. It attempts to forgive minor
|
||||
// formatting errors.
|
||||
func parseCoding(s string) (coding string, qvalue float64, err error) {
|
||||
// Avoid splitting if we can...
|
||||
if len(s) == 0 {
|
||||
return "", 0, errEmptyEncoding
|
||||
}
|
||||
if !strings.ContainsRune(s, ';') {
|
||||
coding = strings.ToLower(strings.TrimSpace(s))
|
||||
if coding == "" {
|
||||
err = errEmptyEncoding
|
||||
}
|
||||
return coding, DefaultQValue, err
|
||||
}
|
||||
for n, part := range strings.Split(s, ";") {
|
||||
part = strings.TrimSpace(part)
|
||||
qvalue = DefaultQValue
|
||||
|
@ -724,7 +843,7 @@ func parseCoding(s string) (coding string, qvalue float64, err error) {
|
|||
}
|
||||
|
||||
if coding == "" {
|
||||
err = fmt.Errorf("empty content-coding")
|
||||
err = errEmptyEncoding
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -766,6 +885,9 @@ const intSize = 32 << (^uint(0) >> 63)
|
|||
|
||||
// atoi is equivalent to ParseInt(s, 10, 0), converted to type int.
|
||||
func atoi(s string) (int, bool) {
|
||||
if len(s) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
sLen := len(s)
|
||||
if intSize == 32 && (0 < sLen && sLen < 10) ||
|
||||
intSize == 64 && (0 < sLen && sLen < 19) {
|
||||
|
|
9
vendor/github.com/klauspost/compress/gzhttp/writer/gzkp/gzkp.go
generated
vendored
|
@ -61,6 +61,15 @@ func NewWriter(w io.Writer, level int) writer.GzipWriter {
|
|||
}
|
||||
}
|
||||
|
||||
// SetHeader will override the gzip header on pw.
|
||||
func (pw *pooledWriter) SetHeader(h writer.Header) {
|
||||
pw.Name = h.Name
|
||||
pw.Extra = h.Extra
|
||||
pw.Comment = h.Comment
|
||||
pw.ModTime = h.ModTime
|
||||
pw.OS = h.OS
|
||||
}
|
||||
|
||||
func Levels() (min, max int) {
|
||||
return gzip.StatelessCompression, gzip.BestCompression
|
||||
}
|
||||
|
|
23
vendor/github.com/klauspost/compress/gzhttp/writer/interface.go
generated
vendored
|
@ -1,6 +1,9 @@
|
|||
package writer
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GzipWriter implements the functions needed for compressing content.
|
||||
type GzipWriter interface {
|
||||
|
@ -9,6 +12,24 @@ type GzipWriter interface {
|
|||
Flush() error
|
||||
}
|
||||
|
||||
// GzipWriterExt implements the functions needed for compressing content
|
||||
// and optional extensions.
|
||||
type GzipWriterExt interface {
|
||||
GzipWriter
|
||||
|
||||
// SetHeader will populate header fields with non-nil values in h.
|
||||
SetHeader(h Header)
|
||||
}
|
||||
|
||||
// Header is a gzip header.
|
||||
type Header struct {
|
||||
Comment string // comment
|
||||
Extra []byte // "extra data"
|
||||
ModTime time.Time // modification time
|
||||
Name string // file name
|
||||
OS byte // operating system type
|
||||
}
|
||||
|
||||
// GzipWriterFactory contains the information needed for custom gzip implementations.
|
||||
type GzipWriterFactory struct {
|
||||
// Must return the minimum and maximum supported level.
|
||||
|
|
16
vendor/github.com/klauspost/compress/huff0/bitwriter.go
generated
vendored
|
@ -60,6 +60,22 @@ func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
|
|||
b.nBits += encA.nBits + encB.nBits
|
||||
}
|
||||
|
||||
// encFourSymbols adds up to 32 bits from four symbols.
|
||||
// It will not check if there is space for them,
|
||||
// so the caller must ensure that b has been flushed recently.
|
||||
func (b *bitWriter) encFourSymbols(encA, encB, encC, encD cTableEntry) {
|
||||
bitsA := encA.nBits
|
||||
bitsB := bitsA + encB.nBits
|
||||
bitsC := bitsB + encC.nBits
|
||||
bitsD := bitsC + encD.nBits
|
||||
combined := uint64(encA.val) |
|
||||
(uint64(encB.val) << (bitsA & 63)) |
|
||||
(uint64(encC.val) << (bitsB & 63)) |
|
||||
(uint64(encD.val) << (bitsC & 63))
|
||||
b.bitContainer |= combined << (b.nBits & 63)
|
||||
b.nBits += bitsD
|
||||
}
|
||||
|
||||
// flush32 will flush out, so there are at least 32 bits available for writing.
|
||||
func (b *bitWriter) flush32() {
|
||||
if b.nBits < 32 {
|
||||
|
|
3
vendor/github.com/klauspost/compress/huff0/compress.go
generated
vendored
|
@ -248,8 +248,7 @@ func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) {
|
|||
tmp := src[n : n+4]
|
||||
// tmp should be len 4
|
||||
bw.flush32()
|
||||
bw.encTwoSymbols(cTable, tmp[3], tmp[2])
|
||||
bw.encTwoSymbols(cTable, tmp[1], tmp[0])
|
||||
bw.encFourSymbols(cTable[tmp[3]], cTable[tmp[2]], cTable[tmp[1]], cTable[tmp[0]])
|
||||
}
|
||||
} else {
|
||||
for ; n >= 0; n -= 4 {
|
||||
|
|
8
vendor/github.com/klauspost/compress/s2/encode_go.go
generated
vendored
|
@ -717,3 +717,11 @@ func cvtLZ4BlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
|
|||
func cvtLZ4BlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
|
||||
panic("cvtLZ4BlockSnappyAsm should be unreachable")
|
||||
}
|
||||
|
||||
func cvtLZ4sBlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
|
||||
panic("cvtLZ4sBlockAsm should be unreachable")
|
||||
}
|
||||
|
||||
func cvtLZ4sBlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int) {
|
||||
panic("cvtLZ4sBlockSnappyAsm should be unreachable")
|
||||
}
|
||||
|
|
12
vendor/github.com/klauspost/compress/s2/encodeblock_amd64.go
generated
vendored
|
@ -212,7 +212,17 @@ func matchLen(a []byte, b []byte) int
|
|||
//go:noescape
|
||||
func cvtLZ4BlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
|
||||
|
||||
// cvtLZ4Block converts an LZ4 block to S2
|
||||
// cvtLZ4sBlock converts an LZ4s block to S2
|
||||
//
|
||||
//go:noescape
|
||||
func cvtLZ4sBlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
|
||||
|
||||
// cvtLZ4Block converts an LZ4 block to Snappy
|
||||
//
|
||||
//go:noescape
|
||||
func cvtLZ4BlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
|
||||
|
||||
// cvtLZ4sBlock converts an LZ4s block to Snappy
|
||||
//
|
||||
//go:noescape
|
||||
func cvtLZ4sBlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
|
||||
|
|
753
vendor/github.com/klauspost/compress/s2/encodeblock_amd64.s
generated
vendored
|
@ -19271,6 +19271,491 @@ lz4_s2_dstfull:
|
|||
MOVQ SI, uncompressed+48(FP)
|
||||
RET
|
||||
|
||||
// func cvtLZ4sBlockAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
|
||||
// Requires: SSE2
|
||||
TEXT ·cvtLZ4sBlockAsm(SB), NOSPLIT, $0-64
|
||||
XORQ SI, SI
|
||||
MOVQ dst_base+0(FP), AX
|
||||
MOVQ dst_len+8(FP), CX
|
||||
MOVQ src_base+24(FP), DX
|
||||
MOVQ src_len+32(FP), BX
|
||||
LEAQ (DX)(BX*1), BX
|
||||
LEAQ -10(AX)(CX*1), CX
|
||||
XORQ DI, DI
|
||||
|
||||
lz4s_s2_loop:
|
||||
CMPQ DX, BX
|
||||
JAE lz4s_s2_corrupt
|
||||
CMPQ AX, CX
|
||||
JAE lz4s_s2_dstfull
|
||||
MOVBQZX (DX), R8
|
||||
MOVQ R8, R9
|
||||
MOVQ R8, R10
|
||||
SHRQ $0x04, R9
|
||||
ANDQ $0x0f, R10
|
||||
CMPQ R8, $0xf0
|
||||
JB lz4s_s2_ll_end
|
||||
|
||||
lz4s_s2_ll_loop:
|
||||
INCQ DX
|
||||
CMPQ DX, BX
|
||||
JAE lz4s_s2_corrupt
|
||||
MOVBQZX (DX), R8
|
||||
ADDQ R8, R9
|
||||
CMPQ R8, $0xff
|
||||
JEQ lz4s_s2_ll_loop
|
||||
|
||||
lz4s_s2_ll_end:
|
||||
LEAQ (DX)(R9*1), R8
|
||||
ADDQ $0x03, R10
|
||||
CMPQ R8, BX
|
||||
JAE lz4s_s2_corrupt
|
||||
INCQ DX
|
||||
INCQ R8
|
||||
TESTQ R9, R9
|
||||
JZ lz4s_s2_lits_done
|
||||
LEAQ (AX)(R9*1), R11
|
||||
CMPQ R11, CX
|
||||
JAE lz4s_s2_dstfull
|
||||
ADDQ R9, SI
|
||||
LEAL -1(R9), R11
|
||||
CMPL R11, $0x3c
|
||||
JLT one_byte_lz4s_s2
|
||||
CMPL R11, $0x00000100
|
||||
JLT two_bytes_lz4s_s2
|
||||
CMPL R11, $0x00010000
|
||||
JLT three_bytes_lz4s_s2
|
||||
CMPL R11, $0x01000000
|
||||
JLT four_bytes_lz4s_s2
|
||||
MOVB $0xfc, (AX)
|
||||
MOVL R11, 1(AX)
|
||||
ADDQ $0x05, AX
|
||||
JMP memmove_long_lz4s_s2
|
||||
|
||||
four_bytes_lz4s_s2:
|
||||
MOVL R11, R12
|
||||
SHRL $0x10, R12
|
||||
MOVB $0xf8, (AX)
|
||||
MOVW R11, 1(AX)
|
||||
MOVB R12, 3(AX)
|
||||
ADDQ $0x04, AX
|
||||
JMP memmove_long_lz4s_s2
|
||||
|
||||
three_bytes_lz4s_s2:
|
||||
MOVB $0xf4, (AX)
|
||||
MOVW R11, 1(AX)
|
||||
ADDQ $0x03, AX
|
||||
JMP memmove_long_lz4s_s2
|
||||
|
||||
two_bytes_lz4s_s2:
|
||||
MOVB $0xf0, (AX)
|
||||
MOVB R11, 1(AX)
|
||||
ADDQ $0x02, AX
|
||||
CMPL R11, $0x40
|
||||
JL memmove_lz4s_s2
|
||||
JMP memmove_long_lz4s_s2
|
||||
|
||||
one_byte_lz4s_s2:
|
||||
SHLB $0x02, R11
|
||||
MOVB R11, (AX)
|
||||
ADDQ $0x01, AX
|
||||
|
||||
memmove_lz4s_s2:
|
||||
LEAQ (AX)(R9*1), R11
|
||||
|
||||
// genMemMoveShort
|
||||
CMPQ R9, $0x08
|
||||
JLE emit_lit_memmove_lz4s_s2_memmove_move_8
|
||||
CMPQ R9, $0x10
|
||||
JBE emit_lit_memmove_lz4s_s2_memmove_move_8through16
|
||||
CMPQ R9, $0x20
|
||||
JBE emit_lit_memmove_lz4s_s2_memmove_move_17through32
|
||||
JMP emit_lit_memmove_lz4s_s2_memmove_move_33through64
|
||||
|
||||
emit_lit_memmove_lz4s_s2_memmove_move_8:
|
||||
MOVQ (DX), R12
|
||||
MOVQ R12, (AX)
|
||||
JMP memmove_end_copy_lz4s_s2
|
||||
|
||||
emit_lit_memmove_lz4s_s2_memmove_move_8through16:
|
||||
MOVQ (DX), R12
|
||||
MOVQ -8(DX)(R9*1), DX
|
||||
MOVQ R12, (AX)
|
||||
MOVQ DX, -8(AX)(R9*1)
|
||||
JMP memmove_end_copy_lz4s_s2
|
||||
|
||||
emit_lit_memmove_lz4s_s2_memmove_move_17through32:
|
||||
MOVOU (DX), X0
|
||||
MOVOU -16(DX)(R9*1), X1
|
||||
MOVOU X0, (AX)
|
||||
MOVOU X1, -16(AX)(R9*1)
|
||||
JMP memmove_end_copy_lz4s_s2
|
||||
|
||||
emit_lit_memmove_lz4s_s2_memmove_move_33through64:
|
||||
MOVOU (DX), X0
|
||||
MOVOU 16(DX), X1
|
||||
MOVOU -32(DX)(R9*1), X2
|
||||
MOVOU -16(DX)(R9*1), X3
|
||||
MOVOU X0, (AX)
|
||||
MOVOU X1, 16(AX)
|
||||
MOVOU X2, -32(AX)(R9*1)
|
||||
MOVOU X3, -16(AX)(R9*1)
|
||||
|
||||
memmove_end_copy_lz4s_s2:
|
||||
MOVQ R11, AX
|
||||
JMP lz4s_s2_lits_emit_done
|
||||
|
||||
memmove_long_lz4s_s2:
|
||||
LEAQ (AX)(R9*1), R11
|
||||
|
||||
// genMemMoveLong
|
||||
MOVOU (DX), X0
|
||||
MOVOU 16(DX), X1
|
||||
MOVOU -32(DX)(R9*1), X2
|
||||
MOVOU -16(DX)(R9*1), X3
|
||||
MOVQ R9, R13
|
||||
SHRQ $0x05, R13
|
||||
MOVQ AX, R12
|
||||
ANDL $0x0000001f, R12
|
||||
MOVQ $0x00000040, R14
|
||||
SUBQ R12, R14
|
||||
DECQ R13
|
||||
JA emit_lit_memmove_long_lz4s_s2large_forward_sse_loop_32
|
||||
LEAQ -32(DX)(R14*1), R12
|
||||
LEAQ -32(AX)(R14*1), R15
|
||||
|
||||
emit_lit_memmove_long_lz4s_s2large_big_loop_back:
|
||||
MOVOU (R12), X4
|
||||
MOVOU 16(R12), X5
|
||||
MOVOA X4, (R15)
|
||||
MOVOA X5, 16(R15)
|
||||
ADDQ $0x20, R15
|
||||
ADDQ $0x20, R12
|
||||
ADDQ $0x20, R14
|
||||
DECQ R13
|
||||
JNA emit_lit_memmove_long_lz4s_s2large_big_loop_back
|
||||
|
||||
emit_lit_memmove_long_lz4s_s2large_forward_sse_loop_32:
|
||||
MOVOU -32(DX)(R14*1), X4
|
||||
MOVOU -16(DX)(R14*1), X5
|
||||
MOVOA X4, -32(AX)(R14*1)
|
||||
MOVOA X5, -16(AX)(R14*1)
|
||||
ADDQ $0x20, R14
|
||||
CMPQ R9, R14
|
||||
JAE emit_lit_memmove_long_lz4s_s2large_forward_sse_loop_32
|
||||
MOVOU X0, (AX)
|
||||
MOVOU X1, 16(AX)
|
||||
MOVOU X2, -32(AX)(R9*1)
|
||||
MOVOU X3, -16(AX)(R9*1)
|
||||
MOVQ R11, AX
|
||||
|
||||
lz4s_s2_lits_emit_done:
|
||||
MOVQ R8, DX
|
||||
|
||||
lz4s_s2_lits_done:
|
||||
CMPQ DX, BX
|
||||
JNE lz4s_s2_match
|
||||
CMPQ R10, $0x03
|
||||
JEQ lz4s_s2_done
|
||||
JMP lz4s_s2_corrupt
|
||||
|
||||
lz4s_s2_match:
|
||||
CMPQ R10, $0x03
|
||||
JEQ lz4s_s2_loop
|
||||
LEAQ 2(DX), R8
|
||||
CMPQ R8, BX
|
||||
JAE lz4s_s2_corrupt
|
||||
MOVWQZX (DX), R9
|
||||
MOVQ R8, DX
|
||||
TESTQ R9, R9
|
||||
JZ lz4s_s2_corrupt
|
||||
CMPQ R9, SI
|
||||
JA lz4s_s2_corrupt
|
||||
CMPQ R10, $0x12
|
||||
JNE lz4s_s2_ml_done
|
||||
|
||||
lz4s_s2_ml_loop:
|
||||
MOVBQZX (DX), R8
|
||||
INCQ DX
|
||||
ADDQ R8, R10
|
||||
CMPQ DX, BX
|
||||
JAE lz4s_s2_corrupt
|
||||
CMPQ R8, $0xff
|
||||
JEQ lz4s_s2_ml_loop
|
||||
|
||||
lz4s_s2_ml_done:
|
||||
ADDQ R10, SI
|
||||
CMPQ R9, DI
|
||||
JNE lz4s_s2_docopy
|
||||
|
||||
// emitRepeat
|
||||
emit_repeat_again_lz4_s2:
|
||||
MOVL R10, R8
|
||||
LEAL -4(R10), R10
|
||||
CMPL R8, $0x08
|
||||
JLE repeat_two_lz4_s2
|
||||
CMPL R8, $0x0c
|
||||
JGE cant_repeat_two_offset_lz4_s2
|
||||
CMPL R9, $0x00000800
|
||||
JLT repeat_two_offset_lz4_s2
|
||||
|
||||
cant_repeat_two_offset_lz4_s2:
|
||||
CMPL R10, $0x00000104
|
||||
JLT repeat_three_lz4_s2
|
||||
CMPL R10, $0x00010100
|
||||
JLT repeat_four_lz4_s2
|
||||
CMPL R10, $0x0100ffff
|
||||
JLT repeat_five_lz4_s2
|
||||
LEAL -16842747(R10), R10
|
||||
MOVL $0xfffb001d, (AX)
|
||||
MOVB $0xff, 4(AX)
|
||||
ADDQ $0x05, AX
|
||||
JMP emit_repeat_again_lz4_s2
|
||||
|
||||
repeat_five_lz4_s2:
|
||||
LEAL -65536(R10), R10
|
||||
MOVL R10, R9
|
||||
MOVW $0x001d, (AX)
|
||||
MOVW R10, 2(AX)
|
||||
SARL $0x10, R9
|
||||
MOVB R9, 4(AX)
|
||||
ADDQ $0x05, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_four_lz4_s2:
|
||||
LEAL -256(R10), R10
|
||||
MOVW $0x0019, (AX)
|
||||
MOVW R10, 2(AX)
|
||||
ADDQ $0x04, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_three_lz4_s2:
|
||||
LEAL -4(R10), R10
|
||||
MOVW $0x0015, (AX)
|
||||
MOVB R10, 2(AX)
|
||||
ADDQ $0x03, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_two_lz4_s2:
|
||||
SHLL $0x02, R10
|
||||
ORL $0x01, R10
|
||||
MOVW R10, (AX)
|
||||
ADDQ $0x02, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_two_offset_lz4_s2:
|
||||
XORQ R8, R8
|
||||
LEAL 1(R8)(R10*4), R10
|
||||
MOVB R9, 1(AX)
|
||||
SARL $0x08, R9
|
||||
SHLL $0x05, R9
|
||||
ORL R9, R10
|
||||
MOVB R10, (AX)
|
||||
ADDQ $0x02, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
lz4s_s2_docopy:
|
||||
MOVQ R9, DI
|
||||
|
||||
// emitCopy
|
||||
CMPL R10, $0x40
|
||||
JLE two_byte_offset_short_lz4_s2
|
||||
CMPL R9, $0x00000800
|
||||
JAE long_offset_short_lz4_s2
|
||||
MOVL $0x00000001, R8
|
||||
LEAL 16(R8), R8
|
||||
MOVB R9, 1(AX)
|
||||
MOVL R9, R11
|
||||
SHRL $0x08, R11
|
||||
SHLL $0x05, R11
|
||||
ORL R11, R8
|
||||
MOVB R8, (AX)
|
||||
ADDQ $0x02, AX
|
||||
SUBL $0x08, R10
|
||||
|
||||
// emitRepeat
|
||||
LEAL -4(R10), R10
|
||||
JMP cant_repeat_two_offset_lz4_s2_emit_copy_short_2b
|
||||
|
||||
emit_repeat_again_lz4_s2_emit_copy_short_2b:
|
||||
MOVL R10, R8
|
||||
LEAL -4(R10), R10
|
||||
CMPL R8, $0x08
|
||||
JLE repeat_two_lz4_s2_emit_copy_short_2b
|
||||
CMPL R8, $0x0c
|
||||
JGE cant_repeat_two_offset_lz4_s2_emit_copy_short_2b
|
||||
CMPL R9, $0x00000800
|
||||
JLT repeat_two_offset_lz4_s2_emit_copy_short_2b
|
||||
|
||||
cant_repeat_two_offset_lz4_s2_emit_copy_short_2b:
|
||||
CMPL R10, $0x00000104
|
||||
JLT repeat_three_lz4_s2_emit_copy_short_2b
|
||||
CMPL R10, $0x00010100
|
||||
JLT repeat_four_lz4_s2_emit_copy_short_2b
|
||||
CMPL R10, $0x0100ffff
|
||||
JLT repeat_five_lz4_s2_emit_copy_short_2b
|
||||
LEAL -16842747(R10), R10
|
||||
MOVL $0xfffb001d, (AX)
|
||||
MOVB $0xff, 4(AX)
|
||||
ADDQ $0x05, AX
|
||||
JMP emit_repeat_again_lz4_s2_emit_copy_short_2b
|
||||
|
||||
repeat_five_lz4_s2_emit_copy_short_2b:
|
||||
LEAL -65536(R10), R10
|
||||
MOVL R10, R9
|
||||
MOVW $0x001d, (AX)
|
||||
MOVW R10, 2(AX)
|
||||
SARL $0x10, R9
|
||||
MOVB R9, 4(AX)
|
||||
ADDQ $0x05, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_four_lz4_s2_emit_copy_short_2b:
|
||||
LEAL -256(R10), R10
|
||||
MOVW $0x0019, (AX)
|
||||
MOVW R10, 2(AX)
|
||||
ADDQ $0x04, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_three_lz4_s2_emit_copy_short_2b:
|
||||
LEAL -4(R10), R10
|
||||
MOVW $0x0015, (AX)
|
||||
MOVB R10, 2(AX)
|
||||
ADDQ $0x03, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_two_lz4_s2_emit_copy_short_2b:
|
||||
SHLL $0x02, R10
|
||||
ORL $0x01, R10
|
||||
MOVW R10, (AX)
|
||||
ADDQ $0x02, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_two_offset_lz4_s2_emit_copy_short_2b:
|
||||
XORQ R8, R8
|
||||
LEAL 1(R8)(R10*4), R10
|
||||
MOVB R9, 1(AX)
|
||||
SARL $0x08, R9
|
||||
SHLL $0x05, R9
|
||||
ORL R9, R10
|
||||
MOVB R10, (AX)
|
||||
ADDQ $0x02, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
long_offset_short_lz4_s2:
|
||||
MOVB $0xee, (AX)
|
||||
MOVW R9, 1(AX)
|
||||
LEAL -60(R10), R10
|
||||
ADDQ $0x03, AX
|
||||
|
||||
// emitRepeat
|
||||
emit_repeat_again_lz4_s2_emit_copy_short:
|
||||
MOVL R10, R8
|
||||
LEAL -4(R10), R10
|
||||
CMPL R8, $0x08
|
||||
JLE repeat_two_lz4_s2_emit_copy_short
|
||||
CMPL R8, $0x0c
|
||||
JGE cant_repeat_two_offset_lz4_s2_emit_copy_short
|
||||
CMPL R9, $0x00000800
|
||||
JLT repeat_two_offset_lz4_s2_emit_copy_short
|
||||
|
||||
cant_repeat_two_offset_lz4_s2_emit_copy_short:
|
||||
CMPL R10, $0x00000104
|
||||
JLT repeat_three_lz4_s2_emit_copy_short
|
||||
CMPL R10, $0x00010100
|
||||
JLT repeat_four_lz4_s2_emit_copy_short
|
||||
CMPL R10, $0x0100ffff
|
||||
JLT repeat_five_lz4_s2_emit_copy_short
|
||||
LEAL -16842747(R10), R10
|
||||
MOVL $0xfffb001d, (AX)
|
||||
MOVB $0xff, 4(AX)
|
||||
ADDQ $0x05, AX
|
||||
JMP emit_repeat_again_lz4_s2_emit_copy_short
|
||||
|
||||
repeat_five_lz4_s2_emit_copy_short:
|
||||
LEAL -65536(R10), R10
|
||||
MOVL R10, R9
|
||||
MOVW $0x001d, (AX)
|
||||
MOVW R10, 2(AX)
|
||||
SARL $0x10, R9
|
||||
MOVB R9, 4(AX)
|
||||
ADDQ $0x05, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_four_lz4_s2_emit_copy_short:
|
||||
LEAL -256(R10), R10
|
||||
MOVW $0x0019, (AX)
|
||||
MOVW R10, 2(AX)
|
||||
ADDQ $0x04, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_three_lz4_s2_emit_copy_short:
|
||||
LEAL -4(R10), R10
|
||||
MOVW $0x0015, (AX)
|
||||
MOVB R10, 2(AX)
|
||||
ADDQ $0x03, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_two_lz4_s2_emit_copy_short:
|
||||
SHLL $0x02, R10
|
||||
ORL $0x01, R10
|
||||
MOVW R10, (AX)
|
||||
ADDQ $0x02, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
repeat_two_offset_lz4_s2_emit_copy_short:
|
||||
XORQ R8, R8
|
||||
LEAL 1(R8)(R10*4), R10
|
||||
MOVB R9, 1(AX)
|
||||
SARL $0x08, R9
|
||||
SHLL $0x05, R9
|
||||
ORL R9, R10
|
||||
MOVB R10, (AX)
|
||||
ADDQ $0x02, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
two_byte_offset_short_lz4_s2:
|
||||
MOVL R10, R8
|
||||
SHLL $0x02, R8
|
||||
CMPL R10, $0x0c
|
||||
JGE emit_copy_three_lz4_s2
|
||||
CMPL R9, $0x00000800
|
||||
JGE emit_copy_three_lz4_s2
|
||||
LEAL -15(R8), R8
|
||||
MOVB R9, 1(AX)
|
||||
SHRL $0x08, R9
|
||||
SHLL $0x05, R9
|
||||
ORL R9, R8
|
||||
MOVB R8, (AX)
|
||||
ADDQ $0x02, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
emit_copy_three_lz4_s2:
|
||||
LEAL -2(R8), R8
|
||||
MOVB R8, (AX)
|
||||
MOVW R9, 1(AX)
|
||||
ADDQ $0x03, AX
|
||||
JMP lz4s_s2_loop
|
||||
|
||||
lz4s_s2_done:
|
||||
MOVQ dst_base+0(FP), CX
|
||||
SUBQ CX, AX
|
||||
MOVQ SI, uncompressed+48(FP)
|
||||
MOVQ AX, dstUsed+56(FP)
|
||||
RET
|
||||
|
||||
lz4s_s2_corrupt:
|
||||
XORQ AX, AX
|
||||
LEAQ -1(AX), SI
|
||||
MOVQ SI, uncompressed+48(FP)
|
||||
RET
|
||||
|
||||
lz4s_s2_dstfull:
|
||||
XORQ AX, AX
|
||||
LEAQ -2(AX), SI
|
||||
MOVQ SI, uncompressed+48(FP)
|
||||
RET
|
||||
|
||||
// func cvtLZ4BlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
|
||||
// Requires: SSE2
|
||||
TEXT ·cvtLZ4BlockSnappyAsm(SB), NOSPLIT, $0-64
|
||||
|
@ -19536,3 +20021,271 @@ lz4_snappy_dstfull:
|
|||
LEAQ -2(AX), SI
|
||||
MOVQ SI, uncompressed+48(FP)
|
||||
RET
|
||||
|
||||
// func cvtLZ4sBlockSnappyAsm(dst []byte, src []byte) (uncompressed int, dstUsed int)
|
||||
// Requires: SSE2
|
||||
TEXT ·cvtLZ4sBlockSnappyAsm(SB), NOSPLIT, $0-64
|
||||
XORQ SI, SI
|
||||
MOVQ dst_base+0(FP), AX
|
||||
MOVQ dst_len+8(FP), CX
|
||||
MOVQ src_base+24(FP), DX
|
||||
MOVQ src_len+32(FP), BX
|
||||
LEAQ (DX)(BX*1), BX
|
||||
LEAQ -10(AX)(CX*1), CX
|
||||
|
||||
lz4s_snappy_loop:
|
||||
CMPQ DX, BX
|
||||
JAE lz4s_snappy_corrupt
|
||||
CMPQ AX, CX
|
||||
JAE lz4s_snappy_dstfull
|
||||
MOVBQZX (DX), DI
|
||||
MOVQ DI, R8
|
||||
MOVQ DI, R9
|
||||
SHRQ $0x04, R8
|
||||
ANDQ $0x0f, R9
|
||||
CMPQ DI, $0xf0
|
||||
JB lz4s_snappy_ll_end
|
||||
|
||||
lz4s_snappy_ll_loop:
|
||||
INCQ DX
|
||||
CMPQ DX, BX
|
||||
JAE lz4s_snappy_corrupt
|
||||
MOVBQZX (DX), DI
|
||||
ADDQ DI, R8
|
||||
CMPQ DI, $0xff
|
||||
JEQ lz4s_snappy_ll_loop
|
||||
|
||||
lz4s_snappy_ll_end:
|
||||
LEAQ (DX)(R8*1), DI
|
||||
ADDQ $0x03, R9
|
||||
CMPQ DI, BX
|
||||
JAE lz4s_snappy_corrupt
|
||||
INCQ DX
|
||||
INCQ DI
|
||||
TESTQ R8, R8
|
||||
JZ lz4s_snappy_lits_done
|
||||
LEAQ (AX)(R8*1), R10
|
||||
CMPQ R10, CX
|
||||
JAE lz4s_snappy_dstfull
|
||||
ADDQ R8, SI
|
||||
LEAL -1(R8), R10
|
||||
CMPL R10, $0x3c
|
||||
JLT one_byte_lz4s_snappy
|
||||
CMPL R10, $0x00000100
|
||||
JLT two_bytes_lz4s_snappy
|
||||
CMPL R10, $0x00010000
|
||||
JLT three_bytes_lz4s_snappy
|
||||
CMPL R10, $0x01000000
|
||||
JLT four_bytes_lz4s_snappy
|
||||
MOVB $0xfc, (AX)
|
||||
MOVL R10, 1(AX)
|
||||
ADDQ $0x05, AX
|
||||
JMP memmove_long_lz4s_snappy
|
||||
|
||||
four_bytes_lz4s_snappy:
|
||||
MOVL R10, R11
|
||||
SHRL $0x10, R11
|
||||
MOVB $0xf8, (AX)
|
||||
MOVW R10, 1(AX)
|
||||
MOVB R11, 3(AX)
|
||||
ADDQ $0x04, AX
|
||||
JMP memmove_long_lz4s_snappy
|
||||
|
||||
three_bytes_lz4s_snappy:
|
||||
MOVB $0xf4, (AX)
|
||||
MOVW R10, 1(AX)
|
||||
ADDQ $0x03, AX
|
||||
JMP memmove_long_lz4s_snappy
|
||||
|
||||
two_bytes_lz4s_snappy:
|
||||
MOVB $0xf0, (AX)
|
||||
MOVB R10, 1(AX)
|
||||
ADDQ $0x02, AX
|
||||
CMPL R10, $0x40
|
||||
JL memmove_lz4s_snappy
|
||||
JMP memmove_long_lz4s_snappy
|
||||
|
||||
one_byte_lz4s_snappy:
|
||||
SHLB $0x02, R10
|
||||
MOVB R10, (AX)
|
||||
ADDQ $0x01, AX
|
||||
|
||||
memmove_lz4s_snappy:
|
||||
LEAQ (AX)(R8*1), R10
|
||||
|
||||
// genMemMoveShort
|
||||
CMPQ R8, $0x08
|
||||
JLE emit_lit_memmove_lz4s_snappy_memmove_move_8
|
||||
CMPQ R8, $0x10
|
||||
JBE emit_lit_memmove_lz4s_snappy_memmove_move_8through16
|
||||
CMPQ R8, $0x20
|
||||
JBE emit_lit_memmove_lz4s_snappy_memmove_move_17through32
|
||||
JMP emit_lit_memmove_lz4s_snappy_memmove_move_33through64
|
||||
|
||||
emit_lit_memmove_lz4s_snappy_memmove_move_8:
|
||||
MOVQ (DX), R11
|
||||
MOVQ R11, (AX)
|
||||
JMP memmove_end_copy_lz4s_snappy
|
||||
|
||||
emit_lit_memmove_lz4s_snappy_memmove_move_8through16:
|
||||
MOVQ (DX), R11
|
||||
MOVQ -8(DX)(R8*1), DX
|
||||
MOVQ R11, (AX)
|
||||
MOVQ DX, -8(AX)(R8*1)
|
||||
JMP memmove_end_copy_lz4s_snappy
|
||||
|
||||
emit_lit_memmove_lz4s_snappy_memmove_move_17through32:
|
||||
MOVOU (DX), X0
|
||||
MOVOU -16(DX)(R8*1), X1
|
||||
MOVOU X0, (AX)
|
||||
MOVOU X1, -16(AX)(R8*1)
|
||||
JMP memmove_end_copy_lz4s_snappy
|
||||
|
||||
emit_lit_memmove_lz4s_snappy_memmove_move_33through64:
|
||||
MOVOU (DX), X0
|
||||
MOVOU 16(DX), X1
|
||||
MOVOU -32(DX)(R8*1), X2
|
||||
MOVOU -16(DX)(R8*1), X3
|
||||
MOVOU X0, (AX)
|
||||
MOVOU X1, 16(AX)
|
||||
MOVOU X2, -32(AX)(R8*1)
|
||||
MOVOU X3, -16(AX)(R8*1)
|
||||
|
||||
memmove_end_copy_lz4s_snappy:
|
||||
MOVQ R10, AX
|
||||
JMP lz4s_snappy_lits_emit_done
|
||||
|
||||
memmove_long_lz4s_snappy:
|
||||
LEAQ (AX)(R8*1), R10
|
||||
|
||||
// genMemMoveLong
|
||||
MOVOU (DX), X0
|
||||
MOVOU 16(DX), X1
|
||||
MOVOU -32(DX)(R8*1), X2
|
||||
MOVOU -16(DX)(R8*1), X3
|
||||
MOVQ R8, R12
|
||||
SHRQ $0x05, R12
|
||||
MOVQ AX, R11
|
||||
ANDL $0x0000001f, R11
|
||||
MOVQ $0x00000040, R13
|
||||
SUBQ R11, R13
|
||||
DECQ R12
|
||||
JA emit_lit_memmove_long_lz4s_snappylarge_forward_sse_loop_32
|
||||
LEAQ -32(DX)(R13*1), R11
|
||||
LEAQ -32(AX)(R13*1), R14
|
||||
|
||||
emit_lit_memmove_long_lz4s_snappylarge_big_loop_back:
|
||||
MOVOU (R11), X4
|
||||
MOVOU 16(R11), X5
|
||||
MOVOA X4, (R14)
|
||||
MOVOA X5, 16(R14)
|
||||
ADDQ $0x20, R14
|
||||
ADDQ $0x20, R11
|
||||
ADDQ $0x20, R13
|
||||
DECQ R12
|
||||
JNA emit_lit_memmove_long_lz4s_snappylarge_big_loop_back
|
||||
|
||||
emit_lit_memmove_long_lz4s_snappylarge_forward_sse_loop_32:
|
||||
MOVOU -32(DX)(R13*1), X4
|
||||
MOVOU -16(DX)(R13*1), X5
|
||||
MOVOA X4, -32(AX)(R13*1)
|
||||
MOVOA X5, -16(AX)(R13*1)
|
||||
ADDQ $0x20, R13
|
||||
CMPQ R8, R13
|
||||
JAE emit_lit_memmove_long_lz4s_snappylarge_forward_sse_loop_32
|
||||
MOVOU X0, (AX)
|
||||
MOVOU X1, 16(AX)
|
||||
MOVOU X2, -32(AX)(R8*1)
|
||||
MOVOU X3, -16(AX)(R8*1)
|
||||
MOVQ R10, AX
|
||||
|
||||
lz4s_snappy_lits_emit_done:
|
||||
MOVQ DI, DX
|
||||
|
||||
lz4s_snappy_lits_done:
|
||||
CMPQ DX, BX
|
||||
JNE lz4s_snappy_match
|
||||
CMPQ R9, $0x03
|
||||
JEQ lz4s_snappy_done
|
||||
JMP lz4s_snappy_corrupt
|
||||
|
||||
lz4s_snappy_match:
|
||||
CMPQ R9, $0x03
|
||||
JEQ lz4s_snappy_loop
|
||||
LEAQ 2(DX), DI
|
||||
CMPQ DI, BX
|
||||
JAE lz4s_snappy_corrupt
|
||||
MOVWQZX (DX), R8
|
||||
MOVQ DI, DX
|
||||
TESTQ R8, R8
|
||||
JZ lz4s_snappy_corrupt
|
||||
CMPQ R8, SI
|
||||
JA lz4s_snappy_corrupt
|
||||
CMPQ R9, $0x12
|
||||
JNE lz4s_snappy_ml_done
|
||||
|
||||
lz4s_snappy_ml_loop:
|
||||
MOVBQZX (DX), DI
|
||||
INCQ DX
|
||||
ADDQ DI, R9
|
||||
CMPQ DX, BX
|
||||
JAE lz4s_snappy_corrupt
|
||||
CMPQ DI, $0xff
|
||||
JEQ lz4s_snappy_ml_loop
|
||||
|
||||
lz4s_snappy_ml_done:
|
||||
ADDQ R9, SI
|
||||
|
||||
// emitCopy
|
||||
two_byte_offset_lz4_s2:
|
||||
CMPL R9, $0x40
|
||||
JLE two_byte_offset_short_lz4_s2
|
||||
MOVB $0xee, (AX)
|
||||
MOVW R8, 1(AX)
|
||||
LEAL -60(R9), R9
|
||||
ADDQ $0x03, AX
|
||||
CMPQ AX, CX
|
||||
JAE lz4s_snappy_loop
|
||||
JMP two_byte_offset_lz4_s2
|
||||
|
||||
two_byte_offset_short_lz4_s2:
|
||||
MOVL R9, DI
|
||||
SHLL $0x02, DI
|
||||
CMPL R9, $0x0c
|
||||
JGE emit_copy_three_lz4_s2
|
||||
CMPL R8, $0x00000800
|
||||
JGE emit_copy_three_lz4_s2
|
||||
LEAL -15(DI), DI
|
||||
MOVB R8, 1(AX)
|
||||
SHRL $0x08, R8
|
||||
SHLL $0x05, R8
|
||||
ORL R8, DI
|
||||
MOVB DI, (AX)
|
||||
ADDQ $0x02, AX
|
||||
JMP lz4s_snappy_loop
|
||||
|
||||
emit_copy_three_lz4_s2:
|
||||
LEAL -2(DI), DI
|
||||
MOVB DI, (AX)
|
||||
MOVW R8, 1(AX)
|
||||
ADDQ $0x03, AX
|
||||
JMP lz4s_snappy_loop
|
||||
|
||||
lz4s_snappy_done:
|
||||
MOVQ dst_base+0(FP), CX
|
||||
SUBQ CX, AX
|
||||
MOVQ SI, uncompressed+48(FP)
|
||||
MOVQ AX, dstUsed+56(FP)
|
||||
RET
|
||||
|
||||
lz4s_snappy_corrupt:
|
||||
XORQ AX, AX
|
||||
LEAQ -1(AX), SI
|
||||
MOVQ SI, uncompressed+48(FP)
|
||||
RET
|
||||
|
||||
lz4s_snappy_dstfull:
|
||||
XORQ AX, AX
|
||||
LEAQ -2(AX), SI
|
||||
MOVQ SI, uncompressed+48(FP)
|
||||
RET
|
||||
|
|
467
vendor/github.com/klauspost/compress/s2/lz4sconvert.go
generated
vendored
Normal file
|
@ -0,0 +1,467 @@
|
|||
// Copyright (c) 2022 Klaus Post. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package s2
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// LZ4sConverter provides conversion from LZ4s.
|
||||
// (Intel modified LZ4 Blocks)
|
||||
// https://cdrdv2-public.intel.com/743912/743912-qat-programmers-guide-v2.0.pdf
|
||||
// LZ4s is a variant of LZ4 block format. LZ4s should be considered as an intermediate compressed block format.
|
||||
// The LZ4s format is selected when the application sets the compType to CPA_DC_LZ4S in CpaDcSessionSetupData.
|
||||
// The LZ4s block returned by the Intel® QAT hardware can be used by an external
|
||||
// software post-processing to generate other compressed data formats.
|
||||
// The following table lists the differences between LZ4 and LZ4s block format. LZ4s block format uses
|
||||
// the same high-level formatting as LZ4 block format with the following encoding changes:
|
||||
// For Min Match of 4 bytes, Copy length value 1-15 means length 4-18 with 18 bytes adding an extra byte.
|
||||
// ONLY "Min match of 4 bytes" is supported.
|
||||
type LZ4sConverter struct {
|
||||
}
|
||||
|
||||
// ConvertBlock will convert an LZ4s block and append it as an S2
|
||||
// block without block length to dst.
|
||||
// The uncompressed size is returned as well.
|
||||
// dst must have capacity to contain the entire compressed block.
|
||||
func (l *LZ4sConverter) ConvertBlock(dst, src []byte) ([]byte, int, error) {
|
||||
if len(src) == 0 {
|
||||
return dst, 0, nil
|
||||
}
|
||||
const debug = false
|
||||
const inline = true
|
||||
const lz4MinMatch = 3
|
||||
|
||||
s, d := 0, len(dst)
|
||||
dst = dst[:cap(dst)]
|
||||
if !debug && hasAmd64Asm {
|
||||
res, sz := cvtLZ4sBlockAsm(dst[d:], src)
|
||||
if res < 0 {
|
||||
const (
|
||||
errCorrupt = -1
|
||||
errDstTooSmall = -2
|
||||
)
|
||||
switch res {
|
||||
case errCorrupt:
|
||||
return nil, 0, ErrCorrupt
|
||||
case errDstTooSmall:
|
||||
return nil, 0, ErrDstTooSmall
|
||||
default:
|
||||
return nil, 0, fmt.Errorf("unexpected result: %d", res)
|
||||
}
|
||||
}
|
||||
if d+sz > len(dst) {
|
||||
return nil, 0, ErrDstTooSmall
|
||||
}
|
||||
return dst[:d+sz], res, nil
|
||||
}
|
||||
|
||||
dLimit := len(dst) - 10
|
||||
var lastOffset uint16
|
||||
var uncompressed int
|
||||
if debug {
|
||||
fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(src), len(dst))
|
||||
}
|
||||
|
||||
for {
|
||||
if s >= len(src) {
|
||||
return dst[:d], 0, ErrCorrupt
|
||||
}
|
||||
// Read literal info
|
||||
token := src[s]
|
||||
ll := int(token >> 4)
|
||||
ml := int(lz4MinMatch + (token & 0xf))
|
||||
|
||||
// If upper nibble is 15, literal length is extended
|
||||
if token >= 0xf0 {
|
||||
for {
|
||||
s++
|
||||
if s >= len(src) {
|
||||
if debug {
|
||||
fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", s, len(src))
|
||||
}
|
||||
return dst[:d], 0, ErrCorrupt
|
||||
}
|
||||
val := src[s]
|
||||
ll += int(val)
|
||||
if val != 255 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Skip past token
|
||||
if s+ll >= len(src) {
|
||||
if debug {
|
||||
fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", s, ll, len(src))
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
s++
|
||||
if ll > 0 {
|
||||
if d+ll > dLimit {
|
||||
return nil, 0, ErrDstTooSmall
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("emit %d literals\n", ll)
|
||||
}
|
||||
d += emitLiteralGo(dst[d:], src[s:s+ll])
|
||||
s += ll
|
||||
uncompressed += ll
|
||||
}
|
||||
|
||||
// Check if we are done...
|
||||
if ml == lz4MinMatch {
|
||||
if s == len(src) {
|
||||
break
|
||||
}
|
||||
// 0 bytes.
|
||||
continue
|
||||
}
|
||||
// 2 byte offset
|
||||
if s >= len(src)-2 {
|
||||
if debug {
|
||||
fmt.Printf("s (%d) >= len(src)-2 (%d)", s, len(src)-2)
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
offset := binary.LittleEndian.Uint16(src[s:])
|
||||
s += 2
|
||||
if offset == 0 {
|
||||
if debug {
|
||||
fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", ml, len(src)-s)
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
if int(offset) > uncompressed {
|
||||
if debug {
|
||||
fmt.Printf("error: offset (%d)> uncompressed (%d)\n", offset, uncompressed)
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
|
||||
if ml == lz4MinMatch+15 {
|
||||
for {
|
||||
if s >= len(src) {
|
||||
if debug {
|
||||
fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
val := src[s]
|
||||
s++
|
||||
ml += int(val)
|
||||
if val != 255 {
|
||||
if s >= len(src) {
|
||||
if debug {
|
||||
fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if offset == lastOffset {
|
||||
if debug {
|
||||
fmt.Printf("emit repeat, length: %d, offset: %d\n", ml, offset)
|
||||
}
|
||||
if !inline {
|
||||
d += emitRepeat16(dst[d:], offset, ml)
|
||||
} else {
|
||||
length := ml
|
||||
dst := dst[d:]
|
||||
for len(dst) > 5 {
|
||||
// Repeat offset, make length cheaper
|
||||
length -= 4
|
||||
if length <= 4 {
|
||||
dst[0] = uint8(length)<<2 | tagCopy1
|
||||
dst[1] = 0
|
||||
d += 2
|
||||
break
|
||||
}
|
||||
if length < 8 && offset < 2048 {
|
||||
// Encode WITH offset
|
||||
dst[1] = uint8(offset)
|
||||
dst[0] = uint8(offset>>8)<<5 | uint8(length)<<2 | tagCopy1
|
||||
d += 2
|
||||
break
|
||||
}
|
||||
if length < (1<<8)+4 {
|
||||
length -= 4
|
||||
dst[2] = uint8(length)
|
||||
dst[1] = 0
|
||||
dst[0] = 5<<2 | tagCopy1
|
||||
d += 3
|
||||
break
|
||||
}
|
||||
if length < (1<<16)+(1<<8) {
|
||||
length -= 1 << 8
|
||||
dst[3] = uint8(length >> 8)
|
||||
dst[2] = uint8(length >> 0)
|
||||
dst[1] = 0
|
||||
dst[0] = 6<<2 | tagCopy1
|
||||
d += 4
|
||||
break
|
||||
}
|
||||
const maxRepeat = (1 << 24) - 1
|
||||
length -= 1 << 16
|
||||
left := 0
|
||||
if length > maxRepeat {
|
||||
left = length - maxRepeat + 4
|
||||
length = maxRepeat - 4
|
||||
}
|
||||
dst[4] = uint8(length >> 16)
|
||||
dst[3] = uint8(length >> 8)
|
||||
dst[2] = uint8(length >> 0)
|
||||
dst[1] = 0
|
||||
dst[0] = 7<<2 | tagCopy1
|
||||
if left > 0 {
|
||||
d += 5 + emitRepeat16(dst[5:], offset, left)
|
||||
break
|
||||
}
|
||||
d += 5
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if debug {
|
||||
fmt.Printf("emit copy, length: %d, offset: %d\n", ml, offset)
|
||||
}
|
||||
if !inline {
|
||||
d += emitCopy16(dst[d:], offset, ml)
|
||||
} else {
|
||||
length := ml
|
||||
dst := dst[d:]
|
||||
for len(dst) > 5 {
|
||||
// Offset no more than 2 bytes.
|
||||
if length > 64 {
|
||||
off := 3
|
||||
if offset < 2048 {
|
||||
// emit 8 bytes as tagCopy1, rest as repeats.
|
||||
dst[1] = uint8(offset)
|
||||
dst[0] = uint8(offset>>8)<<5 | uint8(8-4)<<2 | tagCopy1
|
||||
length -= 8
|
||||
off = 2
|
||||
} else {
|
||||
// Emit a length 60 copy, encoded as 3 bytes.
|
||||
// Emit remaining as repeat value (minimum 4 bytes).
|
||||
dst[2] = uint8(offset >> 8)
|
||||
dst[1] = uint8(offset)
|
||||
dst[0] = 59<<2 | tagCopy2
|
||||
length -= 60
|
||||
}
|
||||
// Emit remaining as repeats, at least 4 bytes remain.
|
||||
d += off + emitRepeat16(dst[off:], offset, length)
|
||||
break
|
||||
}
|
||||
if length >= 12 || offset >= 2048 {
|
||||
// Emit the remaining copy, encoded as 3 bytes.
|
||||
dst[2] = uint8(offset >> 8)
|
||||
dst[1] = uint8(offset)
|
||||
dst[0] = uint8(length-1)<<2 | tagCopy2
|
||||
d += 3
|
||||
break
|
||||
}
|
||||
// Emit the remaining copy, encoded as 2 bytes.
|
||||
dst[1] = uint8(offset)
|
||||
dst[0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
|
||||
d += 2
|
||||
break
|
||||
}
|
||||
}
|
||||
lastOffset = offset
|
||||
}
|
||||
uncompressed += ml
|
||||
if d > dLimit {
|
||||
return nil, 0, ErrDstTooSmall
|
||||
}
|
||||
}
|
||||
|
||||
return dst[:d], uncompressed, nil
|
||||
}
|
||||
|
||||
// ConvertBlockSnappy will convert an LZ4s block and append it
|
||||
// as a Snappy block without block length to dst.
|
||||
// The uncompressed size is returned as well.
|
||||
// dst must have capacity to contain the entire compressed block.
|
||||
func (l *LZ4sConverter) ConvertBlockSnappy(dst, src []byte) ([]byte, int, error) {
|
||||
if len(src) == 0 {
|
||||
return dst, 0, nil
|
||||
}
|
||||
const debug = false
|
||||
const lz4MinMatch = 3
|
||||
|
||||
s, d := 0, len(dst)
|
||||
dst = dst[:cap(dst)]
|
||||
// Use assembly when possible
|
||||
if !debug && hasAmd64Asm {
|
||||
res, sz := cvtLZ4sBlockSnappyAsm(dst[d:], src)
|
||||
if res < 0 {
|
||||
const (
|
||||
errCorrupt = -1
|
||||
errDstTooSmall = -2
|
||||
)
|
||||
switch res {
|
||||
case errCorrupt:
|
||||
return nil, 0, ErrCorrupt
|
||||
case errDstTooSmall:
|
||||
return nil, 0, ErrDstTooSmall
|
||||
default:
|
||||
return nil, 0, fmt.Errorf("unexpected result: %d", res)
|
||||
}
|
||||
}
|
||||
if d+sz > len(dst) {
|
||||
return nil, 0, ErrDstTooSmall
|
||||
}
|
||||
return dst[:d+sz], res, nil
|
||||
}
|
||||
|
||||
dLimit := len(dst) - 10
|
||||
var uncompressed int
|
||||
if debug {
|
||||
fmt.Printf("convert block start: len(src): %d, len(dst):%d \n", len(src), len(dst))
|
||||
}
|
||||
|
||||
for {
|
||||
if s >= len(src) {
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
// Read literal info
|
||||
token := src[s]
|
||||
ll := int(token >> 4)
|
||||
ml := int(lz4MinMatch + (token & 0xf))
|
||||
|
||||
// If upper nibble is 15, literal length is extended
|
||||
if token >= 0xf0 {
|
||||
for {
|
||||
s++
|
||||
if s >= len(src) {
|
||||
if debug {
|
||||
fmt.Printf("error reading ll: s (%d) >= len(src) (%d)\n", s, len(src))
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
val := src[s]
|
||||
ll += int(val)
|
||||
if val != 255 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Skip past token
|
||||
if s+ll >= len(src) {
|
||||
if debug {
|
||||
fmt.Printf("error literals: s+ll (%d+%d) >= len(src) (%d)\n", s, ll, len(src))
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
s++
|
||||
if ll > 0 {
|
||||
if d+ll > dLimit {
|
||||
return nil, 0, ErrDstTooSmall
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("emit %d literals\n", ll)
|
||||
}
|
||||
d += emitLiteralGo(dst[d:], src[s:s+ll])
|
||||
s += ll
|
||||
uncompressed += ll
|
||||
}
|
||||
|
||||
// Check if we are done...
|
||||
if ml == lz4MinMatch {
|
||||
if s == len(src) {
|
||||
break
|
||||
}
|
||||
// 0 bytes.
|
||||
continue
|
||||
}
|
||||
// 2 byte offset
|
||||
if s >= len(src)-2 {
|
||||
if debug {
|
||||
fmt.Printf("s (%d) >= len(src)-2 (%d)", s, len(src)-2)
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
offset := binary.LittleEndian.Uint16(src[s:])
|
||||
s += 2
|
||||
if offset == 0 {
|
||||
if debug {
|
||||
fmt.Printf("error: offset 0, ml: %d, len(src)-s: %d\n", ml, len(src)-s)
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
if int(offset) > uncompressed {
|
||||
if debug {
|
||||
fmt.Printf("error: offset (%d)> uncompressed (%d)\n", offset, uncompressed)
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
|
||||
if ml == lz4MinMatch+15 {
|
||||
for {
|
||||
if s >= len(src) {
|
||||
if debug {
|
||||
fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
val := src[s]
|
||||
s++
|
||||
ml += int(val)
|
||||
if val != 255 {
|
||||
if s >= len(src) {
|
||||
if debug {
|
||||
fmt.Printf("error reading ml: s (%d) >= len(src) (%d)\n", s, len(src))
|
||||
}
|
||||
return nil, 0, ErrCorrupt
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("emit copy, length: %d, offset: %d\n", ml, offset)
|
||||
}
|
||||
length := ml
|
||||
// d += emitCopyNoRepeat(dst[d:], int(offset), ml)
|
||||
for length > 0 {
|
||||
if d >= dLimit {
|
||||
return nil, 0, ErrDstTooSmall
|
||||
}
|
||||
|
||||
// Offset no more than 2 bytes.
|
||||
if length > 64 {
|
||||
// Emit a length 64 copy, encoded as 3 bytes.
|
||||
dst[d+2] = uint8(offset >> 8)
|
||||
dst[d+1] = uint8(offset)
|
||||
dst[d+0] = 63<<2 | tagCopy2
|
||||
length -= 64
|
||||
d += 3
|
||||
continue
|
||||
}
|
||||
if length >= 12 || offset >= 2048 || length < 4 {
|
||||
// Emit the remaining copy, encoded as 3 bytes.
|
||||
dst[d+2] = uint8(offset >> 8)
|
||||
dst[d+1] = uint8(offset)
|
||||
dst[d+0] = uint8(length-1)<<2 | tagCopy2
|
||||
d += 3
|
||||
break
|
||||
}
|
||||
// Emit the remaining copy, encoded as 2 bytes.
|
||||
dst[d+1] = uint8(offset)
|
||||
dst[d+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
|
||||
d += 2
|
||||
break
|
||||
}
|
||||
uncompressed += ml
|
||||
if d > dLimit {
|
||||
return nil, 0, ErrDstTooSmall
|
||||
}
|
||||
}
|
||||
|
||||
return dst[:d], uncompressed, nil
|
||||
}
|
4
vendor/github.com/klauspost/compress/zstd/blockdec.go
generated
vendored
|
@ -9,6 +9,7 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -442,6 +443,9 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
|
|||
}
|
||||
}
|
||||
var err error
|
||||
if debugDecoder {
|
||||
println("huff table input:", len(literals), "CRC:", crc32.ChecksumIEEE(literals))
|
||||
}
|
||||
huff, literals, err = huff0.ReadTable(literals, huff)
|
||||
if err != nil {
|
||||
println("reading huffman table:", err)
|
||||
|
|
2
vendor/github.com/klauspost/compress/zstd/bytebuf.go
generated
vendored
|
@ -54,7 +54,7 @@ func (b *byteBuf) readBig(n int, dst []byte) ([]byte, error) {
|
|||
func (b *byteBuf) readByte() (byte, error) {
|
||||
bb := *b
|
||||
if len(bb) < 1 {
|
||||
return 0, nil
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
r := bb[0]
|
||||
*b = bb[1:]
|
||||
|
|
65
vendor/github.com/klauspost/compress/zstd/enc_best.go
generated
vendored
|
@ -32,7 +32,6 @@ type match struct {
|
|||
length int32
|
||||
rep int32
|
||||
est int32
|
||||
_ [12]byte // Aligned size to cache line: 4+4+4+4+4 bytes + 12 bytes padding = 32 bytes
|
||||
}
|
||||
|
||||
const highScore = 25000
|
||||
|
@ -189,12 +188,6 @@ encodeLoop:
|
|||
panic("offset0 was 0")
|
||||
}
|
||||
|
||||
bestOf := func(a, b *match) *match {
|
||||
if a.est-b.est+(a.s-b.s)*bitsPerByte>>10 < 0 {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
const goodEnough = 100
|
||||
|
||||
nextHashL := hashLen(cv, bestLongTableBits, bestLongLen)
|
||||
|
@ -202,40 +195,41 @@ encodeLoop:
|
|||
candidateL := e.longTable[nextHashL]
|
||||
candidateS := e.table[nextHashS]
|
||||
|
||||
matchAt := func(offset int32, s int32, first uint32, rep int32) match {
|
||||
// Set m to a match at offset if it looks like that will improve compression.
|
||||
improve := func(m *match, offset int32, s int32, first uint32, rep int32) {
|
||||
if s-offset >= e.maxMatchOff || load3232(src, offset) != first {
|
||||
return match{s: s, est: highScore}
|
||||
return
|
||||
}
|
||||
if debugAsserts {
|
||||
if !bytes.Equal(src[s:s+4], src[offset:offset+4]) {
|
||||
panic(fmt.Sprintf("first match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first))
|
||||
}
|
||||
}
|
||||
m := match{offset: offset, s: s, length: 4 + e.matchlen(s+4, offset+4, src), rep: rep}
|
||||
m.estBits(bitsPerByte)
|
||||
return m
|
||||
cand := match{offset: offset, s: s, length: 4 + e.matchlen(s+4, offset+4, src), rep: rep}
|
||||
cand.estBits(bitsPerByte)
|
||||
if m.est >= highScore || cand.est-m.est+(cand.s-m.s)*bitsPerByte>>10 < 0 {
|
||||
*m = cand
|
||||
}
|
||||
}
|
||||
|
||||
m1 := matchAt(candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
m2 := matchAt(candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
m3 := matchAt(candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
m4 := matchAt(candidateS.prev-e.cur, s, uint32(cv), -1)
|
||||
best := bestOf(bestOf(&m1, &m2), bestOf(&m3, &m4))
|
||||
best := match{s: s, est: highScore}
|
||||
improve(&best, candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateS.prev-e.cur, s, uint32(cv), -1)
|
||||
|
||||
if canRepeat && best.length < goodEnough {
|
||||
cv32 := uint32(cv >> 8)
|
||||
spp := s + 1
|
||||
m1 := matchAt(spp-offset1, spp, cv32, 1)
|
||||
m2 := matchAt(spp-offset2, spp, cv32, 2)
|
||||
m3 := matchAt(spp-offset3, spp, cv32, 3)
|
||||
best = bestOf(bestOf(best, &m1), bestOf(&m2, &m3))
|
||||
improve(&best, spp-offset1, spp, cv32, 1)
|
||||
improve(&best, spp-offset2, spp, cv32, 2)
|
||||
improve(&best, spp-offset3, spp, cv32, 3)
|
||||
if best.length > 0 {
|
||||
cv32 = uint32(cv >> 24)
|
||||
spp += 2
|
||||
m1 := matchAt(spp-offset1, spp, cv32, 1)
|
||||
m2 := matchAt(spp-offset2, spp, cv32, 2)
|
||||
m3 := matchAt(spp-offset3, spp, cv32, 3)
|
||||
best = bestOf(bestOf(best, &m1), bestOf(&m2, &m3))
|
||||
improve(&best, spp-offset1, spp, cv32, 1)
|
||||
improve(&best, spp-offset2, spp, cv32, 2)
|
||||
improve(&best, spp-offset3, spp, cv32, 3)
|
||||
}
|
||||
}
|
||||
// Load next and check...
|
||||
|
@ -262,18 +256,16 @@ encodeLoop:
|
|||
candidateL2 := e.longTable[hashLen(cv2, bestLongTableBits, bestLongLen)]
|
||||
|
||||
// Short at s+1
|
||||
m1 := matchAt(candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
// Long at s+1, s+2
|
||||
m2 := matchAt(candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
m3 := matchAt(candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
m4 := matchAt(candidateL2.offset-e.cur, s+1, uint32(cv2), -1)
|
||||
m5 := matchAt(candidateL2.prev-e.cur, s+1, uint32(cv2), -1)
|
||||
best = bestOf(bestOf(bestOf(best, &m1), &m2), bestOf(bestOf(&m3, &m4), &m5))
|
||||
improve(&best, candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
improve(&best, candidateL2.offset-e.cur, s+1, uint32(cv2), -1)
|
||||
improve(&best, candidateL2.prev-e.cur, s+1, uint32(cv2), -1)
|
||||
if false {
|
||||
// Short at s+3.
|
||||
// Too often worse...
|
||||
m := matchAt(e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+2, uint32(cv2>>8), -1)
|
||||
best = bestOf(best, &m)
|
||||
improve(&best, e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+2, uint32(cv2>>8), -1)
|
||||
}
|
||||
// See if we can find a better match by checking where the current best ends.
|
||||
// Use that offset to see if we can find a better full match.
|
||||
|
@ -284,13 +276,10 @@ encodeLoop:
|
|||
// For this compression level 2 yields the best results.
|
||||
const skipBeginning = 2
|
||||
if pos := candidateEnd.offset - e.cur - best.length + skipBeginning; pos >= 0 {
|
||||
m := matchAt(pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
bestEnd := bestOf(best, &m)
|
||||
improve(&best, pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
if pos := candidateEnd.prev - e.cur - best.length + skipBeginning; pos >= 0 {
|
||||
m := matchAt(pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
bestEnd = bestOf(bestEnd, &m)
|
||||
improve(&best, pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
}
|
||||
best = bestEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
6
vendor/github.com/klauspost/compress/zstd/seqdec.go
generated
vendored
|
@ -314,9 +314,6 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
|
|||
}
|
||||
size := ll + ml + len(out)
|
||||
if size-startSize > maxBlockSize {
|
||||
if size-startSize == 424242 {
|
||||
panic("here")
|
||||
}
|
||||
return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
||||
}
|
||||
if size > cap(out) {
|
||||
|
@ -427,8 +424,7 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if space for literals
|
||||
if size := len(s.literals) + len(s.out) - startSize; size > maxBlockSize {
|
||||
if size := len(s.literals) + len(out) - startSize; size > maxBlockSize {
|
||||
return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
||||
}
|
||||
|
||||
|
|
1
vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
generated
vendored
|
@ -148,7 +148,6 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
|
|||
s.seqSize += ctx.litRemain
|
||||
if s.seqSize > maxBlockSize {
|
||||
return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
|
||||
|
||||
}
|
||||
err := br.close()
|
||||
if err != nil {
|
||||
|
|
6
vendor/google.golang.org/protobuf/internal/encoding/text/decode_number.go
generated
vendored
|
@ -88,15 +88,15 @@ func parseNumber(input []byte) number {
|
|||
neg = true
|
||||
s = s[1:]
|
||||
size++
|
||||
if len(s) == 0 {
|
||||
return number{}
|
||||
}
|
||||
// Consume any whitespace or comments between the
|
||||
// negative sign and the rest of the number
|
||||
lenBefore := len(s)
|
||||
s = consume(s, 0)
|
||||
sep = lenBefore - len(s)
|
||||
size += sep
|
||||
if len(s) == 0 {
|
||||
return number{}
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
|
|
2
vendor/google.golang.org/protobuf/internal/version/version.go
generated
vendored
|
@ -52,7 +52,7 @@ import (
|
|||
const (
|
||||
Major = 1
|
||||
Minor = 29
|
||||
Patch = 0
|
||||
Patch = 1
|
||||
PreRelease = ""
|
||||
)
|
||||
|
||||
|
|
18
vendor/modules.txt
vendored
|
@ -81,7 +81,7 @@ github.com/VividCortex/ewma
|
|||
# github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137
|
||||
## explicit; go 1.15
|
||||
github.com/alecthomas/units
|
||||
# github.com/aws/aws-sdk-go v1.44.219
|
||||
# github.com/aws/aws-sdk-go v1.44.221
|
||||
## explicit; go 1.11
|
||||
github.com/aws/aws-sdk-go/aws
|
||||
github.com/aws/aws-sdk-go/aws/awserr
|
||||
|
@ -150,10 +150,10 @@ github.com/aws/aws-sdk-go-v2/internal/timeconv
|
|||
## explicit; go 1.15
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi
|
||||
# github.com/aws/aws-sdk-go-v2/config v1.18.16
|
||||
# github.com/aws/aws-sdk-go-v2/config v1.18.17
|
||||
## explicit; go 1.15
|
||||
github.com/aws/aws-sdk-go-v2/config
|
||||
# github.com/aws/aws-sdk-go-v2/credentials v1.13.16
|
||||
# github.com/aws/aws-sdk-go-v2/credentials v1.13.17
|
||||
## explicit; go 1.15
|
||||
github.com/aws/aws-sdk-go-v2/credentials
|
||||
github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds
|
||||
|
@ -162,11 +162,11 @@ github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client
|
|||
github.com/aws/aws-sdk-go-v2/credentials/processcreds
|
||||
github.com/aws/aws-sdk-go-v2/credentials/ssocreds
|
||||
github.com/aws/aws-sdk-go-v2/credentials/stscreds
|
||||
# github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24
|
||||
# github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.0
|
||||
## explicit; go 1.15
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds/internal/config
|
||||
# github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.56
|
||||
# github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.57
|
||||
## explicit; go 1.15
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager
|
||||
# github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30
|
||||
|
@ -259,7 +259,7 @@ github.com/davecgh/go-spew/spew
|
|||
# github.com/dennwc/varint v1.0.0
|
||||
## explicit; go 1.12
|
||||
github.com/dennwc/varint
|
||||
# github.com/fatih/color v1.14.1
|
||||
# github.com/fatih/color v1.15.0
|
||||
## explicit; go 1.17
|
||||
github.com/fatih/color
|
||||
# github.com/felixge/httpsnoop v1.0.3
|
||||
|
@ -338,7 +338,7 @@ github.com/jmespath/go-jmespath
|
|||
# github.com/jpillora/backoff v1.0.0
|
||||
## explicit; go 1.13
|
||||
github.com/jpillora/backoff
|
||||
# github.com/klauspost/compress v1.16.0
|
||||
# github.com/klauspost/compress v1.16.3
|
||||
## explicit; go 1.18
|
||||
github.com/klauspost/compress
|
||||
github.com/klauspost/compress/flate
|
||||
|
@ -528,7 +528,7 @@ go.uber.org/atomic
|
|||
## explicit; go 1.18
|
||||
go.uber.org/goleak
|
||||
go.uber.org/goleak/internal/stack
|
||||
# golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0
|
||||
# golang.org/x/exp v0.0.0-20230314191032-db074128a8ec
|
||||
## explicit; go 1.18
|
||||
golang.org/x/exp/constraints
|
||||
golang.org/x/exp/slices
|
||||
|
@ -680,7 +680,7 @@ google.golang.org/grpc/serviceconfig
|
|||
google.golang.org/grpc/stats
|
||||
google.golang.org/grpc/status
|
||||
google.golang.org/grpc/tap
|
||||
# google.golang.org/protobuf v1.29.0
|
||||
# google.golang.org/protobuf v1.29.1
|
||||
## explicit; go 1.11
|
||||
google.golang.org/protobuf/encoding/protojson
|
||||
google.golang.org/protobuf/encoding/prototext
|
||||
|
|