chore(deps): bump github.com/go-playground/validator/v10

Bumps [github.com/go-playground/validator/v10](https://github.com/go-playground/validator) from 10.23.0 to 10.24.0.
- [Release notes](https://github.com/go-playground/validator/releases)
- [Commits](https://github.com/go-playground/validator/compare/v10.23.0...v10.24.0)

---
updated-dependencies:
- dependency-name: github.com/go-playground/validator/v10
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2025-01-19 12:17:10 +00:00
committed by GitHub
parent 5ed1eb88a1
commit 1ad7f3d908
22 changed files with 480 additions and 321 deletions

10
go.mod
View File

@@ -20,7 +20,7 @@ require (
github.com/dromara/carbon/v2 v2.5.2 github.com/dromara/carbon/v2 v2.5.2
github.com/eclipse/paho.mqtt.golang v1.5.0 github.com/eclipse/paho.mqtt.golang v1.5.0
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
github.com/go-playground/validator/v10 v10.23.0 github.com/go-playground/validator/v10 v10.24.0
github.com/gregdel/pushover v1.3.1 github.com/gregdel/pushover v1.3.1
github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b // v1.7.2 github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b // v1.7.2
github.com/jedib0t/go-pretty/v6 v6.6.5 github.com/jedib0t/go-pretty/v6 v6.6.5
@@ -75,7 +75,7 @@ require (
github.com/felixge/fgprof v0.9.3 // indirect github.com/felixge/fgprof v0.9.3 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
@@ -134,12 +134,12 @@ require (
go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect
go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/otel/trace v1.28.0 // indirect
golang.org/x/crypto v0.31.0 // indirect golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/net v0.33.0 // indirect golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.10.0 // indirect golang.org/x/sync v0.10.0 // indirect
golang.org/x/term v0.27.0 // indirect golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.7.0 // indirect golang.org/x/time v0.7.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect

20
go.sum
View File

@@ -102,8 +102,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E= github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y= github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -123,8 +123,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -360,8 +360,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -382,8 +382,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -417,8 +417,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2018-2020 Gabriel Vasile Copyright (c) 2018 Gabriel Vasile
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -16,9 +16,6 @@
<a href="https://goreportcard.com/report/github.com/gabriel-vasile/mimetype"> <a href="https://goreportcard.com/report/github.com/gabriel-vasile/mimetype">
<img alt="Go report card" src="https://goreportcard.com/badge/github.com/gabriel-vasile/mimetype"> <img alt="Go report card" src="https://goreportcard.com/badge/github.com/gabriel-vasile/mimetype">
</a> </a>
<a href="https://codecov.io/gh/gabriel-vasile/mimetype">
<img alt="Code coverage" src="https://codecov.io/gh/gabriel-vasile/mimetype/branch/master/graph/badge.svg?token=qcfJF1kkl2"/>
</a>
<a href="LICENSE"> <a href="LICENSE">
<img alt="License" src="https://img.shields.io/badge/License-MIT-green.svg"> <img alt="License" src="https://img.shields.io/badge/License-MIT-green.svg">
</a> </a>
@@ -84,7 +81,7 @@ To prevent loading entire files into memory, when detecting from a
or from a [file](https://pkg.go.dev/github.com/gabriel-vasile/mimetype#DetectFile) or from a [file](https://pkg.go.dev/github.com/gabriel-vasile/mimetype#DetectFile)
**mimetype** limits itself to reading only the header of the input. **mimetype** limits itself to reading only the header of the input.
<div align="center"> <div align="center">
<img alt="structure" src="https://github.com/gabriel-vasile/mimetype/blob/420a05228c6a6efbb6e6f080168a25663414ff36/mimetype.gif?raw=true" width="88%"> <img alt="how project is structured" src="https://raw.githubusercontent.com/gabriel-vasile/mimetype/master/testdata/gif.gif" width="88%">
</div> </div>
## Performance ## Performance

View File

@@ -34,6 +34,7 @@ package json
import ( import (
"fmt" "fmt"
"sync"
) )
type ( type (
@@ -73,10 +74,31 @@ type (
} }
) )
var scannerPool = sync.Pool{
New: func() any {
return &scanner{}
},
}
func newScanner() *scanner {
s := scannerPool.Get().(*scanner)
s.reset()
return s
}
func freeScanner(s *scanner) {
// Avoid hanging on to too much memory in extreme cases.
if len(s.parseState) > 1024 {
s.parseState = nil
}
scannerPool.Put(s)
}
// Scan returns the number of bytes scanned and if there was any error // Scan returns the number of bytes scanned and if there was any error
// in trying to reach the end of data. // in trying to reach the end of data.
func Scan(data []byte) (int, error) { func Scan(data []byte) (int, error) {
s := &scanner{} s := newScanner()
defer freeScanner(s)
_ = checkValid(data, s) _ = checkValid(data, s)
return s.index, s.err return s.index, s.err
} }
@@ -84,7 +106,6 @@ func Scan(data []byte) (int, error) {
// checkValid verifies that data is valid JSON-encoded data. // checkValid verifies that data is valid JSON-encoded data.
// scan is passed in for use by checkValid to avoid an allocation. // scan is passed in for use by checkValid to avoid an allocation.
func checkValid(data []byte, scan *scanner) error { func checkValid(data []byte, scan *scanner) error {
scan.reset()
for _, c := range data { for _, c := range data {
scan.index++ scan.index++
if scan.step(scan, c) == scanError { if scan.step(scan, c) == scanError {
@@ -105,6 +126,8 @@ func (s *scanner) reset() {
s.step = stateBeginValue s.step = stateBeginValue
s.parseState = s.parseState[0:0] s.parseState = s.parseState[0:0]
s.err = nil s.err = nil
s.endTop = false
s.index = 0
} }
// eof tells the scanner that the end of input has been reached. // eof tells the scanner that the end of input has been reached.

View File

@@ -52,10 +52,15 @@ func InstallShieldCab(raw []byte, _ uint32) bool {
} }
// Zstd matches a Zstandard archive file. // Zstd matches a Zstandard archive file.
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md
func Zstd(raw []byte, limit uint32) bool { func Zstd(raw []byte, limit uint32) bool {
return len(raw) >= 4 && if len(raw) < 4 {
(0x22 <= raw[0] && raw[0] <= 0x28 || raw[0] == 0x1E) && // Different Zstandard versions. return false
bytes.HasPrefix(raw[1:], []byte{0xB5, 0x2F, 0xFD}) }
sig := binary.LittleEndian.Uint32(raw)
// Check for Zstandard frames and skippable frames.
return (sig >= 0xFD2FB522 && sig <= 0xFD2FB528) ||
(sig >= 0x184D2A50 && sig <= 0x184D2A5F)
} }
// CRX matches a Chrome extension file: a zip archive prepended by a package header. // CRX matches a Chrome extension file: a zip archive prepended by a package header.
@@ -74,51 +79,85 @@ func CRX(raw []byte, limit uint32) bool {
} }
// Tar matches a (t)ape (ar)chive file. // Tar matches a (t)ape (ar)chive file.
// Tar files are divided into 512 bytes records. First record contains a 257
// bytes header padded with NUL.
func Tar(raw []byte, _ uint32) bool { func Tar(raw []byte, _ uint32) bool {
// The "magic" header field for files in in UStar (POSIX IEEE P1003.1) archives const sizeRecord = 512
// has the prefix "ustar". The values of the remaining bytes in this field vary
// by archiver implementation.
if len(raw) >= 512 && bytes.HasPrefix(raw[257:], []byte{0x75, 0x73, 0x74, 0x61, 0x72}) {
return true
}
if len(raw) < 256 { // The structure of a tar header:
// type TarHeader struct {
// Name [100]byte
// Mode [8]byte
// Uid [8]byte
// Gid [8]byte
// Size [12]byte
// Mtime [12]byte
// Chksum [8]byte
// Linkflag byte
// Linkname [100]byte
// Magic [8]byte
// Uname [32]byte
// Gname [32]byte
// Devmajor [8]byte
// Devminor [8]byte
// }
if len(raw) < sizeRecord {
return false
}
raw = raw[:sizeRecord]
// First 100 bytes of the header represent the file name.
// Check if file looks like Gentoo GLEP binary package.
if bytes.Contains(raw[:100], []byte("/gpkg-1\x00")) {
return false return false
} }
// The older v7 format has no "magic" field, and therefore must be identified // Get the checksum recorded into the file.
// with heuristics based on legal ranges of values for other header fields: recsum := tarParseOctal(raw[148:156])
// https://www.nationalarchives.gov.uk/PRONOM/Format/proFormatSearch.aspx?status=detailReport&id=385&strPageToDisplay=signatures if recsum == -1 {
rules := []struct {
min, max uint8
i int
}{
{0x21, 0xEF, 0},
{0x30, 0x37, 105},
{0x20, 0x37, 106},
{0x00, 0x00, 107},
{0x30, 0x37, 113},
{0x20, 0x37, 114},
{0x00, 0x00, 115},
{0x30, 0x37, 121},
{0x20, 0x37, 122},
{0x00, 0x00, 123},
{0x30, 0x37, 134},
{0x30, 0x37, 146},
{0x30, 0x37, 153},
{0x00, 0x37, 154},
}
for _, r := range rules {
if raw[r.i] < r.min || raw[r.i] > r.max {
return false return false
} }
} sum1, sum2 := tarChksum(raw)
return recsum == sum1 || recsum == sum2
for _, i := range []uint8{135, 147, 155} { }
if raw[i] != 0x00 && raw[i] != 0x20 {
return false // tarParseOctal converts octal string to decimal int.
} func tarParseOctal(b []byte) int64 {
} // Because unused fields are filled with NULs, we need to skip leading NULs.
// Fields may also be padded with spaces or NULs.
return true // So we remove leading and trailing NULs and spaces to be sure.
b = bytes.Trim(b, " \x00")
if len(b) == 0 {
return -1
}
ret := int64(0)
for _, b := range b {
if b == 0 {
break
}
if !(b >= '0' && b <= '7') {
return -1
}
ret = (ret << 3) | int64(b-'0')
}
return ret
}
// tarChksum computes the checksum for the header block b.
// The actual checksum is written to same b block after it has been calculated.
// Before calculation the bytes from b reserved for checksum have placeholder
// value of ASCII space 0x20.
// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
// signed byte values. We compute and return both.
func tarChksum(b []byte) (unsigned, signed int64) {
for i, c := range b {
if 148 <= i && i < 156 {
c = ' ' // Treat the checksum field itself as all spaces.
}
unsigned += int64(c)
signed += int64(int8(c))
}
return unsigned, signed
} }

View File

@@ -21,6 +21,10 @@ var (
SWF = prefix([]byte("CWS"), []byte("FWS"), []byte("ZWS")) SWF = prefix([]byte("CWS"), []byte("FWS"), []byte("ZWS"))
// Torrent has bencoded text in the beginning. // Torrent has bencoded text in the beginning.
Torrent = prefix([]byte("d8:announce")) Torrent = prefix([]byte("d8:announce"))
// PAR1 matches a parquet file.
Par1 = prefix([]byte{0x50, 0x41, 0x52, 0x31})
// CBOR matches a Concise Binary Object Representation https://cbor.io/
CBOR = prefix([]byte{0xD9, 0xD9, 0xF7})
) )
// Java bytecode and Mach-O binaries share the same magic number. // Java bytecode and Mach-O binaries share the same magic number.
@@ -32,7 +36,7 @@ func classOrMachOFat(in []byte) bool {
return false return false
} }
return bytes.HasPrefix(in, []byte{0xCA, 0xFE, 0xBA, 0xBE}) return binary.BigEndian.Uint32(in) == macho.MagicFat
} }
// Class matches a java class file. // Class matches a java class file.
@@ -42,7 +46,7 @@ func Class(raw []byte, limit uint32) bool {
// MachO matches Mach-O binaries format. // MachO matches Mach-O binaries format.
func MachO(raw []byte, limit uint32) bool { func MachO(raw []byte, limit uint32) bool {
if classOrMachOFat(raw) && raw[7] < 20 { if classOrMachOFat(raw) && raw[7] < 0x14 {
return true return true
} }
@@ -170,6 +174,7 @@ var Glb = prefix([]byte("\x67\x6C\x54\x46\x02\x00\x00\x00"),
// TzIf matches a Time Zone Information Format (TZif) file. // TzIf matches a Time Zone Information Format (TZif) file.
// See more: https://tools.ietf.org/id/draft-murchison-tzdist-tzif-00.html#rfc.section.3 // See more: https://tools.ietf.org/id/draft-murchison-tzdist-tzif-00.html#rfc.section.3
// Its header structure is shown below: // Its header structure is shown below:
//
// +---------------+---+ // +---------------+---+
// | magic (4) | <-+-- version (1) // | magic (4) | <-+-- version (1)
// +---------------+---+---------------------------------------+ // +---------------+---+---------------------------------------+

View File

@@ -1,22 +1,14 @@
package magic package magic
import "bytes" import (
"bytes"
)
var ( var (
// AVIF matches an AV1 Image File Format still or animated. // AVIF matches an AV1 Image File Format still or animated.
// Wikipedia page seems outdated listing image/avif-sequence for animations. // Wikipedia page seems outdated listing image/avif-sequence for animations.
// https://github.com/AOMediaCodec/av1-avif/issues/59 // https://github.com/AOMediaCodec/av1-avif/issues/59
AVIF = ftyp([]byte("avif"), []byte("avis")) AVIF = ftyp([]byte("avif"), []byte("avis"))
// Mp4 matches an MP4 file.
Mp4 = ftyp(
[]byte("avc1"), []byte("dash"), []byte("iso2"), []byte("iso3"),
[]byte("iso4"), []byte("iso5"), []byte("iso6"), []byte("isom"),
[]byte("mmp4"), []byte("mp41"), []byte("mp42"), []byte("mp4v"),
[]byte("mp71"), []byte("MSNV"), []byte("NDAS"), []byte("NDSC"),
[]byte("NSDC"), []byte("NSDH"), []byte("NDSM"), []byte("NDSP"),
[]byte("NDSS"), []byte("NDXC"), []byte("NDXH"), []byte("NDXM"),
[]byte("NDXP"), []byte("NDXS"), []byte("F4V "), []byte("F4P "),
)
// ThreeGP matches a 3GPP file. // ThreeGP matches a 3GPP file.
ThreeGP = ftyp( ThreeGP = ftyp(
[]byte("3gp1"), []byte("3gp2"), []byte("3gp3"), []byte("3gp4"), []byte("3gp1"), []byte("3gp2"), []byte("3gp3"), []byte("3gp4"),
@@ -53,6 +45,17 @@ var (
Heif = ftyp([]byte("mif1"), []byte("heim"), []byte("heis"), []byte("avic")) Heif = ftyp([]byte("mif1"), []byte("heim"), []byte("heis"), []byte("avic"))
// HeifSequence matches a High Efficiency Image File Format (HEIF) file sequence. // HeifSequence matches a High Efficiency Image File Format (HEIF) file sequence.
HeifSequence = ftyp([]byte("msf1"), []byte("hevm"), []byte("hevs"), []byte("avcs")) HeifSequence = ftyp([]byte("msf1"), []byte("hevm"), []byte("hevs"), []byte("avcs"))
// Mj2 matches a Motion JPEG 2000 file: https://en.wikipedia.org/wiki/Motion_JPEG_2000.
Mj2 = ftyp([]byte("mj2s"), []byte("mjp2"), []byte("MFSM"), []byte("MGSV"))
// Dvb matches a Digital Video Broadcasting file: https://dvb.org.
// https://cconcolato.github.io/mp4ra/filetype.html
// https://github.com/file/file/blob/512840337ead1076519332d24fefcaa8fac36e06/magic/Magdir/animation#L135-L154
Dvb = ftyp(
[]byte("dby1"), []byte("dsms"), []byte("dts1"), []byte("dts2"),
[]byte("dts3"), []byte("dxo "), []byte("dmb1"), []byte("dmpf"),
[]byte("drc1"), []byte("dv1a"), []byte("dv1b"), []byte("dv2a"),
[]byte("dv2b"), []byte("dv3a"), []byte("dv3b"), []byte("dvr1"),
[]byte("dvt1"), []byte("emsg"))
// TODO: add support for remaining video formats at ftyps.com. // TODO: add support for remaining video formats at ftyps.com.
) )
@@ -86,3 +89,21 @@ func QuickTime(raw []byte, _ uint32) bool {
} }
return bytes.Equal(raw[:8], []byte("\x00\x00\x00\x08wide")) return bytes.Equal(raw[:8], []byte("\x00\x00\x00\x08wide"))
} }
// Mp4 detects an .mp4 file. Mp4 detections only does a basic ftyp check.
// Mp4 has many registered and unregistered code points so it's hard to keep track
// of all. Detection will default on video/mp4 for all ftyp files.
// ISO_IEC_14496-12 is the specification for the iso container.
func Mp4(raw []byte, _ uint32) bool {
if len(raw) < 12 {
return false
}
// ftyps are made out of boxes. The first 4 bytes of the box represent
// its size in big-endian uint32. First box is the ftyp box and it is small
// in size. Check most significant byte is 0 to filter out false positive
// text files that happen to contain the string "ftyp" at index 4.
if raw[0] != 0 {
return false
}
return bytes.Equal(raw[4:8], []byte("ftyp"))
}

View File

@@ -154,7 +154,7 @@ func ftyp(sigs ...[]byte) Detector {
return false return false
} }
for _, s := range sigs { for _, s := range sigs {
if bytes.Equal(raw[4:12], append([]byte("ftyp"), s...)) { if bytes.Equal(raw[8:12], s) {
return true return true
} }
} }
@@ -239,3 +239,13 @@ func min(a, b int) int {
} }
return b return b
} }
type readBuf []byte
func (b *readBuf) advance(n int) bool {
if n < 0 || len(*b) < n {
return false
}
*b = (*b)[n:]
return true
}

View File

@@ -5,58 +5,19 @@ import (
"encoding/binary" "encoding/binary"
) )
var (
xlsxSigFiles = []string{
"xl/worksheets/",
"xl/drawings/",
"xl/theme/",
"xl/_rels/",
"xl/styles.xml",
"xl/workbook.xml",
"xl/sharedStrings.xml",
}
docxSigFiles = []string{
"word/media/",
"word/_rels/document.xml.rels",
"word/document.xml",
"word/styles.xml",
"word/fontTable.xml",
"word/settings.xml",
"word/numbering.xml",
"word/header",
"word/footer",
}
pptxSigFiles = []string{
"ppt/slides/",
"ppt/media/",
"ppt/slideLayouts/",
"ppt/theme/",
"ppt/slideMasters/",
"ppt/tags/",
"ppt/notesMasters/",
"ppt/_rels/",
"ppt/handoutMasters/",
"ppt/notesSlides/",
"ppt/presentation.xml",
"ppt/tableStyles.xml",
"ppt/presProps.xml",
"ppt/viewProps.xml",
}
)
// Xlsx matches a Microsoft Excel 2007 file. // Xlsx matches a Microsoft Excel 2007 file.
func Xlsx(raw []byte, limit uint32) bool { func Xlsx(raw []byte, limit uint32) bool {
return zipContains(raw, xlsxSigFiles...) return zipContains(raw, []byte("xl/"), true)
} }
// Docx matches a Microsoft Word 2007 file. // Docx matches a Microsoft Word 2007 file.
func Docx(raw []byte, limit uint32) bool { func Docx(raw []byte, limit uint32) bool {
return zipContains(raw, docxSigFiles...) return zipContains(raw, []byte("word/"), true)
} }
// Pptx matches a Microsoft PowerPoint 2007 file. // Pptx matches a Microsoft PowerPoint 2007 file.
func Pptx(raw []byte, limit uint32) bool { func Pptx(raw []byte, limit uint32) bool {
return zipContains(raw, pptxSigFiles...) return zipContains(raw, []byte("ppt/"), true)
} }
// Ole matches an Open Linking and Embedding file. // Ole matches an Open Linking and Embedding file.

View File

@@ -1,7 +1,6 @@
package magic package magic
import ( import (
"bufio"
"bytes" "bytes"
"strings" "strings"
"time" "time"
@@ -121,7 +120,7 @@ var (
[]byte("/usr/bin/env wish"), []byte("/usr/bin/env wish"),
) )
// Rtf matches a Rich Text Format file. // Rtf matches a Rich Text Format file.
Rtf = prefix([]byte("{\\rtf1")) Rtf = prefix([]byte("{\\rtf"))
) )
// Text matches a plain text file. // Text matches a plain text file.
@@ -234,9 +233,10 @@ func GeoJSON(raw []byte, limit uint32) bool {
// types. // types.
func NdJSON(raw []byte, limit uint32) bool { func NdJSON(raw []byte, limit uint32) bool {
lCount, hasObjOrArr := 0, false lCount, hasObjOrArr := 0, false
sc := bufio.NewScanner(dropLastLine(raw, limit)) raw = dropLastLine(raw, limit)
for sc.Scan() { var l []byte
l := sc.Bytes() for len(raw) != 0 {
l, raw = scanLine(raw)
// Empty lines are allowed in NDJSON. // Empty lines are allowed in NDJSON.
if l = trimRWS(trimLWS(l)); len(l) == 0 { if l = trimRWS(trimLWS(l)); len(l) == 0 {
continue continue
@@ -301,20 +301,15 @@ func Svg(raw []byte, limit uint32) bool {
} }
// Srt matches a SubRip file. // Srt matches a SubRip file.
func Srt(in []byte, _ uint32) bool { func Srt(raw []byte, _ uint32) bool {
s := bufio.NewScanner(bytes.NewReader(in)) line, raw := scanLine(raw)
if !s.Scan() {
return false
}
// First line must be 1.
if s.Text() != "1" {
return false
}
if !s.Scan() { // First line must be 1.
if string(line) != "1" {
return false return false
} }
secondLine := s.Text() line, raw = scanLine(raw)
secondLine := string(line)
// Timestamp format (e.g: 00:02:16,612 --> 00:02:19,376) limits secondLine // Timestamp format (e.g: 00:02:16,612 --> 00:02:19,376) limits secondLine
// length to exactly 29 characters. // length to exactly 29 characters.
if len(secondLine) != 29 { if len(secondLine) != 29 {
@@ -325,14 +320,12 @@ func Srt(in []byte, _ uint32) bool {
if strings.Contains(secondLine, ".") { if strings.Contains(secondLine, ".") {
return false return false
} }
// For Go <1.17, comma is not recognised as a decimal separator by `time.Parse`.
secondLine = strings.ReplaceAll(secondLine, ",", ".")
// Second line must be a time range. // Second line must be a time range.
ts := strings.Split(secondLine, " --> ") ts := strings.Split(secondLine, " --> ")
if len(ts) != 2 { if len(ts) != 2 {
return false return false
} }
const layout = "15:04:05.000" const layout = "15:04:05,000"
t0, err := time.Parse(layout, ts[0]) t0, err := time.Parse(layout, ts[0])
if err != nil { if err != nil {
return false return false
@@ -345,8 +338,9 @@ func Srt(in []byte, _ uint32) bool {
return false return false
} }
line, _ = scanLine(raw)
// A third line must exist and not be empty. This is the actual subtitle text. // A third line must exist and not be empty. This is the actual subtitle text.
return s.Scan() && len(s.Bytes()) != 0 return len(line) != 0
} }
// Vtt matches a Web Video Text Tracks (WebVTT) file. See // Vtt matches a Web Video Text Tracks (WebVTT) file. See
@@ -373,3 +367,15 @@ func Vtt(raw []byte, limit uint32) bool {
return bytes.Equal(raw, []byte{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) || // UTF-8 BOM and "WEBVTT" return bytes.Equal(raw, []byte{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) || // UTF-8 BOM and "WEBVTT"
bytes.Equal(raw, []byte{0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) // "WEBVTT" bytes.Equal(raw, []byte{0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) // "WEBVTT"
} }
// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
if len(data) > 0 && data[len(data)-1] == '\r' {
return data[0 : len(data)-1]
}
return data
}
func scanLine(b []byte) (line, remainder []byte) {
line, remainder, _ = bytes.Cut(b, []byte("\n"))
return dropCR(line), remainder
}

View File

@@ -1,12 +1,28 @@
package magic package magic
import ( import (
"bufio"
"bytes" "bytes"
"encoding/csv" "encoding/csv"
"errors" "errors"
"io" "io"
"sync"
) )
// A bufio.Reader pool to alleviate problems with memory allocations.
var readerPool = sync.Pool{
New: func() any {
// Initiate with empty source reader.
return bufio.NewReader(nil)
},
}
func newReader(r io.Reader) *bufio.Reader {
br := readerPool.Get().(*bufio.Reader)
br.Reset(r)
return br
}
// Csv matches a comma-separated values file. // Csv matches a comma-separated values file.
func Csv(raw []byte, limit uint32) bool { func Csv(raw []byte, limit uint32) bool {
return sv(raw, ',', limit) return sv(raw, ',', limit)
@@ -18,7 +34,11 @@ func Tsv(raw []byte, limit uint32) bool {
} }
func sv(in []byte, comma rune, limit uint32) bool { func sv(in []byte, comma rune, limit uint32) bool {
r := csv.NewReader(dropLastLine(in, limit)) in = dropLastLine(in, limit)
br := newReader(bytes.NewReader(in))
defer readerPool.Put(br)
r := csv.NewReader(br)
r.Comma = comma r.Comma = comma
r.ReuseRecord = true r.ReuseRecord = true
r.LazyQuotes = true r.LazyQuotes = true
@@ -44,20 +64,14 @@ func sv(in []byte, comma rune, limit uint32) bool {
// mimetype limits itself to ReadLimit bytes when performing a detection. // mimetype limits itself to ReadLimit bytes when performing a detection.
// This means, for file formats like CSV for NDJSON, the last line of the input // This means, for file formats like CSV for NDJSON, the last line of the input
// can be an incomplete line. // can be an incomplete line.
func dropLastLine(b []byte, cutAt uint32) io.Reader { func dropLastLine(b []byte, readLimit uint32) []byte {
if cutAt == 0 { if readLimit == 0 || uint32(len(b)) < readLimit {
return bytes.NewReader(b) return b
} }
if uint32(len(b)) >= cutAt { for i := len(b) - 1; i > 0; i-- {
for i := cutAt - 1; i > 0; i-- {
if b[i] == '\n' { if b[i] == '\n' {
return bytes.NewReader(b[:i]) return b[:i]
} }
} }
return b
// No newline was found between the 0 index and cutAt.
return bytes.NewReader(b[:cutAt])
}
return bytes.NewReader(b)
} }

View File

@@ -3,7 +3,6 @@ package magic
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"strings"
) )
var ( var (
@@ -43,48 +42,88 @@ func Zip(raw []byte, limit uint32) bool {
// Jar matches a Java archive file. // Jar matches a Java archive file.
func Jar(raw []byte, limit uint32) bool { func Jar(raw []byte, limit uint32) bool {
return zipContains(raw, "META-INF/MANIFEST.MF") return zipContains(raw, []byte("META-INF/MANIFEST.MF"), false)
} }
// zipTokenizer holds the source zip file and scanned index. func zipContains(raw, sig []byte, msoCheck bool) bool {
type zipTokenizer struct { b := readBuf(raw)
in []byte pk := []byte("PK\003\004")
i int // current index if len(b) < 0x1E {
} return false
// next returns the next file name from the zip headers.
// https://web.archive.org/web/20191129114319/https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html
func (t *zipTokenizer) next() (fileName string) {
if t.i > len(t.in) {
return
}
in := t.in[t.i:]
// pkSig is the signature of the zip local file header.
pkSig := []byte("PK\003\004")
pkIndex := bytes.Index(in, pkSig)
// 30 is the offset of the file name in the header.
fNameOffset := pkIndex + 30
// end if signature not found or file name offset outside of file.
if pkIndex == -1 || fNameOffset > len(in) {
return
} }
fNameLen := int(binary.LittleEndian.Uint16(in[pkIndex+26 : pkIndex+28])) if !b.advance(0x1E) {
if fNameLen <= 0 || fNameOffset+fNameLen > len(in) { return false
return
} }
t.i += fNameOffset + fNameLen if bytes.HasPrefix(b, sig) {
return string(in[fNameOffset : fNameOffset+fNameLen])
}
// zipContains returns true if the zip file headers from in contain any of the paths.
func zipContains(in []byte, paths ...string) bool {
t := zipTokenizer{in: in}
for i, tok := 0, t.next(); tok != ""; i, tok = i+1, t.next() {
for p := range paths {
if strings.HasPrefix(tok, paths[p]) {
return true return true
} }
if msoCheck {
skipFiles := [][]byte{
[]byte("[Content_Types].xml"),
[]byte("_rels/.rels"),
[]byte("docProps"),
[]byte("customXml"),
[]byte("[trash]"),
}
hasSkipFile := false
for _, sf := range skipFiles {
if bytes.HasPrefix(b, sf) {
hasSkipFile = true
break
}
}
if !hasSkipFile {
return false
}
}
searchOffset := binary.LittleEndian.Uint32(raw[18:]) + 49
if !b.advance(int(searchOffset)) {
return false
}
nextHeader := bytes.Index(raw[searchOffset:], pk)
if !b.advance(nextHeader) {
return false
}
if bytes.HasPrefix(b, sig) {
return true
}
for i := 0; i < 4; i++ {
if !b.advance(0x1A) {
return false
}
nextHeader = bytes.Index(b, pk)
if nextHeader == -1 {
return false
}
if !b.advance(nextHeader + 0x1E) {
return false
}
if bytes.HasPrefix(b, sig) {
return true
}
}
return false
}
// APK matches an Android Package Archive.
// The source of signatures is https://github.com/file/file/blob/1778642b8ba3d947a779a36fcd81f8e807220a19/magic/Magdir/archive#L1820-L1887
func APK(raw []byte, _ uint32) bool {
apkSignatures := [][]byte{
[]byte("AndroidManifest.xml"),
[]byte("META-INF/com/android/build/gradle/app-metadata.properties"),
[]byte("classes.dex"),
[]byte("resources.arsc"),
[]byte("res/drawable"),
}
for _, sig := range apkSignatures {
if zipContains(raw, sig, false) {
return true
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -7,14 +7,15 @@ package mimetype
import ( import (
"io" "io"
"io/ioutil"
"mime" "mime"
"os" "os"
"sync/atomic" "sync/atomic"
) )
var defaultLimit uint32 = 3072
// readLimit is the maximum number of bytes from the input used when detecting. // readLimit is the maximum number of bytes from the input used when detecting.
var readLimit uint32 = 3072 var readLimit uint32 = defaultLimit
// Detect returns the MIME type found from the provided byte slice. // Detect returns the MIME type found from the provided byte slice.
// //
@@ -48,7 +49,7 @@ func DetectReader(r io.Reader) (*MIME, error) {
// Using atomic because readLimit can be written at the same time in other goroutine. // Using atomic because readLimit can be written at the same time in other goroutine.
l := atomic.LoadUint32(&readLimit) l := atomic.LoadUint32(&readLimit)
if l == 0 { if l == 0 {
in, err = ioutil.ReadAll(r) in, err = io.ReadAll(r)
if err != nil { if err != nil {
return errMIME, err return errMIME, err
} }
@@ -103,6 +104,7 @@ func EqualsAny(s string, mimes ...string) bool {
// SetLimit sets the maximum number of bytes read from input when detecting the MIME type. // SetLimit sets the maximum number of bytes read from input when detecting the MIME type.
// Increasing the limit provides better detection for file formats which store // Increasing the limit provides better detection for file formats which store
// their magical numbers towards the end of the file: docx, pptx, xlsx, etc. // their magical numbers towards the end of the file: docx, pptx, xlsx, etc.
// During detection data is read in a single block of size limit, i.e. it is not buffered.
// A limit of 0 means the whole input file will be used. // A limit of 0 means the whole input file will be used.
func SetLimit(limit uint32) { func SetLimit(limit uint32) {
// Using atomic because readLimit can be read at the same time in other goroutine. // Using atomic because readLimit can be read at the same time in other goroutine.

View File

@@ -1,4 +1,4 @@
## 173 Supported MIME types ## 178 Supported MIME types
This file is automatically generated when running tests. Do not edit manually. This file is automatically generated when running tests. Do not edit manually.
Extension | MIME type | Aliases Extension | MIME type | Aliases
@@ -11,6 +11,7 @@ Extension | MIME type | Aliases
**.docx** | application/vnd.openxmlformats-officedocument.wordprocessingml.document | - **.docx** | application/vnd.openxmlformats-officedocument.wordprocessingml.document | -
**.pptx** | application/vnd.openxmlformats-officedocument.presentationml.presentation | - **.pptx** | application/vnd.openxmlformats-officedocument.presentationml.presentation | -
**.epub** | application/epub+zip | - **.epub** | application/epub+zip | -
**.apk** | application/vnd.android.package-archive | -
**.jar** | application/jar | - **.jar** | application/jar | -
**.odt** | application/vnd.oasis.opendocument.text | application/x-vnd.oasis.opendocument.text **.odt** | application/vnd.oasis.opendocument.text | application/x-vnd.oasis.opendocument.text
**.ott** | application/vnd.oasis.opendocument.text-template | application/x-vnd.oasis.opendocument.text-template **.ott** | application/vnd.oasis.opendocument.text-template | application/x-vnd.oasis.opendocument.text-template
@@ -75,21 +76,28 @@ Extension | MIME type | Aliases
**.au** | audio/basic | - **.au** | audio/basic | -
**.mpeg** | video/mpeg | - **.mpeg** | video/mpeg | -
**.mov** | video/quicktime | - **.mov** | video/quicktime | -
**.mqv** | video/quicktime | -
**.mp4** | video/mp4 | - **.mp4** | video/mp4 | -
**.webm** | video/webm | audio/webm **.avif** | image/avif | -
**.3gp** | video/3gpp | video/3gp, audio/3gpp **.3gp** | video/3gpp | video/3gp, audio/3gpp
**.3g2** | video/3gpp2 | video/3g2, audio/3gpp2 **.3g2** | video/3gpp2 | video/3g2, audio/3gpp2
**.mp4** | audio/mp4 | audio/x-mp4a
**.mqv** | video/quicktime | -
**.m4a** | audio/x-m4a | -
**.m4v** | video/x-m4v | -
**.heic** | image/heic | -
**.heic** | image/heic-sequence | -
**.heif** | image/heif | -
**.heif** | image/heif-sequence | -
**.mj2** | video/mj2 | -
**.dvb** | video/vnd.dvb.file | -
**.webm** | video/webm | audio/webm
**.avi** | video/x-msvideo | video/avi, video/msvideo **.avi** | video/x-msvideo | video/avi, video/msvideo
**.flv** | video/x-flv | - **.flv** | video/x-flv | -
**.mkv** | video/x-matroska | - **.mkv** | video/x-matroska | -
**.asf** | video/x-ms-asf | video/asf, video/x-ms-wmv **.asf** | video/x-ms-asf | video/asf, video/x-ms-wmv
**.aac** | audio/aac | - **.aac** | audio/aac | -
**.voc** | audio/x-unknown | - **.voc** | audio/x-unknown | -
**.mp4** | audio/mp4 | audio/x-m4a, audio/x-mp4a
**.m4a** | audio/x-m4a | -
**.m3u** | application/vnd.apple.mpegurl | audio/mpegurl **.m3u** | application/vnd.apple.mpegurl | audio/mpegurl
**.m4v** | video/x-m4v | -
**.rmvb** | application/vnd.rn-realmedia-vbr | - **.rmvb** | application/vnd.rn-realmedia-vbr | -
**.gz** | application/gzip | application/x-gzip, application/x-gunzip, application/gzipped, application/gzip-compressed, application/x-gzip-compressed, gzip/document **.gz** | application/gzip | application/x-gzip, application/x-gunzip, application/gzipped, application/gzip-compressed, application/x-gzip-compressed, gzip/document
**.class** | application/x-java-applet | - **.class** | application/x-java-applet | -
@@ -111,6 +119,7 @@ Extension | MIME type | Aliases
**.mobi** | application/x-mobipocket-ebook | - **.mobi** | application/x-mobipocket-ebook | -
**.lit** | application/x-ms-reader | - **.lit** | application/x-ms-reader | -
**.bpg** | image/bpg | - **.bpg** | image/bpg | -
**.cbor** | application/cbor | -
**.sqlite** | application/vnd.sqlite3 | application/x-sqlite3 **.sqlite** | application/vnd.sqlite3 | application/x-sqlite3
**.dwg** | image/vnd.dwg | image/x-dwg, application/acad, application/x-acad, application/autocad_dwg, application/dwg, application/x-dwg, application/x-autocad, drawing/dwg **.dwg** | image/vnd.dwg | image/x-dwg, application/acad, application/x-acad, application/autocad_dwg, application/dwg, application/x-dwg, application/x-autocad, drawing/dwg
**.nes** | application/vnd.nintendo.snes.rom | - **.nes** | application/vnd.nintendo.snes.rom | -
@@ -118,10 +127,6 @@ Extension | MIME type | Aliases
**.macho** | application/x-mach-binary | - **.macho** | application/x-mach-binary | -
**.qcp** | audio/qcelp | - **.qcp** | audio/qcelp | -
**.icns** | image/x-icns | - **.icns** | image/x-icns | -
**.heic** | image/heic | -
**.heic** | image/heic-sequence | -
**.heif** | image/heif | -
**.heif** | image/heif-sequence | -
**.hdr** | image/vnd.radiance | - **.hdr** | image/vnd.radiance | -
**.mrc** | application/marc | - **.mrc** | application/marc | -
**.mdb** | application/x-msaccess | - **.mdb** | application/x-msaccess | -
@@ -138,13 +143,13 @@ Extension | MIME type | Aliases
**.pat** | image/x-gimp-pat | - **.pat** | image/x-gimp-pat | -
**.gbr** | image/x-gimp-gbr | - **.gbr** | image/x-gimp-gbr | -
**.glb** | model/gltf-binary | - **.glb** | model/gltf-binary | -
**.avif** | image/avif | -
**.cab** | application/x-installshield | - **.cab** | application/x-installshield | -
**.jxr** | image/jxr | image/vnd.ms-photo **.jxr** | image/jxr | image/vnd.ms-photo
**.parquet** | application/vnd.apache.parquet | application/x-parquet
**.txt** | text/plain | - **.txt** | text/plain | -
**.html** | text/html | - **.html** | text/html | -
**.svg** | image/svg+xml | - **.svg** | image/svg+xml | -
**.xml** | text/xml | - **.xml** | text/xml | application/xml
**.rss** | application/rss+xml | text/rss **.rss** | application/rss+xml | text/rss
**.atom** | application/atom+xml | - **.atom** | application/atom+xml | -
**.x3d** | model/x3d+xml | - **.x3d** | model/x3d+xml | -
@@ -159,7 +164,7 @@ Extension | MIME type | Aliases
**.xfdf** | application/vnd.adobe.xfdf | - **.xfdf** | application/vnd.adobe.xfdf | -
**.owl** | application/owl+xml | - **.owl** | application/owl+xml | -
**.php** | text/x-php | - **.php** | text/x-php | -
**.js** | application/javascript | application/x-javascript, text/javascript **.js** | text/javascript | application/x-javascript, application/javascript
**.lua** | text/x-lua | - **.lua** | text/x-lua | -
**.pl** | text/x-perl | - **.pl** | text/x-perl | -
**.py** | text/x-python | text/x-script.python, application/x-python **.py** | text/x-python | text/x-script.python, application/x-python
@@ -167,7 +172,7 @@ Extension | MIME type | Aliases
**.geojson** | application/geo+json | - **.geojson** | application/geo+json | -
**.har** | application/json | - **.har** | application/json | -
**.ndjson** | application/x-ndjson | - **.ndjson** | application/x-ndjson | -
**.rtf** | text/rtf | - **.rtf** | text/rtf | application/rtf
**.srt** | application/x-subrip | application/x-srt, text/x-srt **.srt** | application/x-subrip | application/x-srt, text/x-srt
**.tcl** | text/x-tcl | application/x-tcl **.tcl** | text/x-tcl | application/x-tcl
**.csv** | text/csv | - **.csv** | text/csv | -

View File

@@ -18,14 +18,13 @@ import (
var root = newMIME("application/octet-stream", "", var root = newMIME("application/octet-stream", "",
func([]byte, uint32) bool { return true }, func([]byte, uint32) bool { return true },
xpm, sevenZ, zip, pdf, fdf, ole, ps, psd, p7s, ogg, png, jpg, jxl, jp2, jpx, xpm, sevenZ, zip, pdf, fdf, ole, ps, psd, p7s, ogg, png, jpg, jxl, jp2, jpx,
jpm, jxs, gif, webp, exe, elf, ar, tar, xar, bz2, fits, tiff, bmp, ico, mp3, flac, jpm, jxs, gif, webp, exe, elf, ar, tar, xar, bz2, fits, tiff, bmp, ico, mp3,
midi, ape, musePack, amr, wav, aiff, au, mpeg, quickTime, mqv, mp4, webM, flac, midi, ape, musePack, amr, wav, aiff, au, mpeg, quickTime, mp4, webM,
threeGP, threeG2, avi, flv, mkv, asf, aac, voc, aMp4, m4a, m3u, m4v, rmvb, avi, flv, mkv, asf, aac, voc, m3u, rmvb, gzip, class, swf, crx, ttf, woff,
gzip, class, swf, crx, ttf, woff, woff2, otf, ttc, eot, wasm, shx, dbf, dcm, rar, woff2, otf, ttc, eot, wasm, shx, dbf, dcm, rar, djvu, mobi, lit, bpg, cbor,
djvu, mobi, lit, bpg, sqlite3, dwg, nes, lnk, macho, qcp, icns, heic, sqlite3, dwg, nes, lnk, macho, qcp, icns, hdr, mrc, mdb, accdb, zstd, cab,
heicSeq, heif, heifSeq, hdr, mrc, mdb, accdb, zstd, cab, rpm, xz, lzip, rpm, xz, lzip, torrent, cpio, tzif, xcf, pat, gbr, glb, cabIS, jxr, parquet,
torrent, cpio, tzif, xcf, pat, gbr, glb, avif, cabIS, jxr, // Keep text last because it is the slowest check.
// Keep text last because it is the slowest check
text, text,
) )
@@ -45,7 +44,11 @@ var (
"application/gzip-compressed", "application/x-gzip-compressed", "application/gzip-compressed", "application/x-gzip-compressed",
"gzip/document") "gzip/document")
sevenZ = newMIME("application/x-7z-compressed", ".7z", magic.SevenZ) sevenZ = newMIME("application/x-7z-compressed", ".7z", magic.SevenZ)
zip = newMIME("application/zip", ".zip", magic.Zip, xlsx, docx, pptx, epub, jar, odt, ods, odp, odg, odf, odc, sxc). // APK must be checked before JAR because APK is a subset of JAR.
// This means APK should be a child of JAR detector, but in practice,
// the decisive signature for JAR might be located at the end of the file
// and not reachable because of library readLimit.
zip = newMIME("application/zip", ".zip", magic.Zip, xlsx, docx, pptx, epub, apk, jar, odt, ods, odp, odg, odf, odc, sxc).
alias("application/x-zip", "application/x-zip-compressed") alias("application/x-zip", "application/x-zip-compressed")
tar = newMIME("application/x-tar", ".tar", magic.Tar) tar = newMIME("application/x-tar", ".tar", magic.Tar)
xar = newMIME("application/x-xar", ".xar", magic.Xar) xar = newMIME("application/x-xar", ".xar", magic.Xar)
@@ -58,6 +61,7 @@ var (
pptx = newMIME("application/vnd.openxmlformats-officedocument.presentationml.presentation", ".pptx", magic.Pptx) pptx = newMIME("application/vnd.openxmlformats-officedocument.presentationml.presentation", ".pptx", magic.Pptx)
epub = newMIME("application/epub+zip", ".epub", magic.Epub) epub = newMIME("application/epub+zip", ".epub", magic.Epub)
jar = newMIME("application/jar", ".jar", magic.Jar) jar = newMIME("application/jar", ".jar", magic.Jar)
apk = newMIME("application/vnd.android.package-archive", ".apk", magic.APK)
ole = newMIME("application/x-ole-storage", "", magic.Ole, msi, aaf, msg, xls, pub, ppt, doc) ole = newMIME("application/x-ole-storage", "", magic.Ole, msi, aaf, msg, xls, pub, ppt, doc)
msi = newMIME("application/x-ms-installer", ".msi", magic.Msi). msi = newMIME("application/x-ms-installer", ".msi", magic.Msi).
alias("application/x-windows-installer", "application/x-msi") alias("application/x-windows-installer", "application/x-msi")
@@ -77,7 +81,8 @@ var (
oggAudio = newMIME("audio/ogg", ".oga", magic.OggAudio) oggAudio = newMIME("audio/ogg", ".oga", magic.OggAudio)
oggVideo = newMIME("video/ogg", ".ogv", magic.OggVideo) oggVideo = newMIME("video/ogg", ".ogv", magic.OggVideo)
text = newMIME("text/plain", ".txt", magic.Text, html, svg, xml, php, js, lua, perl, python, json, ndJSON, rtf, srt, tcl, csv, tsv, vCard, iCalendar, warc, vtt) text = newMIME("text/plain", ".txt", magic.Text, html, svg, xml, php, js, lua, perl, python, json, ndJSON, rtf, srt, tcl, csv, tsv, vCard, iCalendar, warc, vtt)
xml = newMIME("text/xml", ".xml", magic.XML, rss, atom, x3d, kml, xliff, collada, gml, gpx, tcx, amf, threemf, xfdf, owl2) xml = newMIME("text/xml", ".xml", magic.XML, rss, atom, x3d, kml, xliff, collada, gml, gpx, tcx, amf, threemf, xfdf, owl2).
alias("application/xml")
json = newMIME("application/json", ".json", magic.JSON, geoJSON, har) json = newMIME("application/json", ".json", magic.JSON, geoJSON, har)
har = newMIME("application/json", ".har", magic.HAR) har = newMIME("application/json", ".har", magic.HAR)
csv = newMIME("text/csv", ".csv", magic.Csv) csv = newMIME("text/csv", ".csv", magic.Csv)
@@ -86,9 +91,9 @@ var (
ndJSON = newMIME("application/x-ndjson", ".ndjson", magic.NdJSON) ndJSON = newMIME("application/x-ndjson", ".ndjson", magic.NdJSON)
html = newMIME("text/html", ".html", magic.HTML) html = newMIME("text/html", ".html", magic.HTML)
php = newMIME("text/x-php", ".php", magic.Php) php = newMIME("text/x-php", ".php", magic.Php)
rtf = newMIME("text/rtf", ".rtf", magic.Rtf) rtf = newMIME("text/rtf", ".rtf", magic.Rtf).alias("application/rtf")
js = newMIME("application/javascript", ".js", magic.Js). js = newMIME("text/javascript", ".js", magic.Js).
alias("application/x-javascript", "text/javascript") alias("application/x-javascript", "application/javascript")
srt = newMIME("application/x-subrip", ".srt", magic.Srt). srt = newMIME("application/x-subrip", ".srt", magic.Srt).
alias("application/x-srt", "text/x-srt") alias("application/x-srt", "text/x-srt")
vtt = newMIME("text/vtt", ".vtt", magic.Vtt) vtt = newMIME("text/vtt", ".vtt", magic.Vtt)
@@ -156,12 +161,14 @@ var (
aac = newMIME("audio/aac", ".aac", magic.AAC) aac = newMIME("audio/aac", ".aac", magic.AAC)
voc = newMIME("audio/x-unknown", ".voc", magic.Voc) voc = newMIME("audio/x-unknown", ".voc", magic.Voc)
aMp4 = newMIME("audio/mp4", ".mp4", magic.AMp4). aMp4 = newMIME("audio/mp4", ".mp4", magic.AMp4).
alias("audio/x-m4a", "audio/x-mp4a") alias("audio/x-mp4a")
m4a = newMIME("audio/x-m4a", ".m4a", magic.M4a) m4a = newMIME("audio/x-m4a", ".m4a", magic.M4a)
m3u = newMIME("application/vnd.apple.mpegurl", ".m3u", magic.M3u). m3u = newMIME("application/vnd.apple.mpegurl", ".m3u", magic.M3u).
alias("audio/mpegurl") alias("audio/mpegurl")
m4v = newMIME("video/x-m4v", ".m4v", magic.M4v) m4v = newMIME("video/x-m4v", ".m4v", magic.M4v)
mp4 = newMIME("video/mp4", ".mp4", magic.Mp4) mj2 = newMIME("video/mj2", ".mj2", magic.Mj2)
dvb = newMIME("video/vnd.dvb.file", ".dvb", magic.Dvb)
mp4 = newMIME("video/mp4", ".mp4", magic.Mp4, avif, threeGP, threeG2, aMp4, mqv, m4a, m4v, heic, heicSeq, heif, heifSeq, mj2, dvb)
webM = newMIME("video/webm", ".webm", magic.WebM). webM = newMIME("video/webm", ".webm", magic.WebM).
alias("audio/webm") alias("audio/webm")
mpeg = newMIME("video/mpeg", ".mpeg", magic.Mpeg) mpeg = newMIME("video/mpeg", ".mpeg", magic.Mpeg)
@@ -257,4 +264,7 @@ var (
xfdf = newMIME("application/vnd.adobe.xfdf", ".xfdf", magic.Xfdf) xfdf = newMIME("application/vnd.adobe.xfdf", ".xfdf", magic.Xfdf)
glb = newMIME("model/gltf-binary", ".glb", magic.Glb) glb = newMIME("model/gltf-binary", ".glb", magic.Glb)
jxr = newMIME("image/jxr", ".jxr", magic.Jxr).alias("image/vnd.ms-photo") jxr = newMIME("image/jxr", ".jxr", magic.Jxr).alias("image/vnd.ms-photo")
parquet = newMIME("application/vnd.apache.parquet", ".parquet", magic.Par1).
alias("application/x-parquet")
cbor = newMIME("application/cbor", ".cbor", magic.CBOR)
) )

View File

@@ -1,7 +1,7 @@
Package validator Package validator
================= =================
<img align="right" src="logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) <img align="right" src="logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Project status](https://img.shields.io/badge/version-10.23.0-green.svg) ![Project status](https://img.shields.io/badge/version-10.24.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator)
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
@@ -22,6 +22,11 @@ It has the following **unique** features:
- Customizable i18n aware error messages. - Customizable i18n aware error messages.
- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding) - Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding)
A Call for Maintainers
----------------------
Please read the discussiong started [here](https://github.com/go-playground/validator/discussions/1330) if you are interested in contributing/helping maintain this package.
Installation Installation
------------ ------------
@@ -266,74 +271,75 @@ validate := validator.New(validator.WithRequiredStructEnabled())
Benchmarks Benchmarks
------ ------
###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 ###### Run on MacBook Pro Max M3
```go ```go
go version go1.21.0 darwin/arm64 go version go1.23.3 darwin/arm64
goos: darwin goos: darwin
goarch: arm64 goarch: arm64
cpu: Apple M3 Max
pkg: github.com/go-playground/validator/v10 pkg: github.com/go-playground/validator/v10
BenchmarkFieldSuccess-8 33142266 35.94 ns/op 0 B/op 0 allocs/op BenchmarkFieldSuccess-16 42461943 27.88 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-8 200816191 6.568 ns/op 0 B/op 0 allocs/op BenchmarkFieldSuccessParallel-16 486632887 2.289 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-8 6779707 175.1 ns/op 200 B/op 4 allocs/op BenchmarkFieldFailure-16 9566167 121.3 ns/op 200 B/op 4 allocs/op
BenchmarkFieldFailureParallel-8 11044147 108.4 ns/op 200 B/op 4 allocs/op BenchmarkFieldFailureParallel-16 17551471 83.68 ns/op 200 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-8 6054232 194.4 ns/op 97 B/op 5 allocs/op BenchmarkFieldArrayDiveSuccess-16 7602306 155.6 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8 12523388 94.07 ns/op 97 B/op 5 allocs/op BenchmarkFieldArrayDiveSuccessParallel-16 20664610 59.80 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveFailure-8 3587043 334.3 ns/op 300 B/op 10 allocs/op BenchmarkFieldArrayDiveFailure-16 4659756 252.9 ns/op 301 B/op 10 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8 5816665 200.8 ns/op 300 B/op 10 allocs/op BenchmarkFieldArrayDiveFailureParallel-16 8010116 152.9 ns/op 301 B/op 10 allocs/op
BenchmarkFieldMapDiveSuccess-8 2217910 540.1 ns/op 288 B/op 14 allocs/op BenchmarkFieldMapDiveSuccess-16 2834575 421.2 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8 4446698 258.7 ns/op 288 B/op 14 allocs/op BenchmarkFieldMapDiveSuccessParallel-16 7179700 171.8 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveFailure-8 2392759 504.6 ns/op 376 B/op 13 allocs/op BenchmarkFieldMapDiveFailure-16 3081728 384.4 ns/op 376 B/op 13 allocs/op
BenchmarkFieldMapDiveFailureParallel-8 4244199 286.9 ns/op 376 B/op 13 allocs/op BenchmarkFieldMapDiveFailureParallel-16 6058137 204.0 ns/op 377 B/op 13 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8 2005857 592.1 ns/op 288 B/op 14 allocs/op BenchmarkFieldMapDiveWithKeysSuccess-16 2544975 464.8 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8 4400850 296.9 ns/op 288 B/op 14 allocs/op BenchmarkFieldMapDiveWithKeysSuccessParallel-16 6661954 181.4 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8 1850227 643.8 ns/op 553 B/op 16 allocs/op BenchmarkFieldMapDiveWithKeysFailure-16 2435484 490.7 ns/op 553 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8 3293233 375.1 ns/op 553 B/op 16 allocs/op BenchmarkFieldMapDiveWithKeysFailureParallel-16 4249617 282.0 ns/op 554 B/op 16 allocs/op
BenchmarkFieldCustomTypeSuccess-8 12174412 98.25 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeSuccess-16 14943525 77.35 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8 34389907 35.49 ns/op 32 B/op 2 allocs/op BenchmarkFieldCustomTypeSuccessParallel-16 64051954 20.61 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-8 7582524 156.6 ns/op 184 B/op 3 allocs/op BenchmarkFieldCustomTypeFailure-16 10721384 107.1 ns/op 184 B/op 3 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8 13019902 92.79 ns/op 184 B/op 3 allocs/op BenchmarkFieldCustomTypeFailureParallel-16 18714495 69.77 ns/op 184 B/op 3 allocs/op
BenchmarkFieldOrTagSuccess-8 3427260 349.4 ns/op 16 B/op 1 allocs/op BenchmarkFieldOrTagSuccess-16 4063124 294.3 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8 15144128 81.25 ns/op 16 B/op 1 allocs/op BenchmarkFieldOrTagSuccessParallel-16 31903756 41.22 ns/op 18 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-8 5913546 201.9 ns/op 216 B/op 5 allocs/op BenchmarkFieldOrTagFailure-16 7748558 146.8 ns/op 216 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-8 9810212 113.7 ns/op 216 B/op 5 allocs/op BenchmarkFieldOrTagFailureParallel-16 13139854 92.05 ns/op 216 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-8 13456327 87.66 ns/op 16 B/op 1 allocs/op BenchmarkStructLevelValidationSuccess-16 16808389 70.25 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8 41818888 27.77 ns/op 16 B/op 1 allocs/op BenchmarkStructLevelValidationSuccessParallel-16 90686955 14.47 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationFailure-8 4166284 272.6 ns/op 264 B/op 7 allocs/op BenchmarkStructLevelValidationFailure-16 5818791 200.2 ns/op 264 B/op 7 allocs/op
BenchmarkStructLevelValidationFailureParallel-8 7594581 152.1 ns/op 264 B/op 7 allocs/op BenchmarkStructLevelValidationFailureParallel-16 11115874 107.5 ns/op 264 B/op 7 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8 6508082 182.6 ns/op 32 B/op 2 allocs/op BenchmarkStructSimpleCustomTypeSuccess-16 7764956 151.9 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8 23078605 54.78 ns/op 32 B/op 2 allocs/op BenchmarkStructSimpleCustomTypeSuccessParallel-16 52316265 30.37 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8 3118352 381.0 ns/op 416 B/op 9 allocs/op BenchmarkStructSimpleCustomTypeFailure-16 4195429 277.2 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8 5300738 224.1 ns/op 432 B/op 10 allocs/op BenchmarkStructSimpleCustomTypeFailureParallel-16 7305661 164.6 ns/op 432 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-8 4761807 251.1 ns/op 216 B/op 5 allocs/op BenchmarkStructFilteredSuccess-16 6312625 186.1 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredSuccessParallel-8 8792598 128.6 ns/op 216 B/op 5 allocs/op BenchmarkStructFilteredSuccessParallel-16 13684459 93.42 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailure-8 5202573 232.1 ns/op 216 B/op 5 allocs/op BenchmarkStructFilteredFailure-16 6751482 171.2 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailureParallel-8 9591267 121.4 ns/op 216 B/op 5 allocs/op BenchmarkStructFilteredFailureParallel-16 14146070 86.93 ns/op 216 B/op 5 allocs/op
BenchmarkStructPartialSuccess-8 5188512 231.6 ns/op 224 B/op 4 allocs/op BenchmarkStructPartialSuccess-16 6544448 177.3 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialSuccessParallel-8 9179776 123.1 ns/op 224 B/op 4 allocs/op BenchmarkStructPartialSuccessParallel-16 13951946 88.73 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialFailure-8 3071212 392.5 ns/op 440 B/op 9 allocs/op BenchmarkStructPartialFailure-16 4075833 287.5 ns/op 440 B/op 9 allocs/op
BenchmarkStructPartialFailureParallel-8 5344261 223.7 ns/op 440 B/op 9 allocs/op BenchmarkStructPartialFailureParallel-16 7490805 161.3 ns/op 440 B/op 9 allocs/op
BenchmarkStructExceptSuccess-8 3184230 375.0 ns/op 424 B/op 8 allocs/op BenchmarkStructExceptSuccess-16 4107187 281.4 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptSuccessParallel-8 10090130 108.9 ns/op 208 B/op 3 allocs/op BenchmarkStructExceptSuccessParallel-16 15979173 80.86 ns/op 208 B/op 3 allocs/op
BenchmarkStructExceptFailure-8 3347226 357.7 ns/op 424 B/op 8 allocs/op BenchmarkStructExceptFailure-16 4434372 264.3 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptFailureParallel-8 5654923 209.5 ns/op 424 B/op 8 allocs/op BenchmarkStructExceptFailureParallel-16 8081367 154.1 ns/op 424 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8 5232265 229.1 ns/op 56 B/op 3 allocs/op BenchmarkStructSimpleCrossFieldSuccess-16 6459542 183.4 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8 17436674 64.75 ns/op 56 B/op 3 allocs/op BenchmarkStructSimpleCrossFieldSuccessParallel-16 41013781 37.95 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8 3128613 383.6 ns/op 272 B/op 8 allocs/op BenchmarkStructSimpleCrossFieldFailure-16 4034998 292.1 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8 6994113 168.8 ns/op 272 B/op 8 allocs/op BenchmarkStructSimpleCrossFieldFailureParallel-16 11348446 115.3 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3506487 340.9 ns/op 64 B/op 4 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccess-16 4448528 267.7 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 13431300 91.77 ns/op 64 B/op 4 allocs/op BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-16 26813619 48.33 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2410566 500.9 ns/op 288 B/op 9 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailure-16 3090646 384.5 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 6344510 188.2 ns/op 288 B/op 9 allocs/op BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-16 9870906 129.5 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-8 8922726 133.8 ns/op 0 B/op 0 allocs/op BenchmarkStructSimpleSuccess-16 10675562 109.5 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-8 55291153 23.63 ns/op 0 B/op 0 allocs/op BenchmarkStructSimpleSuccessParallel-16 131159784 8.932 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-8 3171553 378.4 ns/op 416 B/op 9 allocs/op BenchmarkStructSimpleFailure-16 4094979 286.6 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-8 5571692 212.0 ns/op 416 B/op 9 allocs/op BenchmarkStructSimpleFailureParallel-16 7606663 157.9 ns/op 416 B/op 9 allocs/op
BenchmarkStructComplexSuccess-8 1683750 714.5 ns/op 224 B/op 5 allocs/op BenchmarkStructComplexSuccess-16 2073470 576.0 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexSuccessParallel-8 4578046 257.0 ns/op 224 B/op 5 allocs/op BenchmarkStructComplexSuccessParallel-16 7821831 161.3 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexFailure-8 481585 2547 ns/op 3041 B/op 48 allocs/op BenchmarkStructComplexFailure-16 576358 2001 ns/op 3042 B/op 48 allocs/op
BenchmarkStructComplexFailureParallel-8 965764 1577 ns/op 3040 B/op 48 allocs/op BenchmarkStructComplexFailureParallel-16 1000000 1171 ns/op 3041 B/op 48 allocs/op
BenchmarkOneof-8 17380881 68.50 ns/op 0 B/op 0 allocs/op BenchmarkOneof-16 22503973 52.82 ns/op 0 B/op 0 allocs/op
BenchmarkOneofParallel-8 8084733 153.5 ns/op 0 B/op 0 allocs/op BenchmarkOneofParallel-16 8538474 140.4 ns/op 0 B/op 0 allocs/op
``` ```
Complementary Software Complementary Software
@@ -349,6 +355,20 @@ How to Contribute
Make a pull request... Make a pull request...
Maintenance and support for SDK major versions
----------------------------------------------
See prior discussion [here](https://github.com/go-playground/validator/discussions/1342) for more details.
This package is aligned with the [Go release policy](https://go.dev/doc/devel/release) in that support is guaranteed for
the two most recent major versions.
This does not mean the package will not work with older versions of Go, only that we reserve the right to increase the
MSGV(Minimum Supported Go Version) when the need arises to address Security issues/patches, OS issues & support or newly
introduced functionality that would greatly benefit the maintenance and/or usage of this package.
If and when the MSGV is increased it will be done so in a minimum of a `Minor` release bump.
License License
------- -------
Distributed under MIT License, please see license file within the code for more details. Distributed under MIT License, please see license file within the code for more details.

View File

@@ -60,7 +60,7 @@ func configFromServer(h1 *http.Server, h2 *Server) http2Config {
return conf return conf
} }
// configFromServer merges configuration settings from h2 and h2.t1.HTTP2 // configFromTransport merges configuration settings from h2 and h2.t1.HTTP2
// (the net/http Transport). // (the net/http Transport).
func configFromTransport(h2 *Transport) http2Config { func configFromTransport(h2 *Transport) http2Config {
conf := http2Config{ conf := http2Config{

View File

@@ -13,7 +13,7 @@ func fillNetHTTPServerConfig(conf *http2Config, srv *http.Server) {
fillNetHTTPConfig(conf, srv.HTTP2) fillNetHTTPConfig(conf, srv.HTTP2)
} }
// fillNetHTTPServerConfig sets fields in conf from tr.HTTP2. // fillNetHTTPTransportConfig sets fields in conf from tr.HTTP2.
func fillNetHTTPTransportConfig(conf *http2Config, tr *http.Transport) { func fillNetHTTPTransportConfig(conf *http2Config, tr *http.Transport) {
fillNetHTTPConfig(conf, tr.HTTP2) fillNetHTTPConfig(conf, tr.HTTP2)
} }

View File

@@ -375,6 +375,7 @@ type ClientConn struct {
doNotReuse bool // whether conn is marked to not be reused for any future requests doNotReuse bool // whether conn is marked to not be reused for any future requests
closing bool closing bool
closed bool closed bool
closedOnIdle bool // true if conn was closed for idleness
seenSettings bool // true if we've seen a settings frame, false otherwise seenSettings bool // true if we've seen a settings frame, false otherwise
seenSettingsChan chan struct{} // closed when seenSettings is true or frame reading fails seenSettingsChan chan struct{} // closed when seenSettings is true or frame reading fails
wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back
@@ -1089,10 +1090,12 @@ func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) {
// If this connection has never been used for a request and is closed, // If this connection has never been used for a request and is closed,
// then let it take a request (which will fail). // then let it take a request (which will fail).
// If the conn was closed for idleness, we're racing the idle timer;
// don't try to use the conn. (Issue #70515.)
// //
// This avoids a situation where an error early in a connection's lifetime // This avoids a situation where an error early in a connection's lifetime
// goes unreported. // goes unreported.
if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed { if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed && !cc.closedOnIdle {
st.canTakeNewRequest = true st.canTakeNewRequest = true
} }
@@ -1155,6 +1158,7 @@ func (cc *ClientConn) closeIfIdle() {
return return
} }
cc.closed = true cc.closed = true
cc.closedOnIdle = true
nextID := cc.nextStreamID nextID := cc.nextStreamID
// TODO: do clients send GOAWAY too? maybe? Just Close: // TODO: do clients send GOAWAY too? maybe? Just Close:
cc.mu.Unlock() cc.mu.Unlock()
@@ -2434,9 +2438,12 @@ func (rl *clientConnReadLoop) cleanup() {
// This avoids a situation where new connections are constantly created, // This avoids a situation where new connections are constantly created,
// added to the pool, fail, and are removed from the pool, without any error // added to the pool, fail, and are removed from the pool, without any error
// being surfaced to the user. // being surfaced to the user.
const unusedWaitTime = 5 * time.Second unusedWaitTime := 5 * time.Second
if cc.idleTimeout > 0 && unusedWaitTime > cc.idleTimeout {
unusedWaitTime = cc.idleTimeout
}
idleTime := cc.t.now().Sub(cc.lastActive) idleTime := cc.t.now().Sub(cc.lastActive)
if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime { if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime && !cc.closedOnIdle {
cc.idleTimer = cc.t.afterFunc(unusedWaitTime-idleTime, func() { cc.idleTimer = cc.t.afterFunc(unusedWaitTime-idleTime, func() {
cc.t.connPool().MarkDead(cc) cc.t.connPool().MarkDead(cc)
}) })

12
vendor/modules.txt vendored
View File

@@ -198,7 +198,7 @@ github.com/felixge/httpsnoop
# github.com/fxamacker/cbor/v2 v2.7.0 # github.com/fxamacker/cbor/v2 v2.7.0
## explicit; go 1.17 ## explicit; go 1.17
github.com/fxamacker/cbor/v2 github.com/fxamacker/cbor/v2
# github.com/gabriel-vasile/mimetype v1.4.3 # github.com/gabriel-vasile/mimetype v1.4.8
## explicit; go 1.20 ## explicit; go 1.20
github.com/gabriel-vasile/mimetype github.com/gabriel-vasile/mimetype
github.com/gabriel-vasile/mimetype/internal/charset github.com/gabriel-vasile/mimetype/internal/charset
@@ -231,8 +231,8 @@ github.com/go-playground/locales/currency
# github.com/go-playground/universal-translator v0.18.1 # github.com/go-playground/universal-translator v0.18.1
## explicit; go 1.18 ## explicit; go 1.18
github.com/go-playground/universal-translator github.com/go-playground/universal-translator
# github.com/go-playground/validator/v10 v10.23.0 # github.com/go-playground/validator/v10 v10.24.0
## explicit; go 1.18 ## explicit; go 1.20
github.com/go-playground/validator/v10 github.com/go-playground/validator/v10
# github.com/gogo/protobuf v1.3.2 # github.com/gogo/protobuf v1.3.2
## explicit; go 1.15 ## explicit; go 1.15
@@ -497,7 +497,7 @@ go.opentelemetry.io/otel/metric/embedded
## explicit; go 1.21 ## explicit; go 1.21
go.opentelemetry.io/otel/trace go.opentelemetry.io/otel/trace
go.opentelemetry.io/otel/trace/embedded go.opentelemetry.io/otel/trace/embedded
# golang.org/x/crypto v0.31.0 # golang.org/x/crypto v0.32.0
## explicit; go 1.20 ## explicit; go 1.20
golang.org/x/crypto/pbkdf2 golang.org/x/crypto/pbkdf2
golang.org/x/crypto/scrypt golang.org/x/crypto/scrypt
@@ -508,7 +508,7 @@ golang.org/x/exp/maps
# golang.org/x/mod v0.22.0 # golang.org/x/mod v0.22.0
## explicit; go 1.22.0 ## explicit; go 1.22.0
golang.org/x/mod/semver golang.org/x/mod/semver
# golang.org/x/net v0.33.0 # golang.org/x/net v0.34.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/net/html golang.org/x/net/html
golang.org/x/net/html/atom golang.org/x/net/html/atom
@@ -534,7 +534,7 @@ golang.org/x/sys/cpu
golang.org/x/sys/plan9 golang.org/x/sys/plan9
golang.org/x/sys/unix golang.org/x/sys/unix
golang.org/x/sys/windows golang.org/x/sys/windows
# golang.org/x/term v0.27.0 # golang.org/x/term v0.28.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/term golang.org/x/term
# golang.org/x/text v0.21.0 # golang.org/x/text v0.21.0