This commit is contained in:
parent
99a03bac5d
commit
b20b1719bd
@ -40,7 +40,7 @@ ovhck=
|
||||
## License
|
||||
|
||||
```text
|
||||
Copyright (c) 2020, 2021 PaulBSD
|
||||
Copyright (c) 2020, 2021, 2022 PaulBSD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
49
go.mod
49
go.mod
@ -1,41 +1,42 @@
|
||||
module git.paulbsd.com/paulbsd/pki
|
||||
|
||||
go 1.17
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/go-acme/lego/v4 v4.4.0
|
||||
github.com/go-acme/lego/v4 v4.9.0
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20210406100015-1e088ea4ee04 // indirect
|
||||
github.com/labstack/echo/v4 v4.5.0
|
||||
github.com/lib/pq v1.10.3
|
||||
github.com/miekg/dns v1.1.43 // indirect
|
||||
github.com/labstack/echo/v4 v4.9.1
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/onsi/ginkgo v1.16.0 // indirect
|
||||
github.com/onsi/gomega v1.11.0 // indirect
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect
|
||||
golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
gopkg.in/ini.v1 v1.62.1
|
||||
xorm.io/builder v0.3.9 // indirect
|
||||
xorm.io/xorm v1.2.3
|
||||
golang.org/x/crypto v0.1.0 // indirect
|
||||
golang.org/x/net v0.1.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/time v0.1.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
xorm.io/builder v0.3.12 // indirect
|
||||
xorm.io/xorm v1.3.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
||||
github.com/goccy/go-json v0.7.8 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/goccy/go-json v0.9.11 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/labstack/gommon v0.3.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/labstack/gommon v0.4.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/ovh/go-ovh v1.1.0 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/ovh/go-ovh v1.3.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
golang.org/x/mod v0.6.0 // indirect
|
||||
golang.org/x/tools v0.2.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
)
|
||||
|
3
vendor/github.com/cenkalti/backoff/v4/exponential.go
generated
vendored
3
vendor/github.com/cenkalti/backoff/v4/exponential.go
generated
vendored
@ -147,6 +147,9 @@ func (b *ExponentialBackOff) incrementCurrentInterval() {
|
||||
// Returns a random value from the following interval:
|
||||
// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
|
||||
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
||||
if randomizationFactor == 0 {
|
||||
return currentInterval // make sure no randomness is used when randomizationFactor is 0.
|
||||
}
|
||||
var delta = randomizationFactor * float64(currentInterval)
|
||||
var minInterval = float64(currentInterval) - delta
|
||||
var maxInterval = float64(currentInterval) + delta
|
||||
|
10
vendor/github.com/go-acme/lego/v4/acme/api/api.go
generated
vendored
10
vendor/github.com/go-acme/lego/v4/acme/api/api.go
generated
vendored
@ -2,7 +2,6 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@ -71,7 +70,7 @@ func (a *Core) post(uri string, reqBody, response interface{}) (*http.Response,
|
||||
}
|
||||
|
||||
// postAsGet performs an HTTP POST ("POST-as-GET") request.
|
||||
// https://tools.ietf.org/html/rfc8555#section-6.3
|
||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-6.3
|
||||
func (a *Core) postAsGet(uri string, response interface{}) (*http.Response, error) {
|
||||
return a.retrievablePost(uri, []byte{}, response)
|
||||
}
|
||||
@ -83,8 +82,6 @@ func (a *Core) retrievablePost(uri string, content []byte, response interface{})
|
||||
bo.MaxInterval = 5 * time.Second
|
||||
bo.MaxElapsedTime = 20 * time.Second
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
var resp *http.Response
|
||||
operation := func() error {
|
||||
var err error
|
||||
@ -96,8 +93,7 @@ func (a *Core) retrievablePost(uri string, content []byte, response interface{})
|
||||
return err
|
||||
}
|
||||
|
||||
cancel()
|
||||
return err
|
||||
return backoff.Permanent(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -107,7 +103,7 @@ func (a *Core) retrievablePost(uri string, content []byte, response interface{})
|
||||
log.Infof("retry due to: %v", err)
|
||||
}
|
||||
|
||||
err := backoff.RetryNotify(operation, backoff.WithContext(bo, ctx), notify)
|
||||
err := backoff.RetryNotify(operation, bo, notify)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
14
vendor/github.com/go-acme/lego/v4/acme/api/certificate.go
generated
vendored
14
vendor/github.com/go-acme/lego/v4/acme/api/certificate.go
generated
vendored
@ -1,10 +1,11 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-acme/lego/v4/acme"
|
||||
@ -39,7 +40,7 @@ func (c *CertificateService) GetAll(certURL string, bundle bool) (map[string]*ac
|
||||
certs := map[string]*acme.RawCertificate{certURL: cert}
|
||||
|
||||
// URLs of "alternate" link relation
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.4.2
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4.2
|
||||
alts := getLinks(headers, "alternate")
|
||||
|
||||
for _, alt := range alts {
|
||||
@ -71,7 +72,7 @@ func (c *CertificateService) get(certURL string, bundle bool) (*acme.RawCertific
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||
data, err := io.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||
if err != nil {
|
||||
return nil, resp.Header, err
|
||||
}
|
||||
@ -87,12 +88,17 @@ func (c *CertificateService) getCertificateChain(cert []byte, headers http.Heade
|
||||
// See https://community.letsencrypt.org/t/acme-v2-no-up-link-in-response/64962
|
||||
_, issuer := pem.Decode(cert)
|
||||
if issuer != nil {
|
||||
// If bundle is false, we want to return a single certificate.
|
||||
// To do this, we remove the issuer cert(s) from the issued cert.
|
||||
if !bundle {
|
||||
cert = bytes.TrimSuffix(cert, issuer)
|
||||
}
|
||||
return &acme.RawCertificate{Cert: cert, Issuer: issuer}
|
||||
}
|
||||
|
||||
// The issuer certificate link may be supplied via an "up" link
|
||||
// in the response headers of a new certificate.
|
||||
// See https://tools.ietf.org/html/rfc8555#section-7.4.2
|
||||
// See https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4.2
|
||||
up := getLink(headers, "up")
|
||||
|
||||
issuer, err := c.getIssuerFromLink(up)
|
||||
|
5
vendor/github.com/go-acme/lego/v4/acme/api/internal/sender/sender.go
generated
vendored
5
vendor/github.com/go-acme/lego/v4/acme/api/internal/sender/sender.go
generated
vendored
@ -4,7 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
@ -96,7 +95,7 @@ func (d *Doer) do(req *http.Request, response interface{}) (*http.Response, erro
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
raw, err := ioutil.ReadAll(resp.Body)
|
||||
raw, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
@ -120,7 +119,7 @@ func (d *Doer) formatUserAgent() string {
|
||||
|
||||
func checkError(req *http.Request, resp *http.Response) error {
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%d :: %s :: %s :: %w", resp.StatusCode, req.Method, req.URL, err)
|
||||
}
|
||||
|
2
vendor/github.com/go-acme/lego/v4/acme/api/internal/sender/useragent.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/acme/api/internal/sender/useragent.go
generated
vendored
@ -5,7 +5,7 @@ package sender
|
||||
|
||||
const (
|
||||
// ourUserAgent is the User-Agent of this underlying library package.
|
||||
ourUserAgent = "xenolf-acme/4.4.0"
|
||||
ourUserAgent = "xenolf-acme/4.9.0"
|
||||
|
||||
// ourUserAgentComment is part of the UA comment linked to the version status of this underlying library package.
|
||||
// values: detach|release
|
||||
|
61
vendor/github.com/go-acme/lego/v4/acme/commons.go
generated
vendored
61
vendor/github.com/go-acme/lego/v4/acme/commons.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
// Package acme contains all objects related the ACME endpoints.
|
||||
// https://tools.ietf.org/html/rfc8555
|
||||
// https://www.rfc-editor.org/rfc/rfc8555.html
|
||||
package acme
|
||||
|
||||
import (
|
||||
@ -7,20 +7,37 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Challenge statuses.
|
||||
// https://tools.ietf.org/html/rfc8555#section-7.1.6
|
||||
// ACME status values of Account, Order, Authorization and Challenge objects.
|
||||
// See https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.6 for details.
|
||||
const (
|
||||
StatusPending = "pending"
|
||||
StatusInvalid = "invalid"
|
||||
StatusValid = "valid"
|
||||
StatusProcessing = "processing"
|
||||
StatusDeactivated = "deactivated"
|
||||
StatusExpired = "expired"
|
||||
StatusInvalid = "invalid"
|
||||
StatusPending = "pending"
|
||||
StatusProcessing = "processing"
|
||||
StatusReady = "ready"
|
||||
StatusRevoked = "revoked"
|
||||
StatusUnknown = "unknown"
|
||||
StatusValid = "valid"
|
||||
)
|
||||
|
||||
// CRL reason codes as defined in RFC 5280.
|
||||
// https://datatracker.ietf.org/doc/html/rfc5280#section-5.3.1
|
||||
const (
|
||||
CRLReasonUnspecified uint = 0
|
||||
CRLReasonKeyCompromise uint = 1
|
||||
CRLReasonCACompromise uint = 2
|
||||
CRLReasonAffiliationChanged uint = 3
|
||||
CRLReasonSuperseded uint = 4
|
||||
CRLReasonCessationOfOperation uint = 5
|
||||
CRLReasonCertificateHold uint = 6
|
||||
CRLReasonRemoveFromCRL uint = 8
|
||||
CRLReasonPrivilegeWithdrawn uint = 9
|
||||
CRLReasonAACompromise uint = 10
|
||||
)
|
||||
|
||||
// Directory the ACME directory object.
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.1.1
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.1
|
||||
type Directory struct {
|
||||
NewNonceURL string `json:"newNonce"`
|
||||
NewAccountURL string `json:"newAccount"`
|
||||
@ -32,7 +49,7 @@ type Directory struct {
|
||||
}
|
||||
|
||||
// Meta the ACME meta object (related to Directory).
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.1.1
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.1
|
||||
type Meta struct {
|
||||
// termsOfService (optional, string):
|
||||
// A URL identifying the current terms of service.
|
||||
@ -65,8 +82,8 @@ type ExtendedAccount struct {
|
||||
}
|
||||
|
||||
// Account the ACME account Object.
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.1.2
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.3
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.2
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.3
|
||||
type Account struct {
|
||||
// status (required, string):
|
||||
// The status of this account.
|
||||
@ -112,7 +129,7 @@ type ExtendedOrder struct {
|
||||
}
|
||||
|
||||
// Order the ACME order Object.
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.1.3
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.3
|
||||
type Order struct {
|
||||
// status (required, string):
|
||||
// The status of this order.
|
||||
@ -165,7 +182,7 @@ type Order struct {
|
||||
}
|
||||
|
||||
// Authorization the ACME authorization object.
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.1.4
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.4
|
||||
type Authorization struct {
|
||||
// status (required, string):
|
||||
// The status of this authorization.
|
||||
@ -207,8 +224,8 @@ type ExtendedChallenge struct {
|
||||
}
|
||||
|
||||
// Challenge the ACME challenge object.
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.1.5
|
||||
// - https://tools.ietf.org/html/rfc8555#section-8
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.5
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-8
|
||||
type Challenge struct {
|
||||
// type (required, string):
|
||||
// The type of challenge encoded in the object.
|
||||
@ -241,23 +258,23 @@ type Challenge struct {
|
||||
// It MUST NOT contain any characters outside the base64url alphabet,
|
||||
// and MUST NOT include base64 padding characters ("=").
|
||||
// See [RFC4086] for additional information on randomness requirements.
|
||||
// https://tools.ietf.org/html/rfc8555#section-8.3
|
||||
// https://tools.ietf.org/html/rfc8555#section-8.4
|
||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.3
|
||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.4
|
||||
Token string `json:"token"`
|
||||
|
||||
// https://tools.ietf.org/html/rfc8555#section-8.1
|
||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-8.1
|
||||
KeyAuthorization string `json:"keyAuthorization"`
|
||||
}
|
||||
|
||||
// Identifier the ACME identifier object.
|
||||
// - https://tools.ietf.org/html/rfc8555#section-9.7.7
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-9.7.7
|
||||
type Identifier struct {
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// CSRMessage Certificate Signing Request.
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.4
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4
|
||||
type CSRMessage struct {
|
||||
// csr (required, string):
|
||||
// A CSR encoding the parameters for the certificate being requested [RFC2986].
|
||||
@ -267,8 +284,8 @@ type CSRMessage struct {
|
||||
}
|
||||
|
||||
// RevokeCertMessage a certificate revocation message.
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.6
|
||||
// - https://tools.ietf.org/html/rfc5280#section-5.3.1
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.6
|
||||
// - https://www.rfc-editor.org/rfc/rfc5280.html#section-5.3.1
|
||||
type RevokeCertMessage struct {
|
||||
// certificate (required, string):
|
||||
// The certificate to be revoked, in the base64url-encoded version of the DER format.
|
||||
|
6
vendor/github.com/go-acme/lego/v4/acme/errors.go
generated
vendored
6
vendor/github.com/go-acme/lego/v4/acme/errors.go
generated
vendored
@ -11,8 +11,8 @@ const (
|
||||
)
|
||||
|
||||
// ProblemDetails the problem details object.
|
||||
// - https://tools.ietf.org/html/rfc7807#section-3.1
|
||||
// - https://tools.ietf.org/html/rfc8555#section-7.3.3
|
||||
// - https://www.rfc-editor.org/rfc/rfc7807.html#section-3.1
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-7.3.3
|
||||
type ProblemDetails struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
@ -26,7 +26,7 @@ type ProblemDetails struct {
|
||||
}
|
||||
|
||||
// SubProblem a "subproblems".
|
||||
// - https://tools.ietf.org/html/rfc8555#section-6.7.1
|
||||
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-6.7.1
|
||||
type SubProblem struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
|
5
vendor/github.com/go-acme/lego/v4/certcrypto/crypto.go
generated
vendored
5
vendor/github.com/go-acme/lego/v4/certcrypto/crypto.go
generated
vendored
@ -85,6 +85,9 @@ func ParsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
|
||||
// https://github.com/golang/go/blob/693748e9fa385f1e2c3b91ca9acbb6c0ad2d133d/src/crypto/tls/tls.go#L238)
|
||||
func ParsePEMPrivateKey(key []byte) (crypto.PrivateKey, error) {
|
||||
keyBlockDER, _ := pem.Decode(key)
|
||||
if keyBlockDER == nil {
|
||||
return nil, fmt.Errorf("invalid PEM block")
|
||||
}
|
||||
|
||||
if keyBlockDER.Type != "PRIVATE KEY" && !strings.HasSuffix(keyBlockDER.Type, " PRIVATE KEY") {
|
||||
return nil, fmt.Errorf("unknown PEM header %q", keyBlockDER.Type)
|
||||
@ -261,7 +264,7 @@ func generateDerCert(privateKey *rsa.PrivateKey, expiration time.Time, domain st
|
||||
}
|
||||
|
||||
if expiration.IsZero() {
|
||||
expiration = time.Now().Add(365)
|
||||
expiration = time.Now().AddDate(1, 0, 0)
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
|
4
vendor/github.com/go-acme/lego/v4/certificate/authorization.go
generated
vendored
4
vendor/github.com/go-acme/lego/v4/certificate/authorization.go
generated
vendored
@ -60,7 +60,7 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder) {
|
||||
func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force bool) {
|
||||
for _, authzURL := range order.Authorizations {
|
||||
auth, err := c.core.Authorizations.Get(authzURL)
|
||||
if err != nil {
|
||||
@ -68,7 +68,7 @@ func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder) {
|
||||
continue
|
||||
}
|
||||
|
||||
if auth.Status == acme.StatusValid {
|
||||
if auth.Status == acme.StatusValid && !force {
|
||||
log.Infof("Skipping deactivating of valid auth: %s", authzURL)
|
||||
continue
|
||||
}
|
||||
|
47
vendor/github.com/go-acme/lego/v4/certificate/certificates.go
generated
vendored
47
vendor/github.com/go-acme/lego/v4/certificate/certificates.go
generated
vendored
@ -7,7 +7,7 @@ import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
@ -49,22 +49,30 @@ type Resource struct {
|
||||
// If you do not want that you can supply your own private key in the privateKey parameter.
|
||||
// If this parameter is non-nil it will be used instead of generating a new one.
|
||||
//
|
||||
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
||||
// If `Bundle` is true, the `[]byte` contains both the issuer certificate and your issued certificate as a bundle.
|
||||
//
|
||||
// If `AlwaysDeactivateAuthorizations` is true, the authorizations are also relinquished if the obtain request was successful.
|
||||
// See https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.2.
|
||||
type ObtainRequest struct {
|
||||
Domains []string
|
||||
Bundle bool
|
||||
PrivateKey crypto.PrivateKey
|
||||
MustStaple bool
|
||||
PreferredChain string
|
||||
AlwaysDeactivateAuthorizations bool
|
||||
}
|
||||
|
||||
// ObtainForCSRRequest The request to obtain a certificate matching the CSR passed into it.
|
||||
//
|
||||
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
|
||||
// If `Bundle` is true, the `[]byte` contains both the issuer certificate and your issued certificate as a bundle.
|
||||
//
|
||||
// If `AlwaysDeactivateAuthorizations` is true, the authorizations are also relinquished if the obtain request was successful.
|
||||
// See https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.2.
|
||||
type ObtainForCSRRequest struct {
|
||||
CSR *x509.CertificateRequest
|
||||
Bundle bool
|
||||
PreferredChain string
|
||||
AlwaysDeactivateAuthorizations bool
|
||||
}
|
||||
|
||||
type resolver interface {
|
||||
@ -117,14 +125,14 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
|
||||
authz, err := c.getAuthorizations(order)
|
||||
if err != nil {
|
||||
// If any challenge fails, return. Do not generate partial SAN certificates.
|
||||
c.deactivateAuthorizations(order)
|
||||
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.resolver.Solve(authz)
|
||||
if err != nil {
|
||||
// If any challenge fails, return. Do not generate partial SAN certificates.
|
||||
c.deactivateAuthorizations(order)
|
||||
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -138,6 +146,10 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if request.AlwaysDeactivateAuthorizations {
|
||||
c.deactivateAuthorizations(order, true)
|
||||
}
|
||||
|
||||
// Do not return an empty failures map, because
|
||||
// it would still be a non-nil error value
|
||||
if len(failures) > 0 {
|
||||
@ -178,14 +190,14 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
|
||||
authz, err := c.getAuthorizations(order)
|
||||
if err != nil {
|
||||
// If any challenge fails, return. Do not generate partial SAN certificates.
|
||||
c.deactivateAuthorizations(order)
|
||||
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.resolver.Solve(authz)
|
||||
if err != nil {
|
||||
// If any challenge fails, return. Do not generate partial SAN certificates.
|
||||
c.deactivateAuthorizations(order)
|
||||
c.deactivateAuthorizations(order, request.AlwaysDeactivateAuthorizations)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -199,6 +211,10 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
|
||||
}
|
||||
}
|
||||
|
||||
if request.AlwaysDeactivateAuthorizations {
|
||||
c.deactivateAuthorizations(order, true)
|
||||
}
|
||||
|
||||
if cert != nil {
|
||||
// Add the CSR to the certificate so that it can be used for renewals.
|
||||
cert.CSR = certcrypto.PEMEncode(request.CSR)
|
||||
@ -225,7 +241,7 @@ func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bund
|
||||
commonName := domains[0]
|
||||
|
||||
// RFC8555 Section 7.4 "Applying for Certificate Issuance"
|
||||
// https://tools.ietf.org/html/rfc8555#section-7.4
|
||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4
|
||||
// says:
|
||||
// Clients SHOULD NOT make any assumptions about the sort order of
|
||||
// "identifiers" or "authorizations" elements in the returned order
|
||||
@ -349,6 +365,11 @@ func (c *Certifier) checkResponse(order acme.ExtendedOrder, certRes *Resource, b
|
||||
|
||||
// Revoke takes a PEM encoded certificate or bundle and tries to revoke it at the CA.
|
||||
func (c *Certifier) Revoke(cert []byte) error {
|
||||
return c.RevokeWithReason(cert, nil)
|
||||
}
|
||||
|
||||
// RevokeWithReason takes a PEM encoded certificate or bundle and tries to revoke it at the CA.
|
||||
func (c *Certifier) RevokeWithReason(cert []byte, reason *uint) error {
|
||||
certificates, err := certcrypto.ParsePEMBundle(cert)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -361,6 +382,7 @@ func (c *Certifier) Revoke(cert []byte) error {
|
||||
|
||||
revokeMsg := acme.RevokeCertMessage{
|
||||
Certificate: base64.RawURLEncoding.EncodeToString(x509Cert.Raw),
|
||||
Reason: reason,
|
||||
}
|
||||
|
||||
return c.core.Certificates.Revoke(revokeMsg)
|
||||
@ -423,6 +445,7 @@ func (c *Certifier) Renew(certRes Resource, bundle, mustStaple bool, preferredCh
|
||||
Bundle: bundle,
|
||||
PrivateKey: privateKey,
|
||||
MustStaple: mustStaple,
|
||||
PreferredChain: preferredChain,
|
||||
}
|
||||
return c.Obtain(query)
|
||||
}
|
||||
@ -465,7 +488,7 @@ func (c *Certifier) GetOCSP(bundle []byte) ([]byte, *ocsp.Response, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
issuerBytes, errC := ioutil.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||
issuerBytes, errC := io.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||
if errC != nil {
|
||||
return nil, nil, errC
|
||||
}
|
||||
@ -494,7 +517,7 @@ func (c *Certifier) GetOCSP(bundle []byte) ([]byte, *ocsp.Response, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
ocspResBytes, err := ioutil.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||
ocspResBytes, err := io.ReadAll(http.MaxBytesReader(nil, resp.Body, maxBodySize))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -560,11 +583,11 @@ func checkOrderStatus(order acme.ExtendedOrder) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc8555#section-7.1.4
|
||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-7.1.4
|
||||
// The domain name MUST be encoded in the form in which it would appear in a certificate.
|
||||
// That is, it MUST be encoded according to the rules in Section 7 of [RFC5280].
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc5280#section-7
|
||||
// https://www.rfc-editor.org/rfc/rfc5280.html#section-7
|
||||
func sanitizeDomain(domains []string) []string {
|
||||
var sanitizedDomains []string
|
||||
for _, domain := range domains {
|
||||
|
6
vendor/github.com/go-acme/lego/v4/challenge/challenges.go
generated
vendored
6
vendor/github.com/go-acme/lego/v4/challenge/challenges.go
generated
vendored
@ -10,15 +10,15 @@ import (
|
||||
type Type string
|
||||
|
||||
const (
|
||||
// HTTP01 is the "http-01" ACME challenge https://tools.ietf.org/html/rfc8555#section-8.3
|
||||
// HTTP01 is the "http-01" ACME challenge https://www.rfc-editor.org/rfc/rfc8555.html#section-8.3
|
||||
// Note: ChallengePath returns the URL path to fulfill this challenge.
|
||||
HTTP01 = Type("http-01")
|
||||
|
||||
// DNS01 is the "dns-01" ACME challenge https://tools.ietf.org/html/rfc8555#section-8.4
|
||||
// DNS01 is the "dns-01" ACME challenge https://www.rfc-editor.org/rfc/rfc8555.html#section-8.4
|
||||
// Note: GetRecord returns a DNS record which will fulfill this challenge.
|
||||
DNS01 = Type("dns-01")
|
||||
|
||||
// TLSALPN01 is the "tls-alpn-01" ACME challenge https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07
|
||||
// TLSALPN01 is the "tls-alpn-01" ACME challenge https://www.rfc-editor.org/rfc/rfc8737.html
|
||||
TLSALPN01 = Type("tls-alpn-01")
|
||||
)
|
||||
|
||||
|
34
vendor/github.com/go-acme/lego/v4/challenge/dns01/dns_challenge.go
generated
vendored
34
vendor/github.com/go-acme/lego/v4/challenge/dns01/dns_challenge.go
generated
vendored
@ -176,15 +176,33 @@ func GetRecord(domain, keyAuth string) (fqdn, value string) {
|
||||
keyAuthShaBytes := sha256.Sum256([]byte(keyAuth))
|
||||
// base64URL encoding without padding
|
||||
value = base64.RawURLEncoding.EncodeToString(keyAuthShaBytes[:sha256.Size])
|
||||
fqdn = fmt.Sprintf("_acme-challenge.%s.", domain)
|
||||
|
||||
if ok, _ := strconv.ParseBool(os.Getenv("LEGO_EXPERIMENTAL_CNAME_SUPPORT")); ok {
|
||||
r, err := dnsQuery(fqdn, dns.TypeCNAME, recursiveNameservers, true)
|
||||
// Check if the domain has CNAME then return that
|
||||
if err == nil && r.Rcode == dns.RcodeSuccess {
|
||||
fqdn = updateDomainWithCName(r, fqdn)
|
||||
}
|
||||
}
|
||||
fqdn = getChallengeFqdn(domain)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getChallengeFqdn(domain string) string {
|
||||
fqdn := fmt.Sprintf("_acme-challenge.%s.", domain)
|
||||
|
||||
if ok, _ := strconv.ParseBool(os.Getenv("LEGO_DISABLE_CNAME_SUPPORT")); ok {
|
||||
return fqdn
|
||||
}
|
||||
|
||||
// recursion counter so it doesn't spin out of control
|
||||
for limit := 0; limit < 50; limit++ {
|
||||
// Keep following CNAMEs
|
||||
r, err := dnsQuery(fqdn, dns.TypeCNAME, recursiveNameservers, true)
|
||||
|
||||
// Check if the domain has CNAME then use that
|
||||
if err == nil && r.Rcode == dns.RcodeSuccess {
|
||||
fqdn = updateDomainWithCName(r, fqdn)
|
||||
continue
|
||||
}
|
||||
|
||||
// No more CNAME records to follow, exit
|
||||
break
|
||||
}
|
||||
|
||||
return fqdn
|
||||
}
|
||||
|
2
vendor/github.com/go-acme/lego/v4/challenge/dns01/dns_challenge_manual.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/challenge/dns01/dns_challenge_manual.go
generated
vendored
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
dnsTemplate = `%s %d IN TXT "%s"`
|
||||
dnsTemplate = `%s %d IN TXT %q`
|
||||
)
|
||||
|
||||
// DNSProviderManual is an implementation of the ChallengeProvider interface.
|
||||
|
3
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver.go
generated
vendored
3
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver.go
generated
vendored
@ -13,9 +13,6 @@ import (
|
||||
|
||||
const defaultResolvConf = "/etc/resolv.conf"
|
||||
|
||||
// dnsTimeout is used to override the default DNS timeout of 10 seconds.
|
||||
var dnsTimeout = 10 * time.Second
|
||||
|
||||
var (
|
||||
fqdnSoaCache = map[string]*soaCacheEntry{}
|
||||
muFqdnSoaCache sync.Mutex
|
||||
|
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver_unix.go
generated
vendored
Normal file
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver_unix.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build !windows
|
||||
|
||||
package dns01
|
||||
|
||||
import "time"
|
||||
|
||||
// dnsTimeout is used to override the default DNS timeout of 10 seconds.
|
||||
var dnsTimeout = 10 * time.Second
|
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver_windows.go
generated
vendored
Normal file
8
vendor/github.com/go-acme/lego/v4/challenge/dns01/nameserver_windows.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build windows
|
||||
|
||||
package dns01
|
||||
|
||||
import "time"
|
||||
|
||||
// dnsTimeout is used to override the default DNS timeout of 20 seconds.
|
||||
var dnsTimeout = 20 * time.Second
|
7
vendor/github.com/go-acme/lego/v4/challenge/http01/domain_matcher.go
generated
vendored
7
vendor/github.com/go-acme/lego/v4/challenge/http01/domain_matcher.go
generated
vendored
@ -23,13 +23,16 @@ import (
|
||||
// RFC7239 has standardized the different forwarding headers into a single header named Forwarded.
|
||||
// The header value has a different format, so you should use forwardedMatcher
|
||||
// when the http01.ProviderServer operates behind a RFC7239 compatible proxy.
|
||||
// https://tools.ietf.org/html/rfc7239
|
||||
// https://www.rfc-editor.org/rfc/rfc7239.html
|
||||
//
|
||||
// Note: RFC7239 also reminds us, "that an HTTP list [...] may be split over multiple header fields" (section 7.1),
|
||||
// meaning that
|
||||
//
|
||||
// X-Header: a
|
||||
// X-Header: b
|
||||
//
|
||||
// is equal to
|
||||
//
|
||||
// X-Header: a, b
|
||||
//
|
||||
// All matcher implementations (explicitly not excluding arbitraryMatcher!)
|
||||
@ -66,7 +69,7 @@ func (m arbitraryMatcher) matches(r *http.Request, domain string) bool {
|
||||
}
|
||||
|
||||
// forwardedMatcher checks whether the Forwarded header contains a "host" element starting with a domain name.
|
||||
// See https://tools.ietf.org/html/rfc7239 for details.
|
||||
// See https://www.rfc-editor.org/rfc/rfc7239.html for details.
|
||||
type forwardedMatcher struct{}
|
||||
|
||||
func (m *forwardedMatcher) name() string {
|
||||
|
31
vendor/github.com/go-acme/lego/v4/challenge/http01/http_challenge_server.go
generated
vendored
31
vendor/github.com/go-acme/lego/v4/challenge/http01/http_challenge_server.go
generated
vendored
@ -2,9 +2,11 @@ package http01
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/go-acme/lego/v4/log"
|
||||
@ -14,8 +16,11 @@ import (
|
||||
// It may be instantiated without using the NewProviderServer function if
|
||||
// you want only to use the default values.
|
||||
type ProviderServer struct {
|
||||
iface string
|
||||
port string
|
||||
address string
|
||||
network string // must be valid argument to net.Listen
|
||||
|
||||
socketMode fs.FileMode
|
||||
|
||||
matcher domainMatcher
|
||||
done chan bool
|
||||
listener net.Listener
|
||||
@ -29,24 +34,34 @@ func NewProviderServer(iface, port string) *ProviderServer {
|
||||
port = "80"
|
||||
}
|
||||
|
||||
return &ProviderServer{iface: iface, port: port, matcher: &hostMatcher{}}
|
||||
return &ProviderServer{network: "tcp", address: net.JoinHostPort(iface, port), matcher: &hostMatcher{}}
|
||||
}
|
||||
|
||||
func NewUnixProviderServer(socketPath string, mode fs.FileMode) *ProviderServer {
|
||||
return &ProviderServer{network: "unix", address: socketPath, socketMode: mode, matcher: &hostMatcher{}}
|
||||
}
|
||||
|
||||
// Present starts a web server and makes the token available at `ChallengePath(token)` for web requests.
|
||||
func (s *ProviderServer) Present(domain, token, keyAuth string) error {
|
||||
var err error
|
||||
s.listener, err = net.Listen("tcp", s.GetAddress())
|
||||
s.listener, err = net.Listen(s.network, s.GetAddress())
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not start HTTP server for challenge: %w", err)
|
||||
}
|
||||
|
||||
if s.network == "unix" {
|
||||
if err = os.Chmod(s.address, s.socketMode); err != nil {
|
||||
return fmt.Errorf("chmod %s: %w", s.address, err)
|
||||
}
|
||||
}
|
||||
|
||||
s.done = make(chan bool)
|
||||
go s.serve(domain, token, keyAuth)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ProviderServer) GetAddress() string {
|
||||
return net.JoinHostPort(s.iface, s.port)
|
||||
return s.address
|
||||
}
|
||||
|
||||
// CleanUp closes the HTTP server and removes the token from `ChallengePath(token)`.
|
||||
@ -69,7 +84,7 @@ func (s *ProviderServer) CleanUp(domain, token, keyAuth string) error {
|
||||
//
|
||||
// The exact behavior depends on the value of headerName:
|
||||
// - "" (the empty string) and "Host" will restore the default and only check the Host header
|
||||
// - "Forwarded" will look for a Forwarded header, and inspect it according to https://tools.ietf.org/html/rfc7239
|
||||
// - "Forwarded" will look for a Forwarded header, and inspect it according to https://www.rfc-editor.org/rfc/rfc7239.html
|
||||
// - any other value will check the header value with the same name.
|
||||
func (s *ProviderServer) SetProxyHeader(headerName string) {
|
||||
switch h := textproto.CanonicalMIMEHeaderKey(headerName); h {
|
||||
@ -85,7 +100,7 @@ func (s *ProviderServer) SetProxyHeader(headerName string) {
|
||||
func (s *ProviderServer) serve(domain, token, keyAuth string) {
|
||||
path := ChallengePath(token)
|
||||
|
||||
// The incoming request must will be validated to prevent DNS rebind attacks.
|
||||
// The incoming request will be validated to prevent DNS rebind attacks.
|
||||
// We only respond with the keyAuth, when we're receiving a GET requests with
|
||||
// the "Host" header matching the domain (the latter is configurable though SetProxyHeader).
|
||||
mux := http.NewServeMux()
|
||||
@ -99,7 +114,7 @@ func (s *ProviderServer) serve(domain, token, keyAuth string) {
|
||||
}
|
||||
log.Infof("[%s] Served key authentication", domain)
|
||||
} else {
|
||||
log.Warnf("Received request for domain %s with method %s but the domain did not match any challenge. Please ensure your are passing the %s header properly.", r.Host, r.Method, s.matcher.name())
|
||||
log.Warnf("Received request for domain %s with method %s but the domain did not match any challenge. Please ensure you are passing the %s header properly.", r.Host, r.Method, s.matcher.name())
|
||||
_, err := w.Write([]byte("TEST"))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
11
vendor/github.com/go-acme/lego/v4/challenge/resolver/solver_manager.go
generated
vendored
11
vendor/github.com/go-acme/lego/v4/challenge/resolver/solver_manager.go
generated
vendored
@ -1,7 +1,6 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
@ -107,21 +106,17 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
|
||||
bo.MaxInterval = 10 * initialInterval
|
||||
bo.MaxElapsedTime = 100 * initialInterval
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
// After the path is sent, the ACME server will access our server.
|
||||
// Repeatedly check the server for an updated status on our request.
|
||||
operation := func() error {
|
||||
authz, err := core.Authorizations.Get(chlng.AuthorizationURL)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return err
|
||||
return backoff.Permanent(err)
|
||||
}
|
||||
|
||||
valid, err := checkAuthorizationStatus(authz)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return err
|
||||
return backoff.Permanent(err)
|
||||
}
|
||||
|
||||
if valid {
|
||||
@ -132,7 +127,7 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
|
||||
return errors.New("the server didn't respond to our request")
|
||||
}
|
||||
|
||||
return backoff.Retry(operation, backoff.WithContext(bo, ctx))
|
||||
return backoff.Retry(operation, bo)
|
||||
}
|
||||
|
||||
func checkChallengeStatus(chlng acme.ExtendedChallenge) (bool, error) {
|
||||
|
4
vendor/github.com/go-acme/lego/v4/challenge/tlsalpn01/tls_alpn_challenge.go
generated
vendored
4
vendor/github.com/go-acme/lego/v4/challenge/tlsalpn01/tls_alpn_challenge.go
generated
vendored
@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
// idPeAcmeIdentifierV1 is the SMI Security for PKIX Certification Extension OID referencing the ACME extension.
|
||||
// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07#section-6.1
|
||||
// Reference: https://www.rfc-editor.org/rfc/rfc8737.html#section-6.1
|
||||
var idPeAcmeIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
|
||||
|
||||
type ValidateFunc func(core *api.Core, domain string, chlng acme.Challenge) error
|
||||
@ -83,7 +83,7 @@ func ChallengeBlocks(domain, keyAuth string) ([]byte, []byte, error) {
|
||||
|
||||
// Add the keyAuth digest as the acmeValidation-v1 extension
|
||||
// (marked as critical such that it won't be used by non-ACME software).
|
||||
// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07#section-3
|
||||
// Reference: https://www.rfc-editor.org/rfc/rfc8737.html#section-3
|
||||
extensions := []pkix.Extension{
|
||||
{
|
||||
Id: idPeAcmeIdentifierV1,
|
||||
|
2
vendor/github.com/go-acme/lego/v4/challenge/tlsalpn01/tls_alpn_challenge_server.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/challenge/tlsalpn01/tls_alpn_challenge_server.go
generated
vendored
@ -61,7 +61,7 @@ func (s *ProviderServer) Present(domain, token, keyAuth string) error {
|
||||
|
||||
// We must set that the `acme-tls/1` application level protocol is supported
|
||||
// so that the protocol negotiation can succeed. Reference:
|
||||
// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-07#section-6.2
|
||||
// https://www.rfc-editor.org/rfc/rfc8737.html#section-6.2
|
||||
tlsConf.NextProtos = []string{ACMETLS1Protocol}
|
||||
|
||||
// Create the listener with the created tls.Config.
|
||||
|
53
vendor/github.com/go-acme/lego/v4/lego/client_config.go
generated
vendored
53
vendor/github.com/go-acme/lego/v4/lego/client_config.go
generated
vendored
@ -4,10 +4,11 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
@ -17,10 +18,15 @@ import (
|
||||
const (
|
||||
// caCertificatesEnvVar is the environment variable name that can be used to
|
||||
// specify the path to PEM encoded CA Certificates that can be used to
|
||||
// authenticate an ACME server with a HTTPS certificate not issued by a CA in
|
||||
// authenticate an ACME server with an HTTPS certificate not issued by a CA in
|
||||
// the system-wide trusted root list.
|
||||
// Multiple file paths can be added by using os.PathListSeparator as a separator.
|
||||
caCertificatesEnvVar = "LEGO_CA_CERTIFICATES"
|
||||
|
||||
// caSystemCertPool is the environment variable name that can be used to define
|
||||
// if the certificates pool must use a copy of the system cert pool.
|
||||
caSystemCertPool = "LEGO_CA_SYSTEM_CERT_POOL"
|
||||
|
||||
// caServerNameEnvVar is the environment variable name that can be used to
|
||||
// specify the CA server name that can be used to
|
||||
// authenticate an ACME server with a HTTPS certificate not issued by a CA in
|
||||
@ -82,23 +88,44 @@ func createDefaultHTTPClient() *http.Client {
|
||||
}
|
||||
|
||||
// initCertPool creates a *x509.CertPool populated with the PEM certificates
|
||||
// found in the filepath specified in the caCertificatesEnvVar OS environment
|
||||
// variable. If the caCertificatesEnvVar is not set then initCertPool will
|
||||
// return nil. If there is an error creating a *x509.CertPool from the provided
|
||||
// caCertificatesEnvVar value then initCertPool will panic.
|
||||
// found in the filepath specified in the caCertificatesEnvVar OS environment variable.
|
||||
// If the caCertificatesEnvVar is not set then initCertPool will return nil.
|
||||
// If there is an error creating a *x509.CertPool from the provided caCertificatesEnvVar value then initCertPool will panic.
|
||||
// If the caSystemCertPool is set to a "truthy value" (`1`, `t`, `T`, `TRUE`, `true`, `True`) then a copy of system cert pool will be used.
|
||||
// caSystemCertPool requires caCertificatesEnvVar to be set.
|
||||
func initCertPool() *x509.CertPool {
|
||||
if customCACertsPath := os.Getenv(caCertificatesEnvVar); customCACertsPath != "" {
|
||||
customCAs, err := ioutil.ReadFile(customCACertsPath)
|
||||
customCACertsPath := os.Getenv(caCertificatesEnvVar)
|
||||
if customCACertsPath == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
certPool := getCertPool()
|
||||
|
||||
for _, customPath := range strings.Split(customCACertsPath, string(os.PathListSeparator)) {
|
||||
customCAs, err := os.ReadFile(customPath)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error reading %s=%q: %v",
|
||||
caCertificatesEnvVar, customCACertsPath, err))
|
||||
caCertificatesEnvVar, customPath, err))
|
||||
}
|
||||
certPool := x509.NewCertPool()
|
||||
|
||||
if ok := certPool.AppendCertsFromPEM(customCAs); !ok {
|
||||
panic(fmt.Sprintf("error creating x509 cert pool from %s=%q: %v",
|
||||
caCertificatesEnvVar, customCACertsPath, err))
|
||||
caCertificatesEnvVar, customPath, err))
|
||||
}
|
||||
}
|
||||
|
||||
return certPool
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getCertPool() *x509.CertPool {
|
||||
useSystemCertPool, _ := strconv.ParseBool(os.Getenv(caSystemCertPool))
|
||||
if !useSystemCertPool {
|
||||
return x509.NewCertPool()
|
||||
}
|
||||
|
||||
pool, err := x509.SystemCertPool()
|
||||
if err == nil {
|
||||
return pool
|
||||
}
|
||||
return x509.NewCertPool()
|
||||
}
|
||||
|
4
vendor/github.com/go-acme/lego/v4/platform/config/env/env.go
generated
vendored
4
vendor/github.com/go-acme/lego/v4/platform/config/env/env.go
generated
vendored
@ -3,7 +3,6 @@ package env
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -55,7 +54,6 @@ func Get(names ...string) (map[string]string, error) {
|
||||
// // LEGO_TWO=""
|
||||
// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"})
|
||||
// // => error
|
||||
//
|
||||
func GetWithFallback(groups ...[]string) (map[string]string, error) {
|
||||
values := map[string]string{}
|
||||
|
||||
@ -155,7 +153,7 @@ func GetOrFile(envVar string) string {
|
||||
return envVarValue
|
||||
}
|
||||
|
||||
fileContents, err := ioutil.ReadFile(fileVarValue)
|
||||
fileContents, err := os.ReadFile(fileVarValue)
|
||||
if err != nil {
|
||||
log.Printf("Failed to read the file %s (defined by env var %s): %s", fileVarValue, fileVar, err)
|
||||
return ""
|
||||
|
10
vendor/github.com/go-acme/lego/v4/providers/dns/ovh/ovh.go
generated
vendored
10
vendor/github.com/go-acme/lego/v4/providers/dns/ovh/ovh.go
generated
vendored
@ -126,9 +126,9 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||
|
||||
// Parse domain name
|
||||
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
|
||||
authZone, err := dns01.FindZoneByFqdn(fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ovh: could not determine zone for domain %q: %w", domain, err)
|
||||
return fmt.Errorf("ovh: could not determine zone for domain %q: %w", fqdn, err)
|
||||
}
|
||||
|
||||
authZone = dns01.UnFqdn(authZone)
|
||||
@ -170,9 +170,9 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
return fmt.Errorf("ovh: unknown record ID for '%s'", fqdn)
|
||||
}
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
|
||||
authZone, err := dns01.FindZoneByFqdn(fqdn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ovh: could not determine zone for domain %q: %w", domain, err)
|
||||
return fmt.Errorf("ovh: could not determine zone for domain %q: %w", fqdn, err)
|
||||
}
|
||||
|
||||
authZone = dns01.UnFqdn(authZone)
|
||||
@ -210,5 +210,5 @@ func extractRecordName(fqdn, zone string) string {
|
||||
if idx := strings.Index(name, "."+zone); idx != -1 {
|
||||
return name[:idx]
|
||||
}
|
||||
return name
|
||||
return ""
|
||||
}
|
||||
|
2
vendor/github.com/go-acme/lego/v4/providers/dns/ovh/ovh.toml
generated
vendored
2
vendor/github.com/go-acme/lego/v4/providers/dns/ovh/ovh.toml
generated
vendored
@ -9,7 +9,7 @@ OVH_APPLICATION_KEY=1234567898765432 \
|
||||
OVH_APPLICATION_SECRET=b9841238feb177a84330febba8a832089 \
|
||||
OVH_CONSUMER_KEY=256vfsd347245sdfg \
|
||||
OVH_ENDPOINT=ovh-eu \
|
||||
lego --email myemail@example.com --dns ovh --domains my.example.org run
|
||||
lego --email you@example.com --dns ovh --domains my.example.org run
|
||||
'''
|
||||
|
||||
Additional = '''
|
||||
|
2
vendor/github.com/go-acme/lego/v4/registration/registar.go
generated
vendored
2
vendor/github.com/go-acme/lego/v4/registration/registar.go
generated
vendored
@ -11,7 +11,7 @@ import (
|
||||
|
||||
// Resource represents all important information about a registration
|
||||
// of which the client needs to keep track itself.
|
||||
// WARNING: will be remove in the future (acme.ExtendedAccount), https://github.com/go-acme/lego/issues/855.
|
||||
// WARNING: will be removed in the future (acme.ExtendedAccount), https://github.com/go-acme/lego/issues/855.
|
||||
type Resource struct {
|
||||
Body acme.Account `json:"body,omitempty"`
|
||||
URI string `json:"uri,omitempty"`
|
||||
|
8
vendor/github.com/goccy/go-json/.golangci.yml
generated
vendored
8
vendor/github.com/goccy/go-json/.golangci.yml
generated
vendored
@ -48,6 +48,14 @@ linters:
|
||||
- nlreturn
|
||||
- testpackage
|
||||
- wsl
|
||||
- varnamelen
|
||||
- nilnil
|
||||
- ireturn
|
||||
- govet
|
||||
- forcetypeassert
|
||||
- cyclop
|
||||
- containedctx
|
||||
- revive
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
|
133
vendor/github.com/goccy/go-json/CHANGELOG.md
generated
vendored
133
vendor/github.com/goccy/go-json/CHANGELOG.md
generated
vendored
@ -1,3 +1,136 @@
|
||||
# v0.9.11 - 2022/08/18
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Fix unexpected behavior when buffer ends with backslash ( #383 )
|
||||
* Fix stream decoding of escaped character ( #387 )
|
||||
|
||||
# v0.9.10 - 2022/07/15
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Fix boundary exception of type caching ( #382 )
|
||||
|
||||
# v0.9.9 - 2022/07/15
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Fix encoding of directed interface with typed nil ( #377 )
|
||||
* Fix embedded primitive type encoding using alias ( #378 )
|
||||
* Fix slice/array type encoding with types implementing MarshalJSON ( #379 )
|
||||
* Fix unicode decoding when the expected buffer state is not met after reading ( #380 )
|
||||
|
||||
# v0.9.8 - 2022/06/30
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Fix decoding of surrogate-pair ( #365 )
|
||||
* Fix handling of embedded primitive type ( #366 )
|
||||
* Add validation of escape sequence for decoder ( #367 )
|
||||
* Fix stream tokenizing respecting UseNumber ( #369 )
|
||||
* Fix encoding when struct pointer type that implements Marshal JSON is embedded ( #375 )
|
||||
|
||||
### Improve performance
|
||||
|
||||
* Improve performance of linkRecursiveCode ( #368 )
|
||||
|
||||
# v0.9.7 - 2022/04/22
|
||||
|
||||
### Fix bugs
|
||||
|
||||
#### Encoder
|
||||
|
||||
* Add filtering process for encoding on slow path ( #355 )
|
||||
* Fix encoding of interface{} with pointer type ( #363 )
|
||||
|
||||
#### Decoder
|
||||
|
||||
* Fix map key decoder that implements UnmarshalJSON ( #353 )
|
||||
* Fix decoding of []uint8 type ( #361 )
|
||||
|
||||
### New features
|
||||
|
||||
* Add DebugWith option for encoder ( #356 )
|
||||
|
||||
# v0.9.6 - 2022/03/22
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Correct the handling of the minimum value of int type for decoder ( #344 )
|
||||
* Fix bugs of stream decoder's bufferSize ( #349 )
|
||||
* Add a guard to use typeptr more safely ( #351 )
|
||||
|
||||
### Improve decoder performance
|
||||
|
||||
* Improve escapeString's performance ( #345 )
|
||||
|
||||
### Others
|
||||
|
||||
* Update go version for CI ( #347 )
|
||||
|
||||
# v0.9.5 - 2022/03/04
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Fix panic when decoding time.Time with context ( #328 )
|
||||
* Fix reading the next character in buffer to nul consideration ( #338 )
|
||||
* Fix incorrect handling on skipValue ( #341 )
|
||||
|
||||
### Improve decoder performance
|
||||
|
||||
* Improve performance when a payload contains escape sequence ( #334 )
|
||||
|
||||
# v0.9.4 - 2022/01/21
|
||||
|
||||
* Fix IsNilForMarshaler for string type with omitempty ( #323 )
|
||||
* Fix the case where the embedded field is at the end ( #326 )
|
||||
|
||||
# v0.9.3 - 2022/01/14
|
||||
|
||||
* Fix logic of removing struct field for decoder ( #322 )
|
||||
|
||||
# v0.9.2 - 2022/01/14
|
||||
|
||||
* Add invalid decoder to delay type error judgment at decode ( #321 )
|
||||
|
||||
# v0.9.1 - 2022/01/11
|
||||
|
||||
* Fix encoding of MarshalText/MarshalJSON operation with head offset ( #319 )
|
||||
|
||||
# v0.9.0 - 2022/01/05
|
||||
|
||||
### New feature
|
||||
|
||||
* Supports dynamic filtering of struct fields ( #314 )
|
||||
|
||||
### Improve encoding performance
|
||||
|
||||
* Improve map encoding performance ( #310 )
|
||||
* Optimize encoding path for escaped string ( #311 )
|
||||
* Add encoding option for performance ( #312 )
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Fix panic at encoding map value on 1.18 ( #310 )
|
||||
* Fix MarshalIndent for interface type ( #317 )
|
||||
|
||||
# v0.8.1 - 2021/12/05
|
||||
|
||||
* Fix operation conversion from PtrHead to Head in Recursive type ( #305 )
|
||||
|
||||
# v0.8.0 - 2021/12/02
|
||||
|
||||
* Fix embedded field conflict behavior ( #300 )
|
||||
* Refactor compiler for encoder ( #301 #302 )
|
||||
|
||||
# v0.7.10 - 2021/10/16
|
||||
|
||||
* Fix conversion from pointer to uint64 ( #294 )
|
||||
|
||||
# v0.7.9 - 2021/09/28
|
||||
|
||||
* Fix encoding of nil value about interface type that has method ( #291 )
|
||||
|
||||
# v0.7.8 - 2021/09/01
|
||||
|
||||
* Fix mapassign_faststr for indirect struct type ( #283 )
|
||||
|
6
vendor/github.com/goccy/go-json/README.md
generated
vendored
6
vendor/github.com/goccy/go-json/README.md
generated
vendored
@ -13,7 +13,7 @@ Fast JSON encoder/decoder compatible with encoding/json for Go
|
||||
```
|
||||
* version ( expected release date )
|
||||
|
||||
* v0.7.0
|
||||
* v0.9.0
|
||||
|
|
||||
| while maintaining compatibility with encoding/json, we will add convenient APIs
|
||||
|
|
||||
@ -21,9 +21,8 @@ Fast JSON encoder/decoder compatible with encoding/json for Go
|
||||
* v1.0.0
|
||||
```
|
||||
|
||||
We are accepting requests for features that will be implemented between v0.7.0 and v.1.0.0.
|
||||
We are accepting requests for features that will be implemented between v0.9.0 and v.1.0.0.
|
||||
If you have the API you need, please submit your issue [here](https://github.com/goccy/go-json/issues).
|
||||
For example, I'm thinking of supporting `context.Context` of `json.Marshaler` and decoding using JSON Path.
|
||||
|
||||
# Features
|
||||
|
||||
@ -32,6 +31,7 @@ For example, I'm thinking of supporting `context.Context` of `json.Marshaler` an
|
||||
- Flexible customization with options
|
||||
- Coloring the encoded string
|
||||
- Can propagate context.Context to `MarshalJSON` or `UnmarshalJSON`
|
||||
- Can dynamically filter the fields of the structure type-safely
|
||||
|
||||
# Installation
|
||||
|
||||
|
2
vendor/github.com/goccy/go-json/docker-compose.yml
generated
vendored
2
vendor/github.com/goccy/go-json/docker-compose.yml
generated
vendored
@ -1,7 +1,7 @@
|
||||
version: '2'
|
||||
services:
|
||||
go-json:
|
||||
image: golang:1.16
|
||||
image: golang:1.18
|
||||
volumes:
|
||||
- '.:/go/src/go-json'
|
||||
deploy:
|
||||
|
17
vendor/github.com/goccy/go-json/encode.go
generated
vendored
17
vendor/github.com/goccy/go-json/encode.go
generated
vendored
@ -3,6 +3,7 @@ package json
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
@ -61,6 +62,8 @@ func (e *Encoder) encodeWithOption(ctx *encoder.RuntimeContext, v interface{}, o
|
||||
if e.enabledHTMLEscape {
|
||||
ctx.Option.Flag |= encoder.HTMLEscapeOption
|
||||
}
|
||||
ctx.Option.Flag |= encoder.NormalizeUTF8Option
|
||||
ctx.Option.DebugOut = os.Stdout
|
||||
for _, optFunc := range optFuncs {
|
||||
optFunc(ctx.Option)
|
||||
}
|
||||
@ -111,7 +114,7 @@ func (e *Encoder) SetIndent(prefix, indent string) {
|
||||
func marshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||
rctx := encoder.TakeRuntimeContext()
|
||||
rctx.Option.Flag = 0
|
||||
rctx.Option.Flag = encoder.HTMLEscapeOption | encoder.ContextOption
|
||||
rctx.Option.Flag = encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option | encoder.ContextOption
|
||||
rctx.Option.Context = ctx
|
||||
for _, optFunc := range optFuncs {
|
||||
optFunc(rctx.Option)
|
||||
@ -139,7 +142,7 @@ func marshal(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||
ctx := encoder.TakeRuntimeContext()
|
||||
|
||||
ctx.Option.Flag = 0
|
||||
ctx.Option.Flag |= encoder.HTMLEscapeOption
|
||||
ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option)
|
||||
for _, optFunc := range optFuncs {
|
||||
optFunc(ctx.Option)
|
||||
}
|
||||
@ -166,7 +169,7 @@ func marshalNoEscape(v interface{}) ([]byte, error) {
|
||||
ctx := encoder.TakeRuntimeContext()
|
||||
|
||||
ctx.Option.Flag = 0
|
||||
ctx.Option.Flag |= encoder.HTMLEscapeOption
|
||||
ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option)
|
||||
|
||||
buf, err := encodeNoEscape(ctx, v)
|
||||
if err != nil {
|
||||
@ -190,7 +193,7 @@ func marshalIndent(v interface{}, prefix, indent string, optFuncs ...EncodeOptio
|
||||
ctx := encoder.TakeRuntimeContext()
|
||||
|
||||
ctx.Option.Flag = 0
|
||||
ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.IndentOption)
|
||||
ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.NormalizeUTF8Option | encoder.IndentOption)
|
||||
for _, optFunc := range optFuncs {
|
||||
optFunc(ctx.Option)
|
||||
}
|
||||
@ -220,7 +223,7 @@ func encode(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) {
|
||||
typ := header.typ
|
||||
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
||||
codeSet, err := encoder.CompileToGetCodeSet(ctx, typeptr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -248,7 +251,7 @@ func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error)
|
||||
typ := header.typ
|
||||
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
||||
codeSet, err := encoder.CompileToGetCodeSet(ctx, typeptr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -275,7 +278,7 @@ func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent str
|
||||
typ := header.typ
|
||||
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
||||
codeSet, err := encoder.CompileToGetCodeSet(ctx, typeptr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
5
vendor/github.com/goccy/go-json/internal/decoder/bytes.go
generated
vendored
5
vendor/github.com/goccy/go-json/internal/decoder/bytes.go
generated
vendored
@ -23,9 +23,8 @@ func byteUnmarshalerSliceDecoder(typ *runtime.Type, structName string, fieldName
|
||||
unmarshalDecoder = newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName)
|
||||
case runtime.PtrTo(typ).Implements(unmarshalTextType):
|
||||
unmarshalDecoder = newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName)
|
||||
}
|
||||
if unmarshalDecoder == nil {
|
||||
return nil
|
||||
default:
|
||||
unmarshalDecoder, _ = compileUint8(typ, structName, fieldName)
|
||||
}
|
||||
return newSliceDecoder(unmarshalDecoder, typ, 1, structName, fieldName)
|
||||
}
|
||||
|
197
vendor/github.com/goccy/go-json/internal/decoder/compile.go
generated
vendored
197
vendor/github.com/goccy/go-json/internal/decoder/compile.go
generated
vendored
@ -9,7 +9,6 @@ import (
|
||||
"unicode"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/errors"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
@ -25,7 +24,7 @@ func init() {
|
||||
if typeAddr == nil {
|
||||
typeAddr = &runtime.TypeAddr{}
|
||||
}
|
||||
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift)
|
||||
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
|
||||
}
|
||||
|
||||
func loadDecoderMap() map[uintptr]Decoder {
|
||||
@ -126,13 +125,7 @@ func compile(typ *runtime.Type, structName, fieldName string, structTypeToDecode
|
||||
case reflect.Func:
|
||||
return compileFunc(typ, structName, fieldName)
|
||||
}
|
||||
return nil, &errors.UnmarshalTypeError{
|
||||
Value: "object",
|
||||
Type: runtime.RType2Type(typ),
|
||||
Offset: 0,
|
||||
Struct: structName,
|
||||
Field: fieldName,
|
||||
}
|
||||
return newInvalidDecoder(typ, structName, fieldName), nil
|
||||
}
|
||||
|
||||
func isStringTagSupportedType(typ *runtime.Type) bool {
|
||||
@ -161,6 +154,9 @@ func compileMapKey(typ *runtime.Type, structName, fieldName string, structTypeTo
|
||||
if runtime.PtrTo(typ).Implements(unmarshalTextType) {
|
||||
return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil
|
||||
}
|
||||
if typ.Kind() == reflect.String {
|
||||
return newStringDecoder(structName, fieldName), nil
|
||||
}
|
||||
dec, err := compile(typ, structName, fieldName, structTypeToDecoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -174,17 +170,9 @@ func compileMapKey(typ *runtime.Type, structName, fieldName string, structTypeTo
|
||||
case *ptrDecoder:
|
||||
dec = t.dec
|
||||
default:
|
||||
goto ERROR
|
||||
return newInvalidDecoder(typ, structName, fieldName), nil
|
||||
}
|
||||
}
|
||||
ERROR:
|
||||
return nil, &errors.UnmarshalTypeError{
|
||||
Value: "object",
|
||||
Type: runtime.RType2Type(typ),
|
||||
Offset: 0,
|
||||
Struct: structName,
|
||||
Field: fieldName,
|
||||
}
|
||||
}
|
||||
|
||||
func compilePtr(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||
@ -322,64 +310,21 @@ func compileFunc(typ *runtime.Type, strutName, fieldName string) (Decoder, error
|
||||
return newFuncDecoder(typ, strutName, fieldName), nil
|
||||
}
|
||||
|
||||
func removeConflictFields(fieldMap map[string]*structFieldSet, conflictedMap map[string]struct{}, dec *structDecoder, field reflect.StructField) {
|
||||
for k, v := range dec.fieldMap {
|
||||
if _, exists := conflictedMap[k]; exists {
|
||||
// already conflicted key
|
||||
func typeToStructTags(typ *runtime.Type) runtime.StructTags {
|
||||
tags := runtime.StructTags{}
|
||||
fieldNum := typ.NumField()
|
||||
for i := 0; i < fieldNum; i++ {
|
||||
field := typ.Field(i)
|
||||
if runtime.IsIgnoredStructField(field) {
|
||||
continue
|
||||
}
|
||||
set, exists := fieldMap[k]
|
||||
if !exists {
|
||||
fieldSet := &structFieldSet{
|
||||
dec: v.dec,
|
||||
offset: field.Offset + v.offset,
|
||||
isTaggedKey: v.isTaggedKey,
|
||||
key: k,
|
||||
keyLen: int64(len(k)),
|
||||
}
|
||||
fieldMap[k] = fieldSet
|
||||
lower := strings.ToLower(k)
|
||||
if _, exists := fieldMap[lower]; !exists {
|
||||
fieldMap[lower] = fieldSet
|
||||
}
|
||||
continue
|
||||
}
|
||||
if set.isTaggedKey {
|
||||
if v.isTaggedKey {
|
||||
// conflict tag key
|
||||
delete(fieldMap, k)
|
||||
delete(fieldMap, strings.ToLower(k))
|
||||
conflictedMap[k] = struct{}{}
|
||||
conflictedMap[strings.ToLower(k)] = struct{}{}
|
||||
}
|
||||
} else {
|
||||
if v.isTaggedKey {
|
||||
fieldSet := &structFieldSet{
|
||||
dec: v.dec,
|
||||
offset: field.Offset + v.offset,
|
||||
isTaggedKey: v.isTaggedKey,
|
||||
key: k,
|
||||
keyLen: int64(len(k)),
|
||||
}
|
||||
fieldMap[k] = fieldSet
|
||||
lower := strings.ToLower(k)
|
||||
if _, exists := fieldMap[lower]; !exists {
|
||||
fieldMap[lower] = fieldSet
|
||||
}
|
||||
} else {
|
||||
// conflict tag key
|
||||
delete(fieldMap, k)
|
||||
delete(fieldMap, strings.ToLower(k))
|
||||
conflictedMap[k] = struct{}{}
|
||||
conflictedMap[strings.ToLower(k)] = struct{}{}
|
||||
}
|
||||
}
|
||||
tags = append(tags, runtime.StructTagFromField(field))
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||
fieldNum := typ.NumField()
|
||||
conflictedMap := map[string]struct{}{}
|
||||
fieldMap := map[string]*structFieldSet{}
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
if dec, exists := structTypeToDecoder[typeptr]; exists {
|
||||
@ -388,6 +333,8 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
|
||||
structDec := newStructDecoder(structName, fieldName, fieldMap)
|
||||
structTypeToDecoder[typeptr] = structDec
|
||||
structName = typ.Name()
|
||||
tags := typeToStructTags(typ)
|
||||
allFields := []*structFieldSet{}
|
||||
for i := 0; i < fieldNum; i++ {
|
||||
field := typ.Field(i)
|
||||
if runtime.IsIgnoredStructField(field) {
|
||||
@ -405,7 +352,19 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
|
||||
// recursive definition
|
||||
continue
|
||||
}
|
||||
removeConflictFields(fieldMap, conflictedMap, stDec, field)
|
||||
for k, v := range stDec.fieldMap {
|
||||
if tags.ExistsKey(k) {
|
||||
continue
|
||||
}
|
||||
fieldSet := &structFieldSet{
|
||||
dec: v.dec,
|
||||
offset: field.Offset + v.offset,
|
||||
isTaggedKey: v.isTaggedKey,
|
||||
key: k,
|
||||
keyLen: int64(len(k)),
|
||||
}
|
||||
allFields = append(allFields, fieldSet)
|
||||
}
|
||||
} else if pdec, ok := dec.(*ptrDecoder); ok {
|
||||
contentDec := pdec.contentDecoder()
|
||||
if pdec.typ == typ {
|
||||
@ -421,12 +380,9 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
|
||||
}
|
||||
if dec, ok := contentDec.(*structDecoder); ok {
|
||||
for k, v := range dec.fieldMap {
|
||||
if _, exists := conflictedMap[k]; exists {
|
||||
// already conflicted key
|
||||
if tags.ExistsKey(k) {
|
||||
continue
|
||||
}
|
||||
set, exists := fieldMap[k]
|
||||
if !exists {
|
||||
fieldSet := &structFieldSet{
|
||||
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
|
||||
offset: field.Offset,
|
||||
@ -435,46 +391,27 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
|
||||
keyLen: int64(len(k)),
|
||||
err: fieldSetErr,
|
||||
}
|
||||
fieldMap[k] = fieldSet
|
||||
lower := strings.ToLower(k)
|
||||
if _, exists := fieldMap[lower]; !exists {
|
||||
fieldMap[lower] = fieldSet
|
||||
}
|
||||
continue
|
||||
}
|
||||
if set.isTaggedKey {
|
||||
if v.isTaggedKey {
|
||||
// conflict tag key
|
||||
delete(fieldMap, k)
|
||||
delete(fieldMap, strings.ToLower(k))
|
||||
conflictedMap[k] = struct{}{}
|
||||
conflictedMap[strings.ToLower(k)] = struct{}{}
|
||||
allFields = append(allFields, fieldSet)
|
||||
}
|
||||
} else {
|
||||
if v.isTaggedKey {
|
||||
fieldSet := &structFieldSet{
|
||||
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
|
||||
dec: pdec,
|
||||
offset: field.Offset,
|
||||
isTaggedKey: v.isTaggedKey,
|
||||
key: k,
|
||||
keyLen: int64(len(k)),
|
||||
err: fieldSetErr,
|
||||
isTaggedKey: tag.IsTaggedKey,
|
||||
key: field.Name,
|
||||
keyLen: int64(len(field.Name)),
|
||||
}
|
||||
fieldMap[k] = fieldSet
|
||||
lower := strings.ToLower(k)
|
||||
if _, exists := fieldMap[lower]; !exists {
|
||||
fieldMap[lower] = fieldSet
|
||||
allFields = append(allFields, fieldSet)
|
||||
}
|
||||
} else {
|
||||
// conflict tag key
|
||||
delete(fieldMap, k)
|
||||
delete(fieldMap, strings.ToLower(k))
|
||||
conflictedMap[k] = struct{}{}
|
||||
conflictedMap[strings.ToLower(k)] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
fieldSet := &structFieldSet{
|
||||
dec: dec,
|
||||
offset: field.Offset,
|
||||
isTaggedKey: tag.IsTaggedKey,
|
||||
key: field.Name,
|
||||
keyLen: int64(len(field.Name)),
|
||||
}
|
||||
allFields = append(allFields, fieldSet)
|
||||
}
|
||||
} else {
|
||||
if tag.IsString && isStringTagSupportedType(runtime.Type2RType(field.Type)) {
|
||||
@ -493,18 +430,58 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
|
||||
key: key,
|
||||
keyLen: int64(len(key)),
|
||||
}
|
||||
fieldMap[key] = fieldSet
|
||||
lower := strings.ToLower(key)
|
||||
if _, exists := fieldMap[lower]; !exists {
|
||||
fieldMap[lower] = fieldSet
|
||||
allFields = append(allFields, fieldSet)
|
||||
}
|
||||
}
|
||||
for _, set := range filterDuplicatedFields(allFields) {
|
||||
fieldMap[set.key] = set
|
||||
lower := strings.ToLower(set.key)
|
||||
if _, exists := fieldMap[lower]; !exists {
|
||||
// first win
|
||||
fieldMap[lower] = set
|
||||
}
|
||||
}
|
||||
delete(structTypeToDecoder, typeptr)
|
||||
structDec.tryOptimize()
|
||||
return structDec, nil
|
||||
}
|
||||
|
||||
func filterDuplicatedFields(allFields []*structFieldSet) []*structFieldSet {
|
||||
fieldMap := map[string][]*structFieldSet{}
|
||||
for _, field := range allFields {
|
||||
fieldMap[field.key] = append(fieldMap[field.key], field)
|
||||
}
|
||||
duplicatedFieldMap := map[string]struct{}{}
|
||||
for k, sets := range fieldMap {
|
||||
sets = filterFieldSets(sets)
|
||||
if len(sets) != 1 {
|
||||
duplicatedFieldMap[k] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
filtered := make([]*structFieldSet, 0, len(allFields))
|
||||
for _, field := range allFields {
|
||||
if _, exists := duplicatedFieldMap[field.key]; exists {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, field)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func filterFieldSets(sets []*structFieldSet) []*structFieldSet {
|
||||
if len(sets) == 1 {
|
||||
return sets
|
||||
}
|
||||
filtered := make([]*structFieldSet, 0, len(sets))
|
||||
for _, set := range sets {
|
||||
if set.isTaggedKey {
|
||||
filtered = append(filtered, set)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func implementsUnmarshalJSONType(typ *runtime.Type) bool {
|
||||
return typ.Implements(unmarshalJSONType) || typ.Implements(unmarshalJSONContextType)
|
||||
}
|
||||
|
1
vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go
generated
vendored
1
vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go
generated
vendored
@ -1,3 +1,4 @@
|
||||
//go:build !race
|
||||
// +build !race
|
||||
|
||||
package decoder
|
||||
|
1
vendor/github.com/goccy/go-json/internal/decoder/compile_race.go
generated
vendored
1
vendor/github.com/goccy/go-json/internal/decoder/compile_race.go
generated
vendored
@ -1,3 +1,4 @@
|
||||
//go:build race
|
||||
// +build race
|
||||
|
||||
package decoder
|
||||
|
12
vendor/github.com/goccy/go-json/internal/decoder/int.go
generated
vendored
12
vendor/github.com/goccy/go-json/internal/decoder/int.go
generated
vendored
@ -192,15 +192,15 @@ func (d *intDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro
|
||||
}
|
||||
switch d.kind {
|
||||
case reflect.Int8:
|
||||
if i64 <= -1*(1<<7) || (1<<7) <= i64 {
|
||||
if i64 < -1*(1<<7) || (1<<7) <= i64 {
|
||||
return d.typeError(bytes, s.totalOffset())
|
||||
}
|
||||
case reflect.Int16:
|
||||
if i64 <= -1*(1<<15) || (1<<15) <= i64 {
|
||||
if i64 < -1*(1<<15) || (1<<15) <= i64 {
|
||||
return d.typeError(bytes, s.totalOffset())
|
||||
}
|
||||
case reflect.Int32:
|
||||
if i64 <= -1*(1<<31) || (1<<31) <= i64 {
|
||||
if i64 < -1*(1<<31) || (1<<31) <= i64 {
|
||||
return d.typeError(bytes, s.totalOffset())
|
||||
}
|
||||
}
|
||||
@ -225,15 +225,15 @@ func (d *intDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.P
|
||||
}
|
||||
switch d.kind {
|
||||
case reflect.Int8:
|
||||
if i64 <= -1*(1<<7) || (1<<7) <= i64 {
|
||||
if i64 < -1*(1<<7) || (1<<7) <= i64 {
|
||||
return 0, d.typeError(bytes, cursor)
|
||||
}
|
||||
case reflect.Int16:
|
||||
if i64 <= -1*(1<<15) || (1<<15) <= i64 {
|
||||
if i64 < -1*(1<<15) || (1<<15) <= i64 {
|
||||
return 0, d.typeError(bytes, cursor)
|
||||
}
|
||||
case reflect.Int32:
|
||||
if i64 <= -1*(1<<31) || (1<<31) <= i64 {
|
||||
if i64 < -1*(1<<31) || (1<<31) <= i64 {
|
||||
return 0, d.typeError(bytes, cursor)
|
||||
}
|
||||
}
|
||||
|
45
vendor/github.com/goccy/go-json/internal/decoder/invalid.go
generated
vendored
Normal file
45
vendor/github.com/goccy/go-json/internal/decoder/invalid.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
package decoder
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/errors"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
type invalidDecoder struct {
|
||||
typ *runtime.Type
|
||||
kind reflect.Kind
|
||||
structName string
|
||||
fieldName string
|
||||
}
|
||||
|
||||
func newInvalidDecoder(typ *runtime.Type, structName, fieldName string) *invalidDecoder {
|
||||
return &invalidDecoder{
|
||||
typ: typ,
|
||||
kind: typ.Kind(),
|
||||
structName: structName,
|
||||
fieldName: fieldName,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *invalidDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||
return &errors.UnmarshalTypeError{
|
||||
Value: "object",
|
||||
Type: runtime.RType2Type(d.typ),
|
||||
Offset: s.totalOffset(),
|
||||
Struct: d.structName,
|
||||
Field: d.fieldName,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *invalidDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||
return 0, &errors.UnmarshalTypeError{
|
||||
Value: "object",
|
||||
Type: runtime.RType2Type(d.typ),
|
||||
Offset: cursor,
|
||||
Struct: d.structName,
|
||||
Field: d.fieldName,
|
||||
}
|
||||
}
|
7
vendor/github.com/goccy/go-json/internal/decoder/map.go
generated
vendored
7
vendor/github.com/goccy/go-json/internal/decoder/map.go
generated
vendored
@ -87,13 +87,13 @@ func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro
|
||||
if mapValue == nil {
|
||||
mapValue = makemap(d.mapType, 0)
|
||||
}
|
||||
if s.buf[s.cursor+1] == '}' {
|
||||
s.cursor++
|
||||
if s.equalChar('}') {
|
||||
*(*unsafe.Pointer)(p) = mapValue
|
||||
s.cursor += 2
|
||||
s.cursor++
|
||||
return nil
|
||||
}
|
||||
for {
|
||||
s.cursor++
|
||||
k := unsafe_New(d.keyType)
|
||||
if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil {
|
||||
return err
|
||||
@ -117,6 +117,7 @@ func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro
|
||||
if !s.equalChar(',') {
|
||||
return errors.ErrExpected("comma after object value", s.totalOffset())
|
||||
}
|
||||
s.cursor++
|
||||
}
|
||||
}
|
||||
|
||||
|
16
vendor/github.com/goccy/go-json/internal/decoder/stream.go
generated
vendored
16
vendor/github.com/goccy/go-json/internal/decoder/stream.go
generated
vendored
@ -103,7 +103,7 @@ func (s *Stream) statForRetry() ([]byte, int64, unsafe.Pointer) {
|
||||
|
||||
func (s *Stream) Reset() {
|
||||
s.reset()
|
||||
s.bufSize = initBufSize
|
||||
s.bufSize = int64(len(s.buf))
|
||||
}
|
||||
|
||||
func (s *Stream) More() bool {
|
||||
@ -138,8 +138,11 @@ func (s *Stream) Token() (interface{}, error) {
|
||||
s.cursor++
|
||||
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
bytes := floatBytes(s)
|
||||
s := *(*string)(unsafe.Pointer(&bytes))
|
||||
f64, err := strconv.ParseFloat(s, 64)
|
||||
str := *(*string)(unsafe.Pointer(&bytes))
|
||||
if s.UseNumber {
|
||||
return json.Number(str), nil
|
||||
}
|
||||
f64, err := strconv.ParseFloat(str, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -277,7 +280,7 @@ func (s *Stream) skipObject(depth int64) error {
|
||||
if char(p, cursor) == nul {
|
||||
s.cursor = cursor
|
||||
if s.read() {
|
||||
_, cursor, p = s.statForRetry()
|
||||
_, cursor, p = s.stat()
|
||||
continue
|
||||
}
|
||||
return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||
@ -340,7 +343,7 @@ func (s *Stream) skipArray(depth int64) error {
|
||||
if char(p, cursor) == nul {
|
||||
s.cursor = cursor
|
||||
if s.read() {
|
||||
_, cursor, p = s.statForRetry()
|
||||
_, cursor, p = s.stat()
|
||||
continue
|
||||
}
|
||||
return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||
@ -398,7 +401,7 @@ func (s *Stream) skipValue(depth int64) error {
|
||||
if char(p, cursor) == nul {
|
||||
s.cursor = cursor
|
||||
if s.read() {
|
||||
_, cursor, p = s.statForRetry()
|
||||
_, cursor, p = s.stat()
|
||||
continue
|
||||
}
|
||||
return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
|
||||
@ -423,7 +426,6 @@ func (s *Stream) skipValue(depth int64) error {
|
||||
continue
|
||||
} else if c == nul {
|
||||
if s.read() {
|
||||
s.cursor-- // for retry current character
|
||||
_, cursor, p = s.stat()
|
||||
continue
|
||||
}
|
||||
|
140
vendor/github.com/goccy/go-json/internal/decoder/string.go
generated
vendored
140
vendor/github.com/goccy/go-json/internal/decoder/string.go
generated
vendored
@ -1,6 +1,8 @@
|
||||
package decoder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unicode"
|
||||
"unicode/utf16"
|
||||
@ -93,24 +95,30 @@ func unicodeToRune(code []byte) rune {
|
||||
return r
|
||||
}
|
||||
|
||||
func readAtLeast(s *Stream, n int64, p *unsafe.Pointer) bool {
|
||||
for s.cursor+n >= s.length {
|
||||
if !s.read() {
|
||||
return false
|
||||
}
|
||||
*p = s.bufptr()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func decodeUnicodeRune(s *Stream, p unsafe.Pointer) (rune, int64, unsafe.Pointer, error) {
|
||||
const defaultOffset = 5
|
||||
const surrogateOffset = 11
|
||||
|
||||
if s.cursor+defaultOffset >= s.length {
|
||||
if !s.read() {
|
||||
if !readAtLeast(s, defaultOffset, &p) {
|
||||
return rune(0), 0, nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
|
||||
}
|
||||
p = s.bufptr()
|
||||
}
|
||||
|
||||
r := unicodeToRune(s.buf[s.cursor+1 : s.cursor+defaultOffset])
|
||||
if utf16.IsSurrogate(r) {
|
||||
if s.cursor+surrogateOffset >= s.length {
|
||||
s.read()
|
||||
p = s.bufptr()
|
||||
if !readAtLeast(s, surrogateOffset, &p) {
|
||||
return unicode.ReplacementChar, defaultOffset, p, nil
|
||||
}
|
||||
if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' {
|
||||
if s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' {
|
||||
return unicode.ReplacementChar, defaultOffset, p, nil
|
||||
}
|
||||
r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset])
|
||||
@ -163,6 +171,7 @@ RETRY:
|
||||
if !s.read() {
|
||||
return nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
|
||||
}
|
||||
p = s.bufptr()
|
||||
goto RETRY
|
||||
default:
|
||||
return nil, errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
|
||||
@ -308,49 +317,36 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
|
||||
cursor++
|
||||
start := cursor
|
||||
b := (*sliceHeader)(unsafe.Pointer(&buf)).data
|
||||
escaped := 0
|
||||
for {
|
||||
switch char(b, cursor) {
|
||||
case '\\':
|
||||
escaped++
|
||||
cursor++
|
||||
switch char(b, cursor) {
|
||||
case '"':
|
||||
buf[cursor] = '"'
|
||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||
case '\\':
|
||||
buf[cursor] = '\\'
|
||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||
case '/':
|
||||
buf[cursor] = '/'
|
||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||
case 'b':
|
||||
buf[cursor] = '\b'
|
||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||
case 'f':
|
||||
buf[cursor] = '\f'
|
||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||
case 'n':
|
||||
buf[cursor] = '\n'
|
||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||
case 'r':
|
||||
buf[cursor] = '\r'
|
||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||
case 't':
|
||||
buf[cursor] = '\t'
|
||||
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||
case '"', '\\', '/', 'b', 'f', 'n', 'r', 't':
|
||||
cursor++
|
||||
case 'u':
|
||||
buflen := int64(len(buf))
|
||||
if cursor+5 >= buflen {
|
||||
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
|
||||
}
|
||||
code := unicodeToRune(buf[cursor+1 : cursor+5])
|
||||
unicode := []byte(string(code))
|
||||
buf = append(append(buf[:cursor-1], unicode...), buf[cursor+5:]...)
|
||||
for i := int64(1); i <= 4; i++ {
|
||||
c := char(b, cursor+i)
|
||||
if !(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) {
|
||||
return nil, 0, errors.ErrSyntax(fmt.Sprintf("json: invalid character %c in \\u hexadecimal character escape", c), cursor+i)
|
||||
}
|
||||
}
|
||||
cursor += 5
|
||||
default:
|
||||
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
|
||||
}
|
||||
continue
|
||||
case '"':
|
||||
literal := buf[start:cursor]
|
||||
if escaped > 0 {
|
||||
literal = literal[:unescapeString(literal)]
|
||||
}
|
||||
cursor++
|
||||
return literal, cursor, nil
|
||||
case nul:
|
||||
@ -369,3 +365,77 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var unescapeMap = [256]byte{
|
||||
'"': '"',
|
||||
'\\': '\\',
|
||||
'/': '/',
|
||||
'b': '\b',
|
||||
'f': '\f',
|
||||
'n': '\n',
|
||||
'r': '\r',
|
||||
't': '\t',
|
||||
}
|
||||
|
||||
func unsafeAdd(ptr unsafe.Pointer, offset int) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(ptr) + uintptr(offset))
|
||||
}
|
||||
|
||||
func unescapeString(buf []byte) int {
|
||||
p := (*sliceHeader)(unsafe.Pointer(&buf)).data
|
||||
end := unsafeAdd(p, len(buf))
|
||||
src := unsafeAdd(p, bytes.IndexByte(buf, '\\'))
|
||||
dst := src
|
||||
for src != end {
|
||||
c := char(src, 0)
|
||||
if c == '\\' {
|
||||
escapeChar := char(src, 1)
|
||||
if escapeChar != 'u' {
|
||||
*(*byte)(dst) = unescapeMap[escapeChar]
|
||||
src = unsafeAdd(src, 2)
|
||||
dst = unsafeAdd(dst, 1)
|
||||
} else {
|
||||
v1 := hexToInt[char(src, 2)]
|
||||
v2 := hexToInt[char(src, 3)]
|
||||
v3 := hexToInt[char(src, 4)]
|
||||
v4 := hexToInt[char(src, 5)]
|
||||
code := rune((v1 << 12) | (v2 << 8) | (v3 << 4) | v4)
|
||||
if code >= 0xd800 && code < 0xdc00 && uintptr(unsafeAdd(src, 11)) < uintptr(end) {
|
||||
if char(src, 6) == '\\' && char(src, 7) == 'u' {
|
||||
v1 := hexToInt[char(src, 8)]
|
||||
v2 := hexToInt[char(src, 9)]
|
||||
v3 := hexToInt[char(src, 10)]
|
||||
v4 := hexToInt[char(src, 11)]
|
||||
lo := rune((v1 << 12) | (v2 << 8) | (v3 << 4) | v4)
|
||||
if lo >= 0xdc00 && lo < 0xe000 {
|
||||
code = (code-0xd800)<<10 | (lo - 0xdc00) + 0x10000
|
||||
src = unsafeAdd(src, 6)
|
||||
}
|
||||
}
|
||||
}
|
||||
var b [utf8.UTFMax]byte
|
||||
n := utf8.EncodeRune(b[:], code)
|
||||
switch n {
|
||||
case 4:
|
||||
*(*byte)(unsafeAdd(dst, 3)) = b[3]
|
||||
fallthrough
|
||||
case 3:
|
||||
*(*byte)(unsafeAdd(dst, 2)) = b[2]
|
||||
fallthrough
|
||||
case 2:
|
||||
*(*byte)(unsafeAdd(dst, 1)) = b[1]
|
||||
fallthrough
|
||||
case 1:
|
||||
*(*byte)(unsafeAdd(dst, 0)) = b[0]
|
||||
}
|
||||
src = unsafeAdd(src, 6)
|
||||
dst = unsafeAdd(dst, n)
|
||||
}
|
||||
} else {
|
||||
*(*byte)(dst) = c
|
||||
src = unsafeAdd(src, 1)
|
||||
dst = unsafeAdd(dst, 1)
|
||||
}
|
||||
}
|
||||
return int(uintptr(dst) - uintptr(p))
|
||||
}
|
||||
|
14
vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go
generated
vendored
14
vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
package decoder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"unsafe"
|
||||
|
||||
@ -46,13 +47,20 @@ func (d *unmarshalJSONDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Poi
|
||||
typ: d.typ,
|
||||
ptr: p,
|
||||
}))
|
||||
switch v := v.(type) {
|
||||
case unmarshalerContext:
|
||||
var ctx context.Context
|
||||
if (s.Option.Flags & ContextOption) != 0 {
|
||||
if err := v.(unmarshalerContext).UnmarshalJSON(s.Option.Context, dst); err != nil {
|
||||
ctx = s.Option.Context
|
||||
} else {
|
||||
ctx = context.Background()
|
||||
}
|
||||
if err := v.UnmarshalJSON(ctx, dst); err != nil {
|
||||
d.annotateError(s.cursor, err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil {
|
||||
case json.Unmarshaler:
|
||||
if err := v.UnmarshalJSON(dst); err != nil {
|
||||
d.annotateError(s.cursor, err)
|
||||
return err
|
||||
}
|
||||
|
1017
vendor/github.com/goccy/go-json/internal/encoder/code.go
generated
vendored
Normal file
1017
vendor/github.com/goccy/go-json/internal/encoder/code.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2128
vendor/github.com/goccy/go-json/internal/encoder/compiler.go
generated
vendored
2128
vendor/github.com/goccy/go-json/internal/encoder/compiler.go
generated
vendored
File diff suppressed because it is too large
Load Diff
56
vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go
generated
vendored
56
vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go
generated
vendored
@ -1,56 +1,32 @@
|
||||
//go:build !race
|
||||
// +build !race
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||
if typeptr > typeAddr.MaxTypeAddr {
|
||||
return compileToGetCodeSetSlowPath(typeptr)
|
||||
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
|
||||
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
|
||||
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getFilteredCodeSetIfNeeded(ctx, codeSet)
|
||||
}
|
||||
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
|
||||
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||
return codeSet, nil
|
||||
}
|
||||
|
||||
// noescape trick for header.typ ( reflect.*rtype )
|
||||
copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
|
||||
|
||||
noescapeKeyCode, err := compileHead(&compileContext{
|
||||
typ: copiedType,
|
||||
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||
})
|
||||
filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
escapeKeyCode, err := compileHead(&compileContext{
|
||||
typ: copiedType,
|
||||
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||
escapeKey: true,
|
||||
})
|
||||
return filtered, nil
|
||||
}
|
||||
codeSet, err := newCompiler().compile(typeptr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
noescapeKeyCode = copyOpcode(noescapeKeyCode)
|
||||
escapeKeyCode = copyOpcode(escapeKeyCode)
|
||||
setTotalLengthToInterfaceOp(noescapeKeyCode)
|
||||
setTotalLengthToInterfaceOp(escapeKeyCode)
|
||||
interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode)
|
||||
interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode)
|
||||
codeLength := noescapeKeyCode.TotalLength()
|
||||
codeSet := &OpcodeSet{
|
||||
Type: copiedType,
|
||||
NoescapeKeyCode: noescapeKeyCode,
|
||||
EscapeKeyCode: escapeKeyCode,
|
||||
InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode,
|
||||
InterfaceEscapeKeyCode: interfaceEscapeKeyCode,
|
||||
CodeLength: codeLength,
|
||||
EndCode: ToEndCode(interfaceNoescapeKeyCode),
|
||||
filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cachedOpcodeSets[index] = codeSet
|
||||
return codeSet, nil
|
||||
return filtered, nil
|
||||
}
|
||||
|
54
vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go
generated
vendored
54
vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go
generated
vendored
@ -1,65 +1,45 @@
|
||||
//go:build race
|
||||
// +build race
|
||||
|
||||
package encoder
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
var setsMu sync.RWMutex
|
||||
|
||||
func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||
if typeptr > typeAddr.MaxTypeAddr {
|
||||
return compileToGetCodeSetSlowPath(typeptr)
|
||||
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
|
||||
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
|
||||
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getFilteredCodeSetIfNeeded(ctx, codeSet)
|
||||
}
|
||||
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
|
||||
setsMu.RLock()
|
||||
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||
filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet)
|
||||
if err != nil {
|
||||
setsMu.RUnlock()
|
||||
return codeSet, nil
|
||||
return nil, err
|
||||
}
|
||||
setsMu.RUnlock()
|
||||
return filtered, nil
|
||||
}
|
||||
setsMu.RUnlock()
|
||||
|
||||
// noescape trick for header.typ ( reflect.*rtype )
|
||||
copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
|
||||
|
||||
noescapeKeyCode, err := compileHead(&compileContext{
|
||||
typ: copiedType,
|
||||
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||
})
|
||||
codeSet, err := newCompiler().compile(typeptr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
escapeKeyCode, err := compileHead(&compileContext{
|
||||
typ: copiedType,
|
||||
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||
escapeKey: true,
|
||||
})
|
||||
filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
noescapeKeyCode = copyOpcode(noescapeKeyCode)
|
||||
escapeKeyCode = copyOpcode(escapeKeyCode)
|
||||
setTotalLengthToInterfaceOp(noescapeKeyCode)
|
||||
setTotalLengthToInterfaceOp(escapeKeyCode)
|
||||
interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode)
|
||||
interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode)
|
||||
codeLength := noescapeKeyCode.TotalLength()
|
||||
codeSet := &OpcodeSet{
|
||||
Type: copiedType,
|
||||
NoescapeKeyCode: noescapeKeyCode,
|
||||
EscapeKeyCode: escapeKeyCode,
|
||||
InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode,
|
||||
InterfaceEscapeKeyCode: interfaceEscapeKeyCode,
|
||||
CodeLength: codeLength,
|
||||
EndCode: ToEndCode(interfaceNoescapeKeyCode),
|
||||
}
|
||||
setsMu.Lock()
|
||||
cachedOpcodeSets[index] = codeSet
|
||||
setsMu.Unlock()
|
||||
return codeSet, nil
|
||||
return filtered, nil
|
||||
}
|
||||
|
48
vendor/github.com/goccy/go-json/internal/encoder/context.go
generated
vendored
48
vendor/github.com/goccy/go-json/internal/encoder/context.go
generated
vendored
@ -9,44 +9,20 @@ import (
|
||||
)
|
||||
|
||||
type compileContext struct {
|
||||
typ *runtime.Type
|
||||
opcodeIndex uint32
|
||||
ptrIndex int
|
||||
indent uint32
|
||||
escapeKey bool
|
||||
structTypeToCompiledCode map[uintptr]*CompiledCode
|
||||
|
||||
parent *compileContext
|
||||
structTypeToCodes map[uintptr]Opcodes
|
||||
recursiveCodes *Opcodes
|
||||
}
|
||||
|
||||
func (c *compileContext) context() *compileContext {
|
||||
return &compileContext{
|
||||
typ: c.typ,
|
||||
opcodeIndex: c.opcodeIndex,
|
||||
ptrIndex: c.ptrIndex,
|
||||
indent: c.indent,
|
||||
escapeKey: c.escapeKey,
|
||||
structTypeToCompiledCode: c.structTypeToCompiledCode,
|
||||
parent: c,
|
||||
}
|
||||
func (c *compileContext) incIndent() {
|
||||
c.indent++
|
||||
}
|
||||
|
||||
func (c *compileContext) withType(typ *runtime.Type) *compileContext {
|
||||
ctx := c.context()
|
||||
ctx.typ = typ
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *compileContext) incIndent() *compileContext {
|
||||
ctx := c.context()
|
||||
ctx.indent++
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *compileContext) decIndent() *compileContext {
|
||||
ctx := c.context()
|
||||
ctx.indent--
|
||||
return ctx
|
||||
func (c *compileContext) decIndent() {
|
||||
c.indent--
|
||||
}
|
||||
|
||||
func (c *compileContext) incIndex() {
|
||||
@ -61,30 +37,18 @@ func (c *compileContext) decIndex() {
|
||||
|
||||
func (c *compileContext) incOpcodeIndex() {
|
||||
c.opcodeIndex++
|
||||
if c.parent != nil {
|
||||
c.parent.incOpcodeIndex()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compileContext) decOpcodeIndex() {
|
||||
c.opcodeIndex--
|
||||
if c.parent != nil {
|
||||
c.parent.decOpcodeIndex()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compileContext) incPtrIndex() {
|
||||
c.ptrIndex++
|
||||
if c.parent != nil {
|
||||
c.parent.incPtrIndex()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compileContext) decPtrIndex() {
|
||||
c.ptrIndex--
|
||||
if c.parent != nil {
|
||||
c.parent.decPtrIndex()
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
|
126
vendor/github.com/goccy/go-json/internal/encoder/decode_rune.go
generated
vendored
Normal file
126
vendor/github.com/goccy/go-json/internal/encoder/decode_rune.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
package encoder
|
||||
|
||||
import "unicode/utf8"
|
||||
|
||||
const (
|
||||
// The default lowest and highest continuation byte.
|
||||
locb = 128 //0b10000000
|
||||
hicb = 191 //0b10111111
|
||||
|
||||
// These names of these constants are chosen to give nice alignment in the
|
||||
// table below. The first nibble is an index into acceptRanges or F for
|
||||
// special one-byte cases. The second nibble is the Rune length or the
|
||||
// Status for the special one-byte case.
|
||||
xx = 0xF1 // invalid: size 1
|
||||
as = 0xF0 // ASCII: size 1
|
||||
s1 = 0x02 // accept 0, size 2
|
||||
s2 = 0x13 // accept 1, size 3
|
||||
s3 = 0x03 // accept 0, size 3
|
||||
s4 = 0x23 // accept 2, size 3
|
||||
s5 = 0x34 // accept 3, size 4
|
||||
s6 = 0x04 // accept 0, size 4
|
||||
s7 = 0x44 // accept 4, size 4
|
||||
)
|
||||
|
||||
// first is information about the first byte in a UTF-8 sequence.
|
||||
var first = [256]uint8{
|
||||
// 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F
|
||||
as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F
|
||||
// 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F
|
||||
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F
|
||||
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF
|
||||
xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF
|
||||
xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF
|
||||
s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF
|
||||
s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF
|
||||
s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF
|
||||
}
|
||||
|
||||
const (
|
||||
lineSep = byte(168) //'\u2028'
|
||||
paragraphSep = byte(169) //'\u2029'
|
||||
)
|
||||
|
||||
type decodeRuneState int
|
||||
|
||||
const (
|
||||
validUTF8State decodeRuneState = iota
|
||||
runeErrorState
|
||||
lineSepState
|
||||
paragraphSepState
|
||||
)
|
||||
|
||||
func decodeRuneInString(s string) (decodeRuneState, int) {
|
||||
n := len(s)
|
||||
s0 := s[0]
|
||||
x := first[s0]
|
||||
if x >= as {
|
||||
// The following code simulates an additional check for x == xx and
|
||||
// handling the ASCII and invalid cases accordingly. This mask-and-or
|
||||
// approach prevents an additional branch.
|
||||
mask := rune(x) << 31 >> 31 // Create 0x0000 or 0xFFFF.
|
||||
if rune(s[0])&^mask|utf8.RuneError&mask == utf8.RuneError {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
return validUTF8State, 1
|
||||
}
|
||||
sz := int(x & 7)
|
||||
if n < sz {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
s1 := s[1]
|
||||
switch x >> 4 {
|
||||
case 0:
|
||||
if s1 < locb || hicb < s1 {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
case 1:
|
||||
if s1 < 0xA0 || hicb < s1 {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
case 2:
|
||||
if s1 < locb || 0x9F < s1 {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
case 3:
|
||||
if s1 < 0x90 || hicb < s1 {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
case 4:
|
||||
if s1 < locb || 0x8F < s1 {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
}
|
||||
if sz <= 2 {
|
||||
return validUTF8State, 2
|
||||
}
|
||||
s2 := s[2]
|
||||
if s2 < locb || hicb < s2 {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
if sz <= 3 {
|
||||
// separator character prefixes: [2]byte{226, 128}
|
||||
if s0 == 226 && s1 == 128 {
|
||||
switch s2 {
|
||||
case lineSep:
|
||||
return lineSepState, 3
|
||||
case paragraphSep:
|
||||
return paragraphSepState, 3
|
||||
}
|
||||
}
|
||||
return validUTF8State, 3
|
||||
}
|
||||
s3 := s[3]
|
||||
if s3 < locb || hicb < s3 {
|
||||
return runeErrorState, 1
|
||||
}
|
||||
return validUTF8State, 4
|
||||
}
|
81
vendor/github.com/goccy/go-json/internal/encoder/encoder.go
generated
vendored
81
vendor/github.com/goccy/go-json/internal/encoder/encoder.go
generated
vendored
@ -101,6 +101,22 @@ type OpcodeSet struct {
|
||||
InterfaceEscapeKeyCode *Opcode
|
||||
CodeLength int
|
||||
EndCode *Opcode
|
||||
Code Code
|
||||
QueryCache map[string]*OpcodeSet
|
||||
cacheMu sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *OpcodeSet) getQueryCache(hash string) *OpcodeSet {
|
||||
s.cacheMu.RLock()
|
||||
codeSet := s.QueryCache[hash]
|
||||
s.cacheMu.RUnlock()
|
||||
return codeSet
|
||||
}
|
||||
|
||||
func (s *OpcodeSet) setQueryCache(hash string, codeSet *OpcodeSet) {
|
||||
s.cacheMu.Lock()
|
||||
s.QueryCache[hash] = codeSet
|
||||
s.cacheMu.Unlock()
|
||||
}
|
||||
|
||||
type CompiledCode struct {
|
||||
@ -222,33 +238,56 @@ func (m *Mapslice) Swap(i, j int) {
|
||||
m.Items[i], m.Items[j] = m.Items[j], m.Items[i]
|
||||
}
|
||||
|
||||
//nolint:structcheck,unused
|
||||
type mapIter struct {
|
||||
key unsafe.Pointer
|
||||
elem unsafe.Pointer
|
||||
t unsafe.Pointer
|
||||
h unsafe.Pointer
|
||||
buckets unsafe.Pointer
|
||||
bptr unsafe.Pointer
|
||||
overflow unsafe.Pointer
|
||||
oldoverflow unsafe.Pointer
|
||||
startBucket uintptr
|
||||
offset uint8
|
||||
wrapped bool
|
||||
B uint8
|
||||
i uint8
|
||||
bucket uintptr
|
||||
checkBucket uintptr
|
||||
}
|
||||
|
||||
type MapContext struct {
|
||||
Pos []int
|
||||
Start int
|
||||
First int
|
||||
Idx int
|
||||
Slice *Mapslice
|
||||
Buf []byte
|
||||
Len int
|
||||
Iter mapIter
|
||||
}
|
||||
|
||||
var mapContextPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &MapContext{}
|
||||
return &MapContext{
|
||||
Slice: &Mapslice{},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func NewMapContext(mapLen int) *MapContext {
|
||||
func NewMapContext(mapLen int, unorderedMap bool) *MapContext {
|
||||
ctx := mapContextPool.Get().(*MapContext)
|
||||
if ctx.Slice == nil {
|
||||
ctx.Slice = &Mapslice{
|
||||
Items: make([]MapItem, 0, mapLen),
|
||||
}
|
||||
}
|
||||
if cap(ctx.Pos) < (mapLen*2 + 1) {
|
||||
ctx.Pos = make([]int, 0, mapLen*2+1)
|
||||
ctx.Slice.Items = make([]MapItem, 0, mapLen)
|
||||
if !unorderedMap {
|
||||
if len(ctx.Slice.Items) < mapLen {
|
||||
ctx.Slice.Items = make([]MapItem, mapLen)
|
||||
} else {
|
||||
ctx.Pos = ctx.Pos[:0]
|
||||
ctx.Slice.Items = ctx.Slice.Items[:0]
|
||||
ctx.Slice.Items = ctx.Slice.Items[:mapLen]
|
||||
}
|
||||
}
|
||||
ctx.Buf = ctx.Buf[:0]
|
||||
ctx.Iter = mapIter{}
|
||||
ctx.Idx = 0
|
||||
ctx.Len = mapLen
|
||||
return ctx
|
||||
}
|
||||
|
||||
@ -256,17 +295,17 @@ func ReleaseMapContext(c *MapContext) {
|
||||
mapContextPool.Put(c)
|
||||
}
|
||||
|
||||
//go:linkname MapIterInit reflect.mapiterinit
|
||||
//go:linkname MapIterInit runtime.mapiterinit
|
||||
//go:noescape
|
||||
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer) unsafe.Pointer
|
||||
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter)
|
||||
|
||||
//go:linkname MapIterKey reflect.mapiterkey
|
||||
//go:noescape
|
||||
func MapIterKey(it unsafe.Pointer) unsafe.Pointer
|
||||
func MapIterKey(it *mapIter) unsafe.Pointer
|
||||
|
||||
//go:linkname MapIterNext reflect.mapiternext
|
||||
//go:noescape
|
||||
func MapIterNext(it unsafe.Pointer)
|
||||
func MapIterNext(it *mapIter)
|
||||
|
||||
//go:linkname MapLen reflect.maplen
|
||||
//go:noescape
|
||||
@ -374,7 +413,11 @@ func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{
|
||||
if !ok {
|
||||
return AppendNull(ctx, b), nil
|
||||
}
|
||||
b, err := marshaler.MarshalJSON(ctx.Option.Context)
|
||||
stdctx := ctx.Option.Context
|
||||
if ctx.Option.Flag&FieldQueryOption != 0 {
|
||||
stdctx = SetFieldQueryToContext(stdctx, code.FieldQuery)
|
||||
}
|
||||
b, err := marshaler.MarshalJSON(stdctx)
|
||||
if err != nil {
|
||||
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||
}
|
||||
@ -546,6 +589,8 @@ func IsNilForMarshaler(v interface{}) bool {
|
||||
return rv.IsNil()
|
||||
case reflect.Slice:
|
||||
return rv.IsNil() || rv.Len() == 0
|
||||
case reflect.String:
|
||||
return rv.Len() == 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
26
vendor/github.com/goccy/go-json/internal/encoder/int.go
generated
vendored
26
vendor/github.com/goccy/go-json/internal/encoder/int.go
generated
vendored
@ -53,7 +53,18 @@ func numMask(numBitSize uint8) uint64 {
|
||||
return 1<<numBitSize - 1
|
||||
}
|
||||
|
||||
func AppendInt(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte {
|
||||
func AppendInt(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
|
||||
var u64 uint64
|
||||
switch code.NumBitSize {
|
||||
case 8:
|
||||
u64 = (uint64)(**(**uint8)(unsafe.Pointer(&p)))
|
||||
case 16:
|
||||
u64 = (uint64)(**(**uint16)(unsafe.Pointer(&p)))
|
||||
case 32:
|
||||
u64 = (uint64)(**(**uint32)(unsafe.Pointer(&p)))
|
||||
case 64:
|
||||
u64 = **(**uint64)(unsafe.Pointer(&p))
|
||||
}
|
||||
mask := numMask(code.NumBitSize)
|
||||
n := u64 & mask
|
||||
negative := (u64>>(code.NumBitSize-1))&1 == 1
|
||||
@ -96,7 +107,18 @@ func AppendInt(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte {
|
||||
return append(out, b[i:]...)
|
||||
}
|
||||
|
||||
func AppendUint(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte {
|
||||
func AppendUint(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
|
||||
var u64 uint64
|
||||
switch code.NumBitSize {
|
||||
case 8:
|
||||
u64 = (uint64)(**(**uint8)(unsafe.Pointer(&p)))
|
||||
case 16:
|
||||
u64 = (uint64)(**(**uint16)(unsafe.Pointer(&p)))
|
||||
case 32:
|
||||
u64 = (uint64)(**(**uint32)(unsafe.Pointer(&p)))
|
||||
case 64:
|
||||
u64 = **(**uint64)(unsafe.Pointer(&p))
|
||||
}
|
||||
mask := numMask(code.NumBitSize)
|
||||
n := u64 & mask
|
||||
if n < 10 {
|
||||
|
3
vendor/github.com/goccy/go-json/internal/encoder/map112.go
generated
vendored
3
vendor/github.com/goccy/go-json/internal/encoder/map112.go
generated
vendored
@ -1,3 +1,4 @@
|
||||
//go:build !go1.13
|
||||
// +build !go1.13
|
||||
|
||||
package encoder
|
||||
@ -5,4 +6,4 @@ package encoder
|
||||
import "unsafe"
|
||||
|
||||
//go:linkname MapIterValue reflect.mapitervalue
|
||||
func MapIterValue(it unsafe.Pointer) unsafe.Pointer
|
||||
func MapIterValue(it *mapIter) unsafe.Pointer
|
||||
|
3
vendor/github.com/goccy/go-json/internal/encoder/map113.go
generated
vendored
3
vendor/github.com/goccy/go-json/internal/encoder/map113.go
generated
vendored
@ -1,3 +1,4 @@
|
||||
//go:build go1.13
|
||||
// +build go1.13
|
||||
|
||||
package encoder
|
||||
@ -5,4 +6,4 @@ package encoder
|
||||
import "unsafe"
|
||||
|
||||
//go:linkname MapIterValue reflect.mapiterelem
|
||||
func MapIterValue(it unsafe.Pointer) unsafe.Pointer
|
||||
func MapIterValue(it *mapIter) unsafe.Pointer
|
||||
|
361
vendor/github.com/goccy/go-json/internal/encoder/opcode.go
generated
vendored
361
vendor/github.com/goccy/go-json/internal/encoder/opcode.go
generated
vendored
@ -38,26 +38,58 @@ type Opcode struct {
|
||||
Flags OpFlags
|
||||
|
||||
Type *runtime.Type // go type
|
||||
PrevField *Opcode // prev struct field
|
||||
Jmp *CompiledCode // for recursive call
|
||||
ElemIdx uint32 // offset to access array/slice/map elem
|
||||
Length uint32 // offset to access slice/map length or array length
|
||||
MapIter uint32 // offset to access map iterator
|
||||
MapPos uint32 // offset to access position list for sorted map
|
||||
FieldQuery *FieldQuery // field query for Interface / MarshalJSON / MarshalText
|
||||
ElemIdx uint32 // offset to access array/slice elem
|
||||
Length uint32 // offset to access slice length or array length
|
||||
Indent uint32 // indent number
|
||||
Size uint32 // array/slice elem size
|
||||
DisplayIdx uint32 // opcode index
|
||||
DisplayKey string // key text to display
|
||||
}
|
||||
|
||||
func (c *Opcode) Validate() error {
|
||||
var prevIdx uint32
|
||||
for code := c; !code.IsEnd(); {
|
||||
if prevIdx != 0 {
|
||||
if code.DisplayIdx != prevIdx+1 {
|
||||
return fmt.Errorf(
|
||||
"invalid index. previous display index is %d but next is %d. dump = %s",
|
||||
prevIdx, code.DisplayIdx, c.Dump(),
|
||||
)
|
||||
}
|
||||
}
|
||||
prevIdx = code.DisplayIdx
|
||||
code = code.IterNext()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Opcode) IterNext() *Opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
switch c.Op.CodeType() {
|
||||
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||
return c.End
|
||||
default:
|
||||
return c.Next
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Opcode) IsEnd() bool {
|
||||
if c == nil {
|
||||
return true
|
||||
}
|
||||
return c.Op == OpEnd || c.Op == OpInterfaceEnd || c.Op == OpRecursiveEnd
|
||||
}
|
||||
|
||||
func (c *Opcode) MaxIdx() uint32 {
|
||||
max := uint32(0)
|
||||
for _, value := range []uint32{
|
||||
c.Idx,
|
||||
c.ElemIdx,
|
||||
c.Length,
|
||||
c.MapIter,
|
||||
c.MapPos,
|
||||
c.Size,
|
||||
} {
|
||||
if max < value {
|
||||
@ -273,43 +305,75 @@ func (c *Opcode) ToFieldType(isString bool) OpType {
|
||||
return OpStructField
|
||||
}
|
||||
|
||||
func newOpCode(ctx *compileContext, op OpType) *Opcode {
|
||||
return newOpCodeWithNext(ctx, op, newEndOp(ctx))
|
||||
func newOpCode(ctx *compileContext, typ *runtime.Type, op OpType) *Opcode {
|
||||
return newOpCodeWithNext(ctx, typ, op, newEndOp(ctx, typ))
|
||||
}
|
||||
|
||||
func opcodeOffset(idx int) uint32 {
|
||||
return uint32(idx) * uintptrSize
|
||||
}
|
||||
|
||||
func getCodeAddrByIdx(head *Opcode, idx uint32) *Opcode {
|
||||
addr := uintptr(unsafe.Pointer(head)) + uintptr(idx)*unsafe.Sizeof(Opcode{})
|
||||
return *(**Opcode)(unsafe.Pointer(&addr))
|
||||
}
|
||||
|
||||
func copyOpcode(code *Opcode) *Opcode {
|
||||
codeMap := map[uintptr]*Opcode{}
|
||||
return code.copy(codeMap)
|
||||
codeNum := ToEndCode(code).DisplayIdx + 1
|
||||
codeSlice := make([]Opcode, codeNum)
|
||||
head := (*Opcode)((*runtime.SliceHeader)(unsafe.Pointer(&codeSlice)).Data)
|
||||
ptr := head
|
||||
c := code
|
||||
for {
|
||||
*ptr = Opcode{
|
||||
Op: c.Op,
|
||||
Key: c.Key,
|
||||
PtrNum: c.PtrNum,
|
||||
NumBitSize: c.NumBitSize,
|
||||
Flags: c.Flags,
|
||||
Idx: c.Idx,
|
||||
Offset: c.Offset,
|
||||
Type: c.Type,
|
||||
FieldQuery: c.FieldQuery,
|
||||
DisplayIdx: c.DisplayIdx,
|
||||
DisplayKey: c.DisplayKey,
|
||||
ElemIdx: c.ElemIdx,
|
||||
Length: c.Length,
|
||||
Size: c.Size,
|
||||
Indent: c.Indent,
|
||||
Jmp: c.Jmp,
|
||||
}
|
||||
if c.End != nil {
|
||||
ptr.End = getCodeAddrByIdx(head, c.End.DisplayIdx)
|
||||
}
|
||||
if c.NextField != nil {
|
||||
ptr.NextField = getCodeAddrByIdx(head, c.NextField.DisplayIdx)
|
||||
}
|
||||
if c.Next != nil {
|
||||
ptr.Next = getCodeAddrByIdx(head, c.Next.DisplayIdx)
|
||||
}
|
||||
if c.IsEnd() {
|
||||
break
|
||||
}
|
||||
ptr = getCodeAddrByIdx(head, c.DisplayIdx+1)
|
||||
c = c.IterNext()
|
||||
}
|
||||
return head
|
||||
}
|
||||
|
||||
func setTotalLengthToInterfaceOp(code *Opcode) {
|
||||
c := code
|
||||
for c.Op != OpEnd && c.Op != OpInterfaceEnd {
|
||||
if c.Op == OpInterface {
|
||||
for c := code; !c.IsEnd(); {
|
||||
if c.Op == OpInterface || c.Op == OpInterfacePtr {
|
||||
c.Length = uint32(code.TotalLength())
|
||||
}
|
||||
switch c.Op.CodeType() {
|
||||
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||
c = c.End
|
||||
default:
|
||||
c = c.Next
|
||||
}
|
||||
c = c.IterNext()
|
||||
}
|
||||
}
|
||||
|
||||
func ToEndCode(code *Opcode) *Opcode {
|
||||
c := code
|
||||
for c.Op != OpEnd && c.Op != OpInterfaceEnd {
|
||||
switch c.Op.CodeType() {
|
||||
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||
c = c.End
|
||||
default:
|
||||
c = c.Next
|
||||
}
|
||||
for !c.IsEnd() {
|
||||
c = c.IterNext()
|
||||
}
|
||||
return c
|
||||
}
|
||||
@ -325,77 +389,25 @@ func copyToInterfaceOpcode(code *Opcode) *Opcode {
|
||||
return copied
|
||||
}
|
||||
|
||||
func newOpCodeWithNext(ctx *compileContext, op OpType, next *Opcode) *Opcode {
|
||||
func newOpCodeWithNext(ctx *compileContext, typ *runtime.Type, op OpType, next *Opcode) *Opcode {
|
||||
return &Opcode{
|
||||
Op: op,
|
||||
Idx: opcodeOffset(ctx.ptrIndex),
|
||||
Next: next,
|
||||
Type: ctx.typ,
|
||||
Type: typ,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
Indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
func newEndOp(ctx *compileContext) *Opcode {
|
||||
return newOpCodeWithNext(ctx, OpEnd, nil)
|
||||
}
|
||||
|
||||
func (c *Opcode) copy(codeMap map[uintptr]*Opcode) *Opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
copied := &Opcode{
|
||||
Op: c.Op,
|
||||
Key: c.Key,
|
||||
PtrNum: c.PtrNum,
|
||||
NumBitSize: c.NumBitSize,
|
||||
Flags: c.Flags,
|
||||
Idx: c.Idx,
|
||||
Offset: c.Offset,
|
||||
Type: c.Type,
|
||||
DisplayIdx: c.DisplayIdx,
|
||||
DisplayKey: c.DisplayKey,
|
||||
ElemIdx: c.ElemIdx,
|
||||
Length: c.Length,
|
||||
MapIter: c.MapIter,
|
||||
MapPos: c.MapPos,
|
||||
Size: c.Size,
|
||||
Indent: c.Indent,
|
||||
}
|
||||
codeMap[addr] = copied
|
||||
copied.End = c.End.copy(codeMap)
|
||||
copied.PrevField = c.PrevField.copy(codeMap)
|
||||
copied.NextField = c.NextField.copy(codeMap)
|
||||
copied.Next = c.Next.copy(codeMap)
|
||||
copied.Jmp = c.Jmp
|
||||
return copied
|
||||
}
|
||||
|
||||
func (c *Opcode) BeforeLastCode() *Opcode {
|
||||
code := c
|
||||
for {
|
||||
var nextCode *Opcode
|
||||
switch code.Op.CodeType() {
|
||||
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||
nextCode = code.End
|
||||
default:
|
||||
nextCode = code.Next
|
||||
}
|
||||
if nextCode.Op == OpEnd {
|
||||
return code
|
||||
}
|
||||
code = nextCode
|
||||
}
|
||||
func newEndOp(ctx *compileContext, typ *runtime.Type) *Opcode {
|
||||
return newOpCodeWithNext(ctx, typ, OpEnd, nil)
|
||||
}
|
||||
|
||||
func (c *Opcode) TotalLength() int {
|
||||
var idx int
|
||||
code := c
|
||||
for code.Op != OpEnd && code.Op != OpInterfaceEnd {
|
||||
for !code.IsEnd() {
|
||||
maxIdx := int(code.MaxIdx() / uintptrSize)
|
||||
if idx < maxIdx {
|
||||
idx = maxIdx
|
||||
@ -403,12 +415,7 @@ func (c *Opcode) TotalLength() int {
|
||||
if code.Op == OpRecursiveEnd {
|
||||
break
|
||||
}
|
||||
switch code.Op.CodeType() {
|
||||
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||
code = code.End
|
||||
default:
|
||||
code = code.Next
|
||||
}
|
||||
code = code.IterNext()
|
||||
}
|
||||
maxIdx := int(code.MaxIdx() / uintptrSize)
|
||||
if idx < maxIdx {
|
||||
@ -417,42 +424,6 @@ func (c *Opcode) TotalLength() int {
|
||||
return idx + 1
|
||||
}
|
||||
|
||||
func (c *Opcode) decOpcodeIndex() {
|
||||
for code := c; code.Op != OpEnd; {
|
||||
code.DisplayIdx--
|
||||
if code.Idx > 0 {
|
||||
code.Idx -= uintptrSize
|
||||
}
|
||||
if code.ElemIdx > 0 {
|
||||
code.ElemIdx -= uintptrSize
|
||||
}
|
||||
if code.MapIter > 0 {
|
||||
code.MapIter -= uintptrSize
|
||||
}
|
||||
if code.Length > 0 && code.Op.CodeType() != CodeArrayHead && code.Op.CodeType() != CodeArrayElem {
|
||||
code.Length -= uintptrSize
|
||||
}
|
||||
switch code.Op.CodeType() {
|
||||
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||
code = code.End
|
||||
default:
|
||||
code = code.Next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Opcode) decIndent() {
|
||||
for code := c; code.Op != OpEnd; {
|
||||
code.Indent--
|
||||
switch code.Op.CodeType() {
|
||||
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||
code = code.End
|
||||
default:
|
||||
code = code.Next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Opcode) dumpHead(code *Opcode) string {
|
||||
var length uint32
|
||||
if code.Op.CodeType() == CodeArrayHead {
|
||||
@ -461,7 +432,7 @@ func (c *Opcode) dumpHead(code *Opcode) string {
|
||||
length = code.Length / uintptrSize
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d])`,
|
||||
`[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
@ -473,26 +444,21 @@ func (c *Opcode) dumpHead(code *Opcode) string {
|
||||
|
||||
func (c *Opcode) dumpMapHead(code *Opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||
`[%03d]%s%s ([idx:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
code.Idx/uintptrSize,
|
||||
code.ElemIdx/uintptrSize,
|
||||
code.Length/uintptrSize,
|
||||
code.MapIter/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Opcode) dumpMapEnd(code *Opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`,
|
||||
`[%03d]%s%s ([idx:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
code.Idx/uintptrSize,
|
||||
code.MapPos/uintptrSize,
|
||||
code.Length/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
@ -504,7 +470,7 @@ func (c *Opcode) dumpElem(code *Opcode) string {
|
||||
length = code.Length / uintptrSize
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`,
|
||||
`[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
@ -517,7 +483,7 @@ func (c *Opcode) dumpElem(code *Opcode) string {
|
||||
|
||||
func (c *Opcode) dumpField(code *Opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][key:%s][offset:%d])`,
|
||||
`[%03d]%s%s ([idx:%d][key:%s][offset:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
@ -529,31 +495,27 @@ func (c *Opcode) dumpField(code *Opcode) string {
|
||||
|
||||
func (c *Opcode) dumpKey(code *Opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||
`[%03d]%s%s ([idx:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
code.Idx/uintptrSize,
|
||||
code.ElemIdx/uintptrSize,
|
||||
code.Length/uintptrSize,
|
||||
code.MapIter/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Opcode) dumpValue(code *Opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][mapIter:%d])`,
|
||||
`[%03d]%s%s ([idx:%d])`,
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
code.Idx/uintptrSize,
|
||||
code.MapIter/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Opcode) Dump() string {
|
||||
codes := []string{}
|
||||
for code := c; code.Op != OpEnd && code.Op != OpInterfaceEnd; {
|
||||
for code := c; !code.IsEnd(); {
|
||||
switch code.Op.CodeType() {
|
||||
case CodeSliceHead:
|
||||
codes = append(codes, c.dumpHead(code))
|
||||
@ -581,7 +543,7 @@ func (c *Opcode) Dump() string {
|
||||
code = code.Next
|
||||
default:
|
||||
codes = append(codes, fmt.Sprintf(
|
||||
"[%d]%s%s ([idx:%d])",
|
||||
"[%03d]%s%s ([idx:%d])",
|
||||
code.DisplayIdx,
|
||||
strings.Repeat("-", int(code.Indent)),
|
||||
code.Op,
|
||||
@ -593,44 +555,7 @@ func (c *Opcode) Dump() string {
|
||||
return strings.Join(codes, "\n")
|
||||
}
|
||||
|
||||
func prevField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode {
|
||||
if _, exists := removedFields[code]; exists {
|
||||
return prevField(code.PrevField, removedFields)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func nextField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode {
|
||||
if _, exists := removedFields[code]; exists {
|
||||
return nextField(code.NextField, removedFields)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func linkPrevToNextField(cur *Opcode, removedFields map[*Opcode]struct{}) {
|
||||
prev := prevField(cur.PrevField, removedFields)
|
||||
prev.NextField = nextField(cur.NextField, removedFields)
|
||||
code := prev
|
||||
fcode := cur
|
||||
for {
|
||||
var nextCode *Opcode
|
||||
switch code.Op.CodeType() {
|
||||
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||
nextCode = code.End
|
||||
default:
|
||||
nextCode = code.Next
|
||||
}
|
||||
if nextCode == fcode {
|
||||
code.Next = fcode.Next
|
||||
break
|
||||
} else if nextCode.Op == OpEnd {
|
||||
break
|
||||
}
|
||||
code = nextCode
|
||||
}
|
||||
}
|
||||
|
||||
func newSliceHeaderCode(ctx *compileContext) *Opcode {
|
||||
func newSliceHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode {
|
||||
idx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||
@ -638,6 +563,7 @@ func newSliceHeaderCode(ctx *compileContext) *Opcode {
|
||||
length := opcodeOffset(ctx.ptrIndex)
|
||||
return &Opcode{
|
||||
Op: OpSlice,
|
||||
Type: typ,
|
||||
Idx: idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: elemIdx,
|
||||
@ -646,9 +572,10 @@ func newSliceHeaderCode(ctx *compileContext) *Opcode {
|
||||
}
|
||||
}
|
||||
|
||||
func newSliceElemCode(ctx *compileContext, head *Opcode, size uintptr) *Opcode {
|
||||
func newSliceElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, size uintptr) *Opcode {
|
||||
return &Opcode{
|
||||
Op: OpSliceElem,
|
||||
Type: typ,
|
||||
Idx: head.Idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: head.ElemIdx,
|
||||
@ -658,12 +585,13 @@ func newSliceElemCode(ctx *compileContext, head *Opcode, size uintptr) *Opcode {
|
||||
}
|
||||
}
|
||||
|
||||
func newArrayHeaderCode(ctx *compileContext, alen int) *Opcode {
|
||||
func newArrayHeaderCode(ctx *compileContext, typ *runtime.Type, alen int) *Opcode {
|
||||
idx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||
return &Opcode{
|
||||
Op: OpArray,
|
||||
Type: typ,
|
||||
Idx: idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: elemIdx,
|
||||
@ -672,9 +600,10 @@ func newArrayHeaderCode(ctx *compileContext, alen int) *Opcode {
|
||||
}
|
||||
}
|
||||
|
||||
func newArrayElemCode(ctx *compileContext, head *Opcode, length int, size uintptr) *Opcode {
|
||||
func newArrayElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, length int, size uintptr) *Opcode {
|
||||
return &Opcode{
|
||||
Op: OpArrayElem,
|
||||
Type: typ,
|
||||
Idx: head.Idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: head.ElemIdx,
|
||||
@ -684,87 +613,55 @@ func newArrayElemCode(ctx *compileContext, head *Opcode, length int, size uintpt
|
||||
}
|
||||
}
|
||||
|
||||
func newMapHeaderCode(ctx *compileContext) *Opcode {
|
||||
func newMapHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode {
|
||||
idx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
length := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
mapIter := opcodeOffset(ctx.ptrIndex)
|
||||
return &Opcode{
|
||||
Op: OpMap,
|
||||
Type: typ,
|
||||
Idx: idx,
|
||||
Type: ctx.typ,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: elemIdx,
|
||||
Length: length,
|
||||
MapIter: mapIter,
|
||||
Indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
func newMapKeyCode(ctx *compileContext, head *Opcode) *Opcode {
|
||||
func newMapKeyCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
|
||||
return &Opcode{
|
||||
Op: OpMapKey,
|
||||
Idx: opcodeOffset(ctx.ptrIndex),
|
||||
Type: typ,
|
||||
Idx: head.Idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: head.ElemIdx,
|
||||
Length: head.Length,
|
||||
MapIter: head.MapIter,
|
||||
Indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
func newMapValueCode(ctx *compileContext, head *Opcode) *Opcode {
|
||||
func newMapValueCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
|
||||
return &Opcode{
|
||||
Op: OpMapValue,
|
||||
Idx: opcodeOffset(ctx.ptrIndex),
|
||||
Type: typ,
|
||||
Idx: head.Idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
ElemIdx: head.ElemIdx,
|
||||
Length: head.Length,
|
||||
MapIter: head.MapIter,
|
||||
Indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
func newMapEndCode(ctx *compileContext, head *Opcode) *Opcode {
|
||||
mapPos := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
idx := opcodeOffset(ctx.ptrIndex)
|
||||
func newMapEndCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
|
||||
return &Opcode{
|
||||
Op: OpMapEnd,
|
||||
Idx: idx,
|
||||
Next: newEndOp(ctx),
|
||||
Type: typ,
|
||||
Idx: head.Idx,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
Length: head.Length,
|
||||
MapPos: mapPos,
|
||||
Indent: ctx.indent,
|
||||
Next: newEndOp(ctx, typ),
|
||||
}
|
||||
}
|
||||
|
||||
func newInterfaceCode(ctx *compileContext) *Opcode {
|
||||
var flag OpFlags
|
||||
if ctx.typ.NumMethod() > 0 {
|
||||
flag |= NonEmptyInterfaceFlags
|
||||
}
|
||||
return &Opcode{
|
||||
Op: OpInterface,
|
||||
Idx: opcodeOffset(ctx.ptrIndex),
|
||||
Next: newEndOp(ctx),
|
||||
Type: ctx.typ,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
Indent: ctx.indent,
|
||||
Flags: flag,
|
||||
}
|
||||
}
|
||||
|
||||
func newRecursiveCode(ctx *compileContext, jmp *CompiledCode) *Opcode {
|
||||
func newRecursiveCode(ctx *compileContext, typ *runtime.Type, jmp *CompiledCode) *Opcode {
|
||||
return &Opcode{
|
||||
Op: OpRecursive,
|
||||
Type: typ,
|
||||
Idx: opcodeOffset(ctx.ptrIndex),
|
||||
Next: newEndOp(ctx),
|
||||
Type: ctx.typ,
|
||||
Next: newEndOp(ctx, typ),
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
Indent: ctx.indent,
|
||||
Jmp: jmp,
|
||||
|
8
vendor/github.com/goccy/go-json/internal/encoder/option.go
generated
vendored
8
vendor/github.com/goccy/go-json/internal/encoder/option.go
generated
vendored
@ -1,6 +1,9 @@
|
||||
package encoder
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
type OptionFlag uint8
|
||||
|
||||
@ -11,12 +14,15 @@ const (
|
||||
DebugOption
|
||||
ColorizeOption
|
||||
ContextOption
|
||||
NormalizeUTF8Option
|
||||
FieldQueryOption
|
||||
)
|
||||
|
||||
type Option struct {
|
||||
Flag OptionFlag
|
||||
ColorScheme *ColorScheme
|
||||
Context context.Context
|
||||
DebugOut io.Writer
|
||||
}
|
||||
|
||||
type EncodeFormat struct {
|
||||
|
780
vendor/github.com/goccy/go-json/internal/encoder/optype.go
generated
vendored
780
vendor/github.com/goccy/go-json/internal/encoder/optype.go
generated
vendored
@ -22,7 +22,7 @@ const (
|
||||
CodeStructEnd CodeType = 11
|
||||
)
|
||||
|
||||
var opTypeStrings = [401]string{
|
||||
var opTypeStrings = [400]string{
|
||||
"End",
|
||||
"Interface",
|
||||
"Ptr",
|
||||
@ -37,7 +37,6 @@ var opTypeStrings = [401]string{
|
||||
"RecursivePtr",
|
||||
"RecursiveEnd",
|
||||
"InterfaceEnd",
|
||||
"StructAnonymousEnd",
|
||||
"Int",
|
||||
"Uint",
|
||||
"Float32",
|
||||
@ -443,397 +442,396 @@ const (
|
||||
OpRecursivePtr OpType = 11
|
||||
OpRecursiveEnd OpType = 12
|
||||
OpInterfaceEnd OpType = 13
|
||||
OpStructAnonymousEnd OpType = 14
|
||||
OpInt OpType = 15
|
||||
OpUint OpType = 16
|
||||
OpFloat32 OpType = 17
|
||||
OpFloat64 OpType = 18
|
||||
OpBool OpType = 19
|
||||
OpString OpType = 20
|
||||
OpBytes OpType = 21
|
||||
OpNumber OpType = 22
|
||||
OpArray OpType = 23
|
||||
OpMap OpType = 24
|
||||
OpSlice OpType = 25
|
||||
OpStruct OpType = 26
|
||||
OpMarshalJSON OpType = 27
|
||||
OpMarshalText OpType = 28
|
||||
OpIntString OpType = 29
|
||||
OpUintString OpType = 30
|
||||
OpFloat32String OpType = 31
|
||||
OpFloat64String OpType = 32
|
||||
OpBoolString OpType = 33
|
||||
OpStringString OpType = 34
|
||||
OpNumberString OpType = 35
|
||||
OpIntPtr OpType = 36
|
||||
OpUintPtr OpType = 37
|
||||
OpFloat32Ptr OpType = 38
|
||||
OpFloat64Ptr OpType = 39
|
||||
OpBoolPtr OpType = 40
|
||||
OpStringPtr OpType = 41
|
||||
OpBytesPtr OpType = 42
|
||||
OpNumberPtr OpType = 43
|
||||
OpArrayPtr OpType = 44
|
||||
OpMapPtr OpType = 45
|
||||
OpSlicePtr OpType = 46
|
||||
OpMarshalJSONPtr OpType = 47
|
||||
OpMarshalTextPtr OpType = 48
|
||||
OpInterfacePtr OpType = 49
|
||||
OpIntPtrString OpType = 50
|
||||
OpUintPtrString OpType = 51
|
||||
OpFloat32PtrString OpType = 52
|
||||
OpFloat64PtrString OpType = 53
|
||||
OpBoolPtrString OpType = 54
|
||||
OpStringPtrString OpType = 55
|
||||
OpNumberPtrString OpType = 56
|
||||
OpStructHeadInt OpType = 57
|
||||
OpStructHeadOmitEmptyInt OpType = 58
|
||||
OpStructPtrHeadInt OpType = 59
|
||||
OpStructPtrHeadOmitEmptyInt OpType = 60
|
||||
OpStructHeadUint OpType = 61
|
||||
OpStructHeadOmitEmptyUint OpType = 62
|
||||
OpStructPtrHeadUint OpType = 63
|
||||
OpStructPtrHeadOmitEmptyUint OpType = 64
|
||||
OpStructHeadFloat32 OpType = 65
|
||||
OpStructHeadOmitEmptyFloat32 OpType = 66
|
||||
OpStructPtrHeadFloat32 OpType = 67
|
||||
OpStructPtrHeadOmitEmptyFloat32 OpType = 68
|
||||
OpStructHeadFloat64 OpType = 69
|
||||
OpStructHeadOmitEmptyFloat64 OpType = 70
|
||||
OpStructPtrHeadFloat64 OpType = 71
|
||||
OpStructPtrHeadOmitEmptyFloat64 OpType = 72
|
||||
OpStructHeadBool OpType = 73
|
||||
OpStructHeadOmitEmptyBool OpType = 74
|
||||
OpStructPtrHeadBool OpType = 75
|
||||
OpStructPtrHeadOmitEmptyBool OpType = 76
|
||||
OpStructHeadString OpType = 77
|
||||
OpStructHeadOmitEmptyString OpType = 78
|
||||
OpStructPtrHeadString OpType = 79
|
||||
OpStructPtrHeadOmitEmptyString OpType = 80
|
||||
OpStructHeadBytes OpType = 81
|
||||
OpStructHeadOmitEmptyBytes OpType = 82
|
||||
OpStructPtrHeadBytes OpType = 83
|
||||
OpStructPtrHeadOmitEmptyBytes OpType = 84
|
||||
OpStructHeadNumber OpType = 85
|
||||
OpStructHeadOmitEmptyNumber OpType = 86
|
||||
OpStructPtrHeadNumber OpType = 87
|
||||
OpStructPtrHeadOmitEmptyNumber OpType = 88
|
||||
OpStructHeadArray OpType = 89
|
||||
OpStructHeadOmitEmptyArray OpType = 90
|
||||
OpStructPtrHeadArray OpType = 91
|
||||
OpStructPtrHeadOmitEmptyArray OpType = 92
|
||||
OpStructHeadMap OpType = 93
|
||||
OpStructHeadOmitEmptyMap OpType = 94
|
||||
OpStructPtrHeadMap OpType = 95
|
||||
OpStructPtrHeadOmitEmptyMap OpType = 96
|
||||
OpStructHeadSlice OpType = 97
|
||||
OpStructHeadOmitEmptySlice OpType = 98
|
||||
OpStructPtrHeadSlice OpType = 99
|
||||
OpStructPtrHeadOmitEmptySlice OpType = 100
|
||||
OpStructHeadStruct OpType = 101
|
||||
OpStructHeadOmitEmptyStruct OpType = 102
|
||||
OpStructPtrHeadStruct OpType = 103
|
||||
OpStructPtrHeadOmitEmptyStruct OpType = 104
|
||||
OpStructHeadMarshalJSON OpType = 105
|
||||
OpStructHeadOmitEmptyMarshalJSON OpType = 106
|
||||
OpStructPtrHeadMarshalJSON OpType = 107
|
||||
OpStructPtrHeadOmitEmptyMarshalJSON OpType = 108
|
||||
OpStructHeadMarshalText OpType = 109
|
||||
OpStructHeadOmitEmptyMarshalText OpType = 110
|
||||
OpStructPtrHeadMarshalText OpType = 111
|
||||
OpStructPtrHeadOmitEmptyMarshalText OpType = 112
|
||||
OpStructHeadIntString OpType = 113
|
||||
OpStructHeadOmitEmptyIntString OpType = 114
|
||||
OpStructPtrHeadIntString OpType = 115
|
||||
OpStructPtrHeadOmitEmptyIntString OpType = 116
|
||||
OpStructHeadUintString OpType = 117
|
||||
OpStructHeadOmitEmptyUintString OpType = 118
|
||||
OpStructPtrHeadUintString OpType = 119
|
||||
OpStructPtrHeadOmitEmptyUintString OpType = 120
|
||||
OpStructHeadFloat32String OpType = 121
|
||||
OpStructHeadOmitEmptyFloat32String OpType = 122
|
||||
OpStructPtrHeadFloat32String OpType = 123
|
||||
OpStructPtrHeadOmitEmptyFloat32String OpType = 124
|
||||
OpStructHeadFloat64String OpType = 125
|
||||
OpStructHeadOmitEmptyFloat64String OpType = 126
|
||||
OpStructPtrHeadFloat64String OpType = 127
|
||||
OpStructPtrHeadOmitEmptyFloat64String OpType = 128
|
||||
OpStructHeadBoolString OpType = 129
|
||||
OpStructHeadOmitEmptyBoolString OpType = 130
|
||||
OpStructPtrHeadBoolString OpType = 131
|
||||
OpStructPtrHeadOmitEmptyBoolString OpType = 132
|
||||
OpStructHeadStringString OpType = 133
|
||||
OpStructHeadOmitEmptyStringString OpType = 134
|
||||
OpStructPtrHeadStringString OpType = 135
|
||||
OpStructPtrHeadOmitEmptyStringString OpType = 136
|
||||
OpStructHeadNumberString OpType = 137
|
||||
OpStructHeadOmitEmptyNumberString OpType = 138
|
||||
OpStructPtrHeadNumberString OpType = 139
|
||||
OpStructPtrHeadOmitEmptyNumberString OpType = 140
|
||||
OpStructHeadIntPtr OpType = 141
|
||||
OpStructHeadOmitEmptyIntPtr OpType = 142
|
||||
OpStructPtrHeadIntPtr OpType = 143
|
||||
OpStructPtrHeadOmitEmptyIntPtr OpType = 144
|
||||
OpStructHeadUintPtr OpType = 145
|
||||
OpStructHeadOmitEmptyUintPtr OpType = 146
|
||||
OpStructPtrHeadUintPtr OpType = 147
|
||||
OpStructPtrHeadOmitEmptyUintPtr OpType = 148
|
||||
OpStructHeadFloat32Ptr OpType = 149
|
||||
OpStructHeadOmitEmptyFloat32Ptr OpType = 150
|
||||
OpStructPtrHeadFloat32Ptr OpType = 151
|
||||
OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 152
|
||||
OpStructHeadFloat64Ptr OpType = 153
|
||||
OpStructHeadOmitEmptyFloat64Ptr OpType = 154
|
||||
OpStructPtrHeadFloat64Ptr OpType = 155
|
||||
OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 156
|
||||
OpStructHeadBoolPtr OpType = 157
|
||||
OpStructHeadOmitEmptyBoolPtr OpType = 158
|
||||
OpStructPtrHeadBoolPtr OpType = 159
|
||||
OpStructPtrHeadOmitEmptyBoolPtr OpType = 160
|
||||
OpStructHeadStringPtr OpType = 161
|
||||
OpStructHeadOmitEmptyStringPtr OpType = 162
|
||||
OpStructPtrHeadStringPtr OpType = 163
|
||||
OpStructPtrHeadOmitEmptyStringPtr OpType = 164
|
||||
OpStructHeadBytesPtr OpType = 165
|
||||
OpStructHeadOmitEmptyBytesPtr OpType = 166
|
||||
OpStructPtrHeadBytesPtr OpType = 167
|
||||
OpStructPtrHeadOmitEmptyBytesPtr OpType = 168
|
||||
OpStructHeadNumberPtr OpType = 169
|
||||
OpStructHeadOmitEmptyNumberPtr OpType = 170
|
||||
OpStructPtrHeadNumberPtr OpType = 171
|
||||
OpStructPtrHeadOmitEmptyNumberPtr OpType = 172
|
||||
OpStructHeadArrayPtr OpType = 173
|
||||
OpStructHeadOmitEmptyArrayPtr OpType = 174
|
||||
OpStructPtrHeadArrayPtr OpType = 175
|
||||
OpStructPtrHeadOmitEmptyArrayPtr OpType = 176
|
||||
OpStructHeadMapPtr OpType = 177
|
||||
OpStructHeadOmitEmptyMapPtr OpType = 178
|
||||
OpStructPtrHeadMapPtr OpType = 179
|
||||
OpStructPtrHeadOmitEmptyMapPtr OpType = 180
|
||||
OpStructHeadSlicePtr OpType = 181
|
||||
OpStructHeadOmitEmptySlicePtr OpType = 182
|
||||
OpStructPtrHeadSlicePtr OpType = 183
|
||||
OpStructPtrHeadOmitEmptySlicePtr OpType = 184
|
||||
OpStructHeadMarshalJSONPtr OpType = 185
|
||||
OpStructHeadOmitEmptyMarshalJSONPtr OpType = 186
|
||||
OpStructPtrHeadMarshalJSONPtr OpType = 187
|
||||
OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 188
|
||||
OpStructHeadMarshalTextPtr OpType = 189
|
||||
OpStructHeadOmitEmptyMarshalTextPtr OpType = 190
|
||||
OpStructPtrHeadMarshalTextPtr OpType = 191
|
||||
OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 192
|
||||
OpStructHeadInterfacePtr OpType = 193
|
||||
OpStructHeadOmitEmptyInterfacePtr OpType = 194
|
||||
OpStructPtrHeadInterfacePtr OpType = 195
|
||||
OpStructPtrHeadOmitEmptyInterfacePtr OpType = 196
|
||||
OpStructHeadIntPtrString OpType = 197
|
||||
OpStructHeadOmitEmptyIntPtrString OpType = 198
|
||||
OpStructPtrHeadIntPtrString OpType = 199
|
||||
OpStructPtrHeadOmitEmptyIntPtrString OpType = 200
|
||||
OpStructHeadUintPtrString OpType = 201
|
||||
OpStructHeadOmitEmptyUintPtrString OpType = 202
|
||||
OpStructPtrHeadUintPtrString OpType = 203
|
||||
OpStructPtrHeadOmitEmptyUintPtrString OpType = 204
|
||||
OpStructHeadFloat32PtrString OpType = 205
|
||||
OpStructHeadOmitEmptyFloat32PtrString OpType = 206
|
||||
OpStructPtrHeadFloat32PtrString OpType = 207
|
||||
OpStructPtrHeadOmitEmptyFloat32PtrString OpType = 208
|
||||
OpStructHeadFloat64PtrString OpType = 209
|
||||
OpStructHeadOmitEmptyFloat64PtrString OpType = 210
|
||||
OpStructPtrHeadFloat64PtrString OpType = 211
|
||||
OpStructPtrHeadOmitEmptyFloat64PtrString OpType = 212
|
||||
OpStructHeadBoolPtrString OpType = 213
|
||||
OpStructHeadOmitEmptyBoolPtrString OpType = 214
|
||||
OpStructPtrHeadBoolPtrString OpType = 215
|
||||
OpStructPtrHeadOmitEmptyBoolPtrString OpType = 216
|
||||
OpStructHeadStringPtrString OpType = 217
|
||||
OpStructHeadOmitEmptyStringPtrString OpType = 218
|
||||
OpStructPtrHeadStringPtrString OpType = 219
|
||||
OpStructPtrHeadOmitEmptyStringPtrString OpType = 220
|
||||
OpStructHeadNumberPtrString OpType = 221
|
||||
OpStructHeadOmitEmptyNumberPtrString OpType = 222
|
||||
OpStructPtrHeadNumberPtrString OpType = 223
|
||||
OpStructPtrHeadOmitEmptyNumberPtrString OpType = 224
|
||||
OpStructHead OpType = 225
|
||||
OpStructHeadOmitEmpty OpType = 226
|
||||
OpStructPtrHead OpType = 227
|
||||
OpStructPtrHeadOmitEmpty OpType = 228
|
||||
OpStructFieldInt OpType = 229
|
||||
OpStructFieldOmitEmptyInt OpType = 230
|
||||
OpStructEndInt OpType = 231
|
||||
OpStructEndOmitEmptyInt OpType = 232
|
||||
OpStructFieldUint OpType = 233
|
||||
OpStructFieldOmitEmptyUint OpType = 234
|
||||
OpStructEndUint OpType = 235
|
||||
OpStructEndOmitEmptyUint OpType = 236
|
||||
OpStructFieldFloat32 OpType = 237
|
||||
OpStructFieldOmitEmptyFloat32 OpType = 238
|
||||
OpStructEndFloat32 OpType = 239
|
||||
OpStructEndOmitEmptyFloat32 OpType = 240
|
||||
OpStructFieldFloat64 OpType = 241
|
||||
OpStructFieldOmitEmptyFloat64 OpType = 242
|
||||
OpStructEndFloat64 OpType = 243
|
||||
OpStructEndOmitEmptyFloat64 OpType = 244
|
||||
OpStructFieldBool OpType = 245
|
||||
OpStructFieldOmitEmptyBool OpType = 246
|
||||
OpStructEndBool OpType = 247
|
||||
OpStructEndOmitEmptyBool OpType = 248
|
||||
OpStructFieldString OpType = 249
|
||||
OpStructFieldOmitEmptyString OpType = 250
|
||||
OpStructEndString OpType = 251
|
||||
OpStructEndOmitEmptyString OpType = 252
|
||||
OpStructFieldBytes OpType = 253
|
||||
OpStructFieldOmitEmptyBytes OpType = 254
|
||||
OpStructEndBytes OpType = 255
|
||||
OpStructEndOmitEmptyBytes OpType = 256
|
||||
OpStructFieldNumber OpType = 257
|
||||
OpStructFieldOmitEmptyNumber OpType = 258
|
||||
OpStructEndNumber OpType = 259
|
||||
OpStructEndOmitEmptyNumber OpType = 260
|
||||
OpStructFieldArray OpType = 261
|
||||
OpStructFieldOmitEmptyArray OpType = 262
|
||||
OpStructEndArray OpType = 263
|
||||
OpStructEndOmitEmptyArray OpType = 264
|
||||
OpStructFieldMap OpType = 265
|
||||
OpStructFieldOmitEmptyMap OpType = 266
|
||||
OpStructEndMap OpType = 267
|
||||
OpStructEndOmitEmptyMap OpType = 268
|
||||
OpStructFieldSlice OpType = 269
|
||||
OpStructFieldOmitEmptySlice OpType = 270
|
||||
OpStructEndSlice OpType = 271
|
||||
OpStructEndOmitEmptySlice OpType = 272
|
||||
OpStructFieldStruct OpType = 273
|
||||
OpStructFieldOmitEmptyStruct OpType = 274
|
||||
OpStructEndStruct OpType = 275
|
||||
OpStructEndOmitEmptyStruct OpType = 276
|
||||
OpStructFieldMarshalJSON OpType = 277
|
||||
OpStructFieldOmitEmptyMarshalJSON OpType = 278
|
||||
OpStructEndMarshalJSON OpType = 279
|
||||
OpStructEndOmitEmptyMarshalJSON OpType = 280
|
||||
OpStructFieldMarshalText OpType = 281
|
||||
OpStructFieldOmitEmptyMarshalText OpType = 282
|
||||
OpStructEndMarshalText OpType = 283
|
||||
OpStructEndOmitEmptyMarshalText OpType = 284
|
||||
OpStructFieldIntString OpType = 285
|
||||
OpStructFieldOmitEmptyIntString OpType = 286
|
||||
OpStructEndIntString OpType = 287
|
||||
OpStructEndOmitEmptyIntString OpType = 288
|
||||
OpStructFieldUintString OpType = 289
|
||||
OpStructFieldOmitEmptyUintString OpType = 290
|
||||
OpStructEndUintString OpType = 291
|
||||
OpStructEndOmitEmptyUintString OpType = 292
|
||||
OpStructFieldFloat32String OpType = 293
|
||||
OpStructFieldOmitEmptyFloat32String OpType = 294
|
||||
OpStructEndFloat32String OpType = 295
|
||||
OpStructEndOmitEmptyFloat32String OpType = 296
|
||||
OpStructFieldFloat64String OpType = 297
|
||||
OpStructFieldOmitEmptyFloat64String OpType = 298
|
||||
OpStructEndFloat64String OpType = 299
|
||||
OpStructEndOmitEmptyFloat64String OpType = 300
|
||||
OpStructFieldBoolString OpType = 301
|
||||
OpStructFieldOmitEmptyBoolString OpType = 302
|
||||
OpStructEndBoolString OpType = 303
|
||||
OpStructEndOmitEmptyBoolString OpType = 304
|
||||
OpStructFieldStringString OpType = 305
|
||||
OpStructFieldOmitEmptyStringString OpType = 306
|
||||
OpStructEndStringString OpType = 307
|
||||
OpStructEndOmitEmptyStringString OpType = 308
|
||||
OpStructFieldNumberString OpType = 309
|
||||
OpStructFieldOmitEmptyNumberString OpType = 310
|
||||
OpStructEndNumberString OpType = 311
|
||||
OpStructEndOmitEmptyNumberString OpType = 312
|
||||
OpStructFieldIntPtr OpType = 313
|
||||
OpStructFieldOmitEmptyIntPtr OpType = 314
|
||||
OpStructEndIntPtr OpType = 315
|
||||
OpStructEndOmitEmptyIntPtr OpType = 316
|
||||
OpStructFieldUintPtr OpType = 317
|
||||
OpStructFieldOmitEmptyUintPtr OpType = 318
|
||||
OpStructEndUintPtr OpType = 319
|
||||
OpStructEndOmitEmptyUintPtr OpType = 320
|
||||
OpStructFieldFloat32Ptr OpType = 321
|
||||
OpStructFieldOmitEmptyFloat32Ptr OpType = 322
|
||||
OpStructEndFloat32Ptr OpType = 323
|
||||
OpStructEndOmitEmptyFloat32Ptr OpType = 324
|
||||
OpStructFieldFloat64Ptr OpType = 325
|
||||
OpStructFieldOmitEmptyFloat64Ptr OpType = 326
|
||||
OpStructEndFloat64Ptr OpType = 327
|
||||
OpStructEndOmitEmptyFloat64Ptr OpType = 328
|
||||
OpStructFieldBoolPtr OpType = 329
|
||||
OpStructFieldOmitEmptyBoolPtr OpType = 330
|
||||
OpStructEndBoolPtr OpType = 331
|
||||
OpStructEndOmitEmptyBoolPtr OpType = 332
|
||||
OpStructFieldStringPtr OpType = 333
|
||||
OpStructFieldOmitEmptyStringPtr OpType = 334
|
||||
OpStructEndStringPtr OpType = 335
|
||||
OpStructEndOmitEmptyStringPtr OpType = 336
|
||||
OpStructFieldBytesPtr OpType = 337
|
||||
OpStructFieldOmitEmptyBytesPtr OpType = 338
|
||||
OpStructEndBytesPtr OpType = 339
|
||||
OpStructEndOmitEmptyBytesPtr OpType = 340
|
||||
OpStructFieldNumberPtr OpType = 341
|
||||
OpStructFieldOmitEmptyNumberPtr OpType = 342
|
||||
OpStructEndNumberPtr OpType = 343
|
||||
OpStructEndOmitEmptyNumberPtr OpType = 344
|
||||
OpStructFieldArrayPtr OpType = 345
|
||||
OpStructFieldOmitEmptyArrayPtr OpType = 346
|
||||
OpStructEndArrayPtr OpType = 347
|
||||
OpStructEndOmitEmptyArrayPtr OpType = 348
|
||||
OpStructFieldMapPtr OpType = 349
|
||||
OpStructFieldOmitEmptyMapPtr OpType = 350
|
||||
OpStructEndMapPtr OpType = 351
|
||||
OpStructEndOmitEmptyMapPtr OpType = 352
|
||||
OpStructFieldSlicePtr OpType = 353
|
||||
OpStructFieldOmitEmptySlicePtr OpType = 354
|
||||
OpStructEndSlicePtr OpType = 355
|
||||
OpStructEndOmitEmptySlicePtr OpType = 356
|
||||
OpStructFieldMarshalJSONPtr OpType = 357
|
||||
OpStructFieldOmitEmptyMarshalJSONPtr OpType = 358
|
||||
OpStructEndMarshalJSONPtr OpType = 359
|
||||
OpStructEndOmitEmptyMarshalJSONPtr OpType = 360
|
||||
OpStructFieldMarshalTextPtr OpType = 361
|
||||
OpStructFieldOmitEmptyMarshalTextPtr OpType = 362
|
||||
OpStructEndMarshalTextPtr OpType = 363
|
||||
OpStructEndOmitEmptyMarshalTextPtr OpType = 364
|
||||
OpStructFieldInterfacePtr OpType = 365
|
||||
OpStructFieldOmitEmptyInterfacePtr OpType = 366
|
||||
OpStructEndInterfacePtr OpType = 367
|
||||
OpStructEndOmitEmptyInterfacePtr OpType = 368
|
||||
OpStructFieldIntPtrString OpType = 369
|
||||
OpStructFieldOmitEmptyIntPtrString OpType = 370
|
||||
OpStructEndIntPtrString OpType = 371
|
||||
OpStructEndOmitEmptyIntPtrString OpType = 372
|
||||
OpStructFieldUintPtrString OpType = 373
|
||||
OpStructFieldOmitEmptyUintPtrString OpType = 374
|
||||
OpStructEndUintPtrString OpType = 375
|
||||
OpStructEndOmitEmptyUintPtrString OpType = 376
|
||||
OpStructFieldFloat32PtrString OpType = 377
|
||||
OpStructFieldOmitEmptyFloat32PtrString OpType = 378
|
||||
OpStructEndFloat32PtrString OpType = 379
|
||||
OpStructEndOmitEmptyFloat32PtrString OpType = 380
|
||||
OpStructFieldFloat64PtrString OpType = 381
|
||||
OpStructFieldOmitEmptyFloat64PtrString OpType = 382
|
||||
OpStructEndFloat64PtrString OpType = 383
|
||||
OpStructEndOmitEmptyFloat64PtrString OpType = 384
|
||||
OpStructFieldBoolPtrString OpType = 385
|
||||
OpStructFieldOmitEmptyBoolPtrString OpType = 386
|
||||
OpStructEndBoolPtrString OpType = 387
|
||||
OpStructEndOmitEmptyBoolPtrString OpType = 388
|
||||
OpStructFieldStringPtrString OpType = 389
|
||||
OpStructFieldOmitEmptyStringPtrString OpType = 390
|
||||
OpStructEndStringPtrString OpType = 391
|
||||
OpStructEndOmitEmptyStringPtrString OpType = 392
|
||||
OpStructFieldNumberPtrString OpType = 393
|
||||
OpStructFieldOmitEmptyNumberPtrString OpType = 394
|
||||
OpStructEndNumberPtrString OpType = 395
|
||||
OpStructEndOmitEmptyNumberPtrString OpType = 396
|
||||
OpStructField OpType = 397
|
||||
OpStructFieldOmitEmpty OpType = 398
|
||||
OpStructEnd OpType = 399
|
||||
OpStructEndOmitEmpty OpType = 400
|
||||
OpInt OpType = 14
|
||||
OpUint OpType = 15
|
||||
OpFloat32 OpType = 16
|
||||
OpFloat64 OpType = 17
|
||||
OpBool OpType = 18
|
||||
OpString OpType = 19
|
||||
OpBytes OpType = 20
|
||||
OpNumber OpType = 21
|
||||
OpArray OpType = 22
|
||||
OpMap OpType = 23
|
||||
OpSlice OpType = 24
|
||||
OpStruct OpType = 25
|
||||
OpMarshalJSON OpType = 26
|
||||
OpMarshalText OpType = 27
|
||||
OpIntString OpType = 28
|
||||
OpUintString OpType = 29
|
||||
OpFloat32String OpType = 30
|
||||
OpFloat64String OpType = 31
|
||||
OpBoolString OpType = 32
|
||||
OpStringString OpType = 33
|
||||
OpNumberString OpType = 34
|
||||
OpIntPtr OpType = 35
|
||||
OpUintPtr OpType = 36
|
||||
OpFloat32Ptr OpType = 37
|
||||
OpFloat64Ptr OpType = 38
|
||||
OpBoolPtr OpType = 39
|
||||
OpStringPtr OpType = 40
|
||||
OpBytesPtr OpType = 41
|
||||
OpNumberPtr OpType = 42
|
||||
OpArrayPtr OpType = 43
|
||||
OpMapPtr OpType = 44
|
||||
OpSlicePtr OpType = 45
|
||||
OpMarshalJSONPtr OpType = 46
|
||||
OpMarshalTextPtr OpType = 47
|
||||
OpInterfacePtr OpType = 48
|
||||
OpIntPtrString OpType = 49
|
||||
OpUintPtrString OpType = 50
|
||||
OpFloat32PtrString OpType = 51
|
||||
OpFloat64PtrString OpType = 52
|
||||
OpBoolPtrString OpType = 53
|
||||
OpStringPtrString OpType = 54
|
||||
OpNumberPtrString OpType = 55
|
||||
OpStructHeadInt OpType = 56
|
||||
OpStructHeadOmitEmptyInt OpType = 57
|
||||
OpStructPtrHeadInt OpType = 58
|
||||
OpStructPtrHeadOmitEmptyInt OpType = 59
|
||||
OpStructHeadUint OpType = 60
|
||||
OpStructHeadOmitEmptyUint OpType = 61
|
||||
OpStructPtrHeadUint OpType = 62
|
||||
OpStructPtrHeadOmitEmptyUint OpType = 63
|
||||
OpStructHeadFloat32 OpType = 64
|
||||
OpStructHeadOmitEmptyFloat32 OpType = 65
|
||||
OpStructPtrHeadFloat32 OpType = 66
|
||||
OpStructPtrHeadOmitEmptyFloat32 OpType = 67
|
||||
OpStructHeadFloat64 OpType = 68
|
||||
OpStructHeadOmitEmptyFloat64 OpType = 69
|
||||
OpStructPtrHeadFloat64 OpType = 70
|
||||
OpStructPtrHeadOmitEmptyFloat64 OpType = 71
|
||||
OpStructHeadBool OpType = 72
|
||||
OpStructHeadOmitEmptyBool OpType = 73
|
||||
OpStructPtrHeadBool OpType = 74
|
||||
OpStructPtrHeadOmitEmptyBool OpType = 75
|
||||
OpStructHeadString OpType = 76
|
||||
OpStructHeadOmitEmptyString OpType = 77
|
||||
OpStructPtrHeadString OpType = 78
|
||||
OpStructPtrHeadOmitEmptyString OpType = 79
|
||||
OpStructHeadBytes OpType = 80
|
||||
OpStructHeadOmitEmptyBytes OpType = 81
|
||||
OpStructPtrHeadBytes OpType = 82
|
||||
OpStructPtrHeadOmitEmptyBytes OpType = 83
|
||||
OpStructHeadNumber OpType = 84
|
||||
OpStructHeadOmitEmptyNumber OpType = 85
|
||||
OpStructPtrHeadNumber OpType = 86
|
||||
OpStructPtrHeadOmitEmptyNumber OpType = 87
|
||||
OpStructHeadArray OpType = 88
|
||||
OpStructHeadOmitEmptyArray OpType = 89
|
||||
OpStructPtrHeadArray OpType = 90
|
||||
OpStructPtrHeadOmitEmptyArray OpType = 91
|
||||
OpStructHeadMap OpType = 92
|
||||
OpStructHeadOmitEmptyMap OpType = 93
|
||||
OpStructPtrHeadMap OpType = 94
|
||||
OpStructPtrHeadOmitEmptyMap OpType = 95
|
||||
OpStructHeadSlice OpType = 96
|
||||
OpStructHeadOmitEmptySlice OpType = 97
|
||||
OpStructPtrHeadSlice OpType = 98
|
||||
OpStructPtrHeadOmitEmptySlice OpType = 99
|
||||
OpStructHeadStruct OpType = 100
|
||||
OpStructHeadOmitEmptyStruct OpType = 101
|
||||
OpStructPtrHeadStruct OpType = 102
|
||||
OpStructPtrHeadOmitEmptyStruct OpType = 103
|
||||
OpStructHeadMarshalJSON OpType = 104
|
||||
OpStructHeadOmitEmptyMarshalJSON OpType = 105
|
||||
OpStructPtrHeadMarshalJSON OpType = 106
|
||||
OpStructPtrHeadOmitEmptyMarshalJSON OpType = 107
|
||||
OpStructHeadMarshalText OpType = 108
|
||||
OpStructHeadOmitEmptyMarshalText OpType = 109
|
||||
OpStructPtrHeadMarshalText OpType = 110
|
||||
OpStructPtrHeadOmitEmptyMarshalText OpType = 111
|
||||
OpStructHeadIntString OpType = 112
|
||||
OpStructHeadOmitEmptyIntString OpType = 113
|
||||
OpStructPtrHeadIntString OpType = 114
|
||||
OpStructPtrHeadOmitEmptyIntString OpType = 115
|
||||
OpStructHeadUintString OpType = 116
|
||||
OpStructHeadOmitEmptyUintString OpType = 117
|
||||
OpStructPtrHeadUintString OpType = 118
|
||||
OpStructPtrHeadOmitEmptyUintString OpType = 119
|
||||
OpStructHeadFloat32String OpType = 120
|
||||
OpStructHeadOmitEmptyFloat32String OpType = 121
|
||||
OpStructPtrHeadFloat32String OpType = 122
|
||||
OpStructPtrHeadOmitEmptyFloat32String OpType = 123
|
||||
OpStructHeadFloat64String OpType = 124
|
||||
OpStructHeadOmitEmptyFloat64String OpType = 125
|
||||
OpStructPtrHeadFloat64String OpType = 126
|
||||
OpStructPtrHeadOmitEmptyFloat64String OpType = 127
|
||||
OpStructHeadBoolString OpType = 128
|
||||
OpStructHeadOmitEmptyBoolString OpType = 129
|
||||
OpStructPtrHeadBoolString OpType = 130
|
||||
OpStructPtrHeadOmitEmptyBoolString OpType = 131
|
||||
OpStructHeadStringString OpType = 132
|
||||
OpStructHeadOmitEmptyStringString OpType = 133
|
||||
OpStructPtrHeadStringString OpType = 134
|
||||
OpStructPtrHeadOmitEmptyStringString OpType = 135
|
||||
OpStructHeadNumberString OpType = 136
|
||||
OpStructHeadOmitEmptyNumberString OpType = 137
|
||||
OpStructPtrHeadNumberString OpType = 138
|
||||
OpStructPtrHeadOmitEmptyNumberString OpType = 139
|
||||
OpStructHeadIntPtr OpType = 140
|
||||
OpStructHeadOmitEmptyIntPtr OpType = 141
|
||||
OpStructPtrHeadIntPtr OpType = 142
|
||||
OpStructPtrHeadOmitEmptyIntPtr OpType = 143
|
||||
OpStructHeadUintPtr OpType = 144
|
||||
OpStructHeadOmitEmptyUintPtr OpType = 145
|
||||
OpStructPtrHeadUintPtr OpType = 146
|
||||
OpStructPtrHeadOmitEmptyUintPtr OpType = 147
|
||||
OpStructHeadFloat32Ptr OpType = 148
|
||||
OpStructHeadOmitEmptyFloat32Ptr OpType = 149
|
||||
OpStructPtrHeadFloat32Ptr OpType = 150
|
||||
OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 151
|
||||
OpStructHeadFloat64Ptr OpType = 152
|
||||
OpStructHeadOmitEmptyFloat64Ptr OpType = 153
|
||||
OpStructPtrHeadFloat64Ptr OpType = 154
|
||||
OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 155
|
||||
OpStructHeadBoolPtr OpType = 156
|
||||
OpStructHeadOmitEmptyBoolPtr OpType = 157
|
||||
OpStructPtrHeadBoolPtr OpType = 158
|
||||
OpStructPtrHeadOmitEmptyBoolPtr OpType = 159
|
||||
OpStructHeadStringPtr OpType = 160
|
||||
OpStructHeadOmitEmptyStringPtr OpType = 161
|
||||
OpStructPtrHeadStringPtr OpType = 162
|
||||
OpStructPtrHeadOmitEmptyStringPtr OpType = 163
|
||||
OpStructHeadBytesPtr OpType = 164
|
||||
OpStructHeadOmitEmptyBytesPtr OpType = 165
|
||||
OpStructPtrHeadBytesPtr OpType = 166
|
||||
OpStructPtrHeadOmitEmptyBytesPtr OpType = 167
|
||||
OpStructHeadNumberPtr OpType = 168
|
||||
OpStructHeadOmitEmptyNumberPtr OpType = 169
|
||||
OpStructPtrHeadNumberPtr OpType = 170
|
||||
OpStructPtrHeadOmitEmptyNumberPtr OpType = 171
|
||||
OpStructHeadArrayPtr OpType = 172
|
||||
OpStructHeadOmitEmptyArrayPtr OpType = 173
|
||||
OpStructPtrHeadArrayPtr OpType = 174
|
||||
OpStructPtrHeadOmitEmptyArrayPtr OpType = 175
|
||||
OpStructHeadMapPtr OpType = 176
|
||||
OpStructHeadOmitEmptyMapPtr OpType = 177
|
||||
OpStructPtrHeadMapPtr OpType = 178
|
||||
OpStructPtrHeadOmitEmptyMapPtr OpType = 179
|
||||
OpStructHeadSlicePtr OpType = 180
|
||||
OpStructHeadOmitEmptySlicePtr OpType = 181
|
||||
OpStructPtrHeadSlicePtr OpType = 182
|
||||
OpStructPtrHeadOmitEmptySlicePtr OpType = 183
|
||||
OpStructHeadMarshalJSONPtr OpType = 184
|
||||
OpStructHeadOmitEmptyMarshalJSONPtr OpType = 185
|
||||
OpStructPtrHeadMarshalJSONPtr OpType = 186
|
||||
OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 187
|
||||
OpStructHeadMarshalTextPtr OpType = 188
|
||||
OpStructHeadOmitEmptyMarshalTextPtr OpType = 189
|
||||
OpStructPtrHeadMarshalTextPtr OpType = 190
|
||||
OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 191
|
||||
OpStructHeadInterfacePtr OpType = 192
|
||||
OpStructHeadOmitEmptyInterfacePtr OpType = 193
|
||||
OpStructPtrHeadInterfacePtr OpType = 194
|
||||
OpStructPtrHeadOmitEmptyInterfacePtr OpType = 195
|
||||
OpStructHeadIntPtrString OpType = 196
|
||||
OpStructHeadOmitEmptyIntPtrString OpType = 197
|
||||
OpStructPtrHeadIntPtrString OpType = 198
|
||||
OpStructPtrHeadOmitEmptyIntPtrString OpType = 199
|
||||
OpStructHeadUintPtrString OpType = 200
|
||||
OpStructHeadOmitEmptyUintPtrString OpType = 201
|
||||
OpStructPtrHeadUintPtrString OpType = 202
|
||||
OpStructPtrHeadOmitEmptyUintPtrString OpType = 203
|
||||
OpStructHeadFloat32PtrString OpType = 204
|
||||
OpStructHeadOmitEmptyFloat32PtrString OpType = 205
|
||||
OpStructPtrHeadFloat32PtrString OpType = 206
|
||||
OpStructPtrHeadOmitEmptyFloat32PtrString OpType = 207
|
||||
OpStructHeadFloat64PtrString OpType = 208
|
||||
OpStructHeadOmitEmptyFloat64PtrString OpType = 209
|
||||
OpStructPtrHeadFloat64PtrString OpType = 210
|
||||
OpStructPtrHeadOmitEmptyFloat64PtrString OpType = 211
|
||||
OpStructHeadBoolPtrString OpType = 212
|
||||
OpStructHeadOmitEmptyBoolPtrString OpType = 213
|
||||
OpStructPtrHeadBoolPtrString OpType = 214
|
||||
OpStructPtrHeadOmitEmptyBoolPtrString OpType = 215
|
||||
OpStructHeadStringPtrString OpType = 216
|
||||
OpStructHeadOmitEmptyStringPtrString OpType = 217
|
||||
OpStructPtrHeadStringPtrString OpType = 218
|
||||
OpStructPtrHeadOmitEmptyStringPtrString OpType = 219
|
||||
OpStructHeadNumberPtrString OpType = 220
|
||||
OpStructHeadOmitEmptyNumberPtrString OpType = 221
|
||||
OpStructPtrHeadNumberPtrString OpType = 222
|
||||
OpStructPtrHeadOmitEmptyNumberPtrString OpType = 223
|
||||
OpStructHead OpType = 224
|
||||
OpStructHeadOmitEmpty OpType = 225
|
||||
OpStructPtrHead OpType = 226
|
||||
OpStructPtrHeadOmitEmpty OpType = 227
|
||||
OpStructFieldInt OpType = 228
|
||||
OpStructFieldOmitEmptyInt OpType = 229
|
||||
OpStructEndInt OpType = 230
|
||||
OpStructEndOmitEmptyInt OpType = 231
|
||||
OpStructFieldUint OpType = 232
|
||||
OpStructFieldOmitEmptyUint OpType = 233
|
||||
OpStructEndUint OpType = 234
|
||||
OpStructEndOmitEmptyUint OpType = 235
|
||||
OpStructFieldFloat32 OpType = 236
|
||||
OpStructFieldOmitEmptyFloat32 OpType = 237
|
||||
OpStructEndFloat32 OpType = 238
|
||||
OpStructEndOmitEmptyFloat32 OpType = 239
|
||||
OpStructFieldFloat64 OpType = 240
|
||||
OpStructFieldOmitEmptyFloat64 OpType = 241
|
||||
OpStructEndFloat64 OpType = 242
|
||||
OpStructEndOmitEmptyFloat64 OpType = 243
|
||||
OpStructFieldBool OpType = 244
|
||||
OpStructFieldOmitEmptyBool OpType = 245
|
||||
OpStructEndBool OpType = 246
|
||||
OpStructEndOmitEmptyBool OpType = 247
|
||||
OpStructFieldString OpType = 248
|
||||
OpStructFieldOmitEmptyString OpType = 249
|
||||
OpStructEndString OpType = 250
|
||||
OpStructEndOmitEmptyString OpType = 251
|
||||
OpStructFieldBytes OpType = 252
|
||||
OpStructFieldOmitEmptyBytes OpType = 253
|
||||
OpStructEndBytes OpType = 254
|
||||
OpStructEndOmitEmptyBytes OpType = 255
|
||||
OpStructFieldNumber OpType = 256
|
||||
OpStructFieldOmitEmptyNumber OpType = 257
|
||||
OpStructEndNumber OpType = 258
|
||||
OpStructEndOmitEmptyNumber OpType = 259
|
||||
OpStructFieldArray OpType = 260
|
||||
OpStructFieldOmitEmptyArray OpType = 261
|
||||
OpStructEndArray OpType = 262
|
||||
OpStructEndOmitEmptyArray OpType = 263
|
||||
OpStructFieldMap OpType = 264
|
||||
OpStructFieldOmitEmptyMap OpType = 265
|
||||
OpStructEndMap OpType = 266
|
||||
OpStructEndOmitEmptyMap OpType = 267
|
||||
OpStructFieldSlice OpType = 268
|
||||
OpStructFieldOmitEmptySlice OpType = 269
|
||||
OpStructEndSlice OpType = 270
|
||||
OpStructEndOmitEmptySlice OpType = 271
|
||||
OpStructFieldStruct OpType = 272
|
||||
OpStructFieldOmitEmptyStruct OpType = 273
|
||||
OpStructEndStruct OpType = 274
|
||||
OpStructEndOmitEmptyStruct OpType = 275
|
||||
OpStructFieldMarshalJSON OpType = 276
|
||||
OpStructFieldOmitEmptyMarshalJSON OpType = 277
|
||||
OpStructEndMarshalJSON OpType = 278
|
||||
OpStructEndOmitEmptyMarshalJSON OpType = 279
|
||||
OpStructFieldMarshalText OpType = 280
|
||||
OpStructFieldOmitEmptyMarshalText OpType = 281
|
||||
OpStructEndMarshalText OpType = 282
|
||||
OpStructEndOmitEmptyMarshalText OpType = 283
|
||||
OpStructFieldIntString OpType = 284
|
||||
OpStructFieldOmitEmptyIntString OpType = 285
|
||||
OpStructEndIntString OpType = 286
|
||||
OpStructEndOmitEmptyIntString OpType = 287
|
||||
OpStructFieldUintString OpType = 288
|
||||
OpStructFieldOmitEmptyUintString OpType = 289
|
||||
OpStructEndUintString OpType = 290
|
||||
OpStructEndOmitEmptyUintString OpType = 291
|
||||
OpStructFieldFloat32String OpType = 292
|
||||
OpStructFieldOmitEmptyFloat32String OpType = 293
|
||||
OpStructEndFloat32String OpType = 294
|
||||
OpStructEndOmitEmptyFloat32String OpType = 295
|
||||
OpStructFieldFloat64String OpType = 296
|
||||
OpStructFieldOmitEmptyFloat64String OpType = 297
|
||||
OpStructEndFloat64String OpType = 298
|
||||
OpStructEndOmitEmptyFloat64String OpType = 299
|
||||
OpStructFieldBoolString OpType = 300
|
||||
OpStructFieldOmitEmptyBoolString OpType = 301
|
||||
OpStructEndBoolString OpType = 302
|
||||
OpStructEndOmitEmptyBoolString OpType = 303
|
||||
OpStructFieldStringString OpType = 304
|
||||
OpStructFieldOmitEmptyStringString OpType = 305
|
||||
OpStructEndStringString OpType = 306
|
||||
OpStructEndOmitEmptyStringString OpType = 307
|
||||
OpStructFieldNumberString OpType = 308
|
||||
OpStructFieldOmitEmptyNumberString OpType = 309
|
||||
OpStructEndNumberString OpType = 310
|
||||
OpStructEndOmitEmptyNumberString OpType = 311
|
||||
OpStructFieldIntPtr OpType = 312
|
||||
OpStructFieldOmitEmptyIntPtr OpType = 313
|
||||
OpStructEndIntPtr OpType = 314
|
||||
OpStructEndOmitEmptyIntPtr OpType = 315
|
||||
OpStructFieldUintPtr OpType = 316
|
||||
OpStructFieldOmitEmptyUintPtr OpType = 317
|
||||
OpStructEndUintPtr OpType = 318
|
||||
OpStructEndOmitEmptyUintPtr OpType = 319
|
||||
OpStructFieldFloat32Ptr OpType = 320
|
||||
OpStructFieldOmitEmptyFloat32Ptr OpType = 321
|
||||
OpStructEndFloat32Ptr OpType = 322
|
||||
OpStructEndOmitEmptyFloat32Ptr OpType = 323
|
||||
OpStructFieldFloat64Ptr OpType = 324
|
||||
OpStructFieldOmitEmptyFloat64Ptr OpType = 325
|
||||
OpStructEndFloat64Ptr OpType = 326
|
||||
OpStructEndOmitEmptyFloat64Ptr OpType = 327
|
||||
OpStructFieldBoolPtr OpType = 328
|
||||
OpStructFieldOmitEmptyBoolPtr OpType = 329
|
||||
OpStructEndBoolPtr OpType = 330
|
||||
OpStructEndOmitEmptyBoolPtr OpType = 331
|
||||
OpStructFieldStringPtr OpType = 332
|
||||
OpStructFieldOmitEmptyStringPtr OpType = 333
|
||||
OpStructEndStringPtr OpType = 334
|
||||
OpStructEndOmitEmptyStringPtr OpType = 335
|
||||
OpStructFieldBytesPtr OpType = 336
|
||||
OpStructFieldOmitEmptyBytesPtr OpType = 337
|
||||
OpStructEndBytesPtr OpType = 338
|
||||
OpStructEndOmitEmptyBytesPtr OpType = 339
|
||||
OpStructFieldNumberPtr OpType = 340
|
||||
OpStructFieldOmitEmptyNumberPtr OpType = 341
|
||||
OpStructEndNumberPtr OpType = 342
|
||||
OpStructEndOmitEmptyNumberPtr OpType = 343
|
||||
OpStructFieldArrayPtr OpType = 344
|
||||
OpStructFieldOmitEmptyArrayPtr OpType = 345
|
||||
OpStructEndArrayPtr OpType = 346
|
||||
OpStructEndOmitEmptyArrayPtr OpType = 347
|
||||
OpStructFieldMapPtr OpType = 348
|
||||
OpStructFieldOmitEmptyMapPtr OpType = 349
|
||||
OpStructEndMapPtr OpType = 350
|
||||
OpStructEndOmitEmptyMapPtr OpType = 351
|
||||
OpStructFieldSlicePtr OpType = 352
|
||||
OpStructFieldOmitEmptySlicePtr OpType = 353
|
||||
OpStructEndSlicePtr OpType = 354
|
||||
OpStructEndOmitEmptySlicePtr OpType = 355
|
||||
OpStructFieldMarshalJSONPtr OpType = 356
|
||||
OpStructFieldOmitEmptyMarshalJSONPtr OpType = 357
|
||||
OpStructEndMarshalJSONPtr OpType = 358
|
||||
OpStructEndOmitEmptyMarshalJSONPtr OpType = 359
|
||||
OpStructFieldMarshalTextPtr OpType = 360
|
||||
OpStructFieldOmitEmptyMarshalTextPtr OpType = 361
|
||||
OpStructEndMarshalTextPtr OpType = 362
|
||||
OpStructEndOmitEmptyMarshalTextPtr OpType = 363
|
||||
OpStructFieldInterfacePtr OpType = 364
|
||||
OpStructFieldOmitEmptyInterfacePtr OpType = 365
|
||||
OpStructEndInterfacePtr OpType = 366
|
||||
OpStructEndOmitEmptyInterfacePtr OpType = 367
|
||||
OpStructFieldIntPtrString OpType = 368
|
||||
OpStructFieldOmitEmptyIntPtrString OpType = 369
|
||||
OpStructEndIntPtrString OpType = 370
|
||||
OpStructEndOmitEmptyIntPtrString OpType = 371
|
||||
OpStructFieldUintPtrString OpType = 372
|
||||
OpStructFieldOmitEmptyUintPtrString OpType = 373
|
||||
OpStructEndUintPtrString OpType = 374
|
||||
OpStructEndOmitEmptyUintPtrString OpType = 375
|
||||
OpStructFieldFloat32PtrString OpType = 376
|
||||
OpStructFieldOmitEmptyFloat32PtrString OpType = 377
|
||||
OpStructEndFloat32PtrString OpType = 378
|
||||
OpStructEndOmitEmptyFloat32PtrString OpType = 379
|
||||
OpStructFieldFloat64PtrString OpType = 380
|
||||
OpStructFieldOmitEmptyFloat64PtrString OpType = 381
|
||||
OpStructEndFloat64PtrString OpType = 382
|
||||
OpStructEndOmitEmptyFloat64PtrString OpType = 383
|
||||
OpStructFieldBoolPtrString OpType = 384
|
||||
OpStructFieldOmitEmptyBoolPtrString OpType = 385
|
||||
OpStructEndBoolPtrString OpType = 386
|
||||
OpStructEndOmitEmptyBoolPtrString OpType = 387
|
||||
OpStructFieldStringPtrString OpType = 388
|
||||
OpStructFieldOmitEmptyStringPtrString OpType = 389
|
||||
OpStructEndStringPtrString OpType = 390
|
||||
OpStructEndOmitEmptyStringPtrString OpType = 391
|
||||
OpStructFieldNumberPtrString OpType = 392
|
||||
OpStructFieldOmitEmptyNumberPtrString OpType = 393
|
||||
OpStructEndNumberPtrString OpType = 394
|
||||
OpStructEndOmitEmptyNumberPtrString OpType = 395
|
||||
OpStructField OpType = 396
|
||||
OpStructFieldOmitEmpty OpType = 397
|
||||
OpStructEnd OpType = 398
|
||||
OpStructEndOmitEmpty OpType = 399
|
||||
)
|
||||
|
||||
func (t OpType) String() string {
|
||||
if int(t) >= 401 {
|
||||
if int(t) >= 400 {
|
||||
return ""
|
||||
}
|
||||
return opTypeStrings[int(t)]
|
||||
@ -896,7 +894,7 @@ func (t OpType) HeadToOmitEmptyHead() OpType {
|
||||
}
|
||||
|
||||
func (t OpType) PtrHeadToHead() OpType {
|
||||
idx := strings.Index(t.String(), "Ptr")
|
||||
idx := strings.Index(t.String(), "PtrHead")
|
||||
if idx == -1 {
|
||||
return t
|
||||
}
|
||||
|
135
vendor/github.com/goccy/go-json/internal/encoder/query.go
generated
vendored
Normal file
135
vendor/github.com/goccy/go-json/internal/encoder/query.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
package encoder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
Marshal func(interface{}) ([]byte, error)
|
||||
Unmarshal func([]byte, interface{}) error
|
||||
)
|
||||
|
||||
type FieldQuery struct {
|
||||
Name string
|
||||
Fields []*FieldQuery
|
||||
hash string
|
||||
}
|
||||
|
||||
func (q *FieldQuery) Hash() string {
|
||||
if q.hash != "" {
|
||||
return q.hash
|
||||
}
|
||||
b, _ := Marshal(q)
|
||||
q.hash = string(b)
|
||||
return q.hash
|
||||
}
|
||||
|
||||
func (q *FieldQuery) MarshalJSON() ([]byte, error) {
|
||||
if q.Name != "" {
|
||||
if len(q.Fields) > 0 {
|
||||
return Marshal(map[string][]*FieldQuery{q.Name: q.Fields})
|
||||
}
|
||||
return Marshal(q.Name)
|
||||
}
|
||||
return Marshal(q.Fields)
|
||||
}
|
||||
|
||||
func (q *FieldQuery) QueryString() (FieldQueryString, error) {
|
||||
b, err := Marshal(q)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return FieldQueryString(b), nil
|
||||
}
|
||||
|
||||
type FieldQueryString string
|
||||
|
||||
func (s FieldQueryString) Build() (*FieldQuery, error) {
|
||||
var query interface{}
|
||||
if err := Unmarshal([]byte(s), &query); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.build(reflect.ValueOf(query))
|
||||
}
|
||||
|
||||
func (s FieldQueryString) build(v reflect.Value) (*FieldQuery, error) {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.String:
|
||||
return s.buildString(v)
|
||||
case reflect.Map:
|
||||
return s.buildMap(v)
|
||||
case reflect.Slice:
|
||||
return s.buildSlice(v)
|
||||
case reflect.Interface:
|
||||
return s.build(reflect.ValueOf(v.Interface()))
|
||||
}
|
||||
return nil, fmt.Errorf("failed to build field query")
|
||||
}
|
||||
|
||||
func (s FieldQueryString) buildString(v reflect.Value) (*FieldQuery, error) {
|
||||
b := []byte(v.String())
|
||||
switch b[0] {
|
||||
case '[', '{':
|
||||
var query interface{}
|
||||
if err := Unmarshal(b, &query); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if str, ok := query.(string); ok {
|
||||
return &FieldQuery{Name: str}, nil
|
||||
}
|
||||
return s.build(reflect.ValueOf(query))
|
||||
}
|
||||
return &FieldQuery{Name: string(b)}, nil
|
||||
}
|
||||
|
||||
func (s FieldQueryString) buildSlice(v reflect.Value) (*FieldQuery, error) {
|
||||
fields := make([]*FieldQuery, 0, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
def, err := s.build(v.Index(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields = append(fields, def)
|
||||
}
|
||||
return &FieldQuery{Fields: fields}, nil
|
||||
}
|
||||
|
||||
func (s FieldQueryString) buildMap(v reflect.Value) (*FieldQuery, error) {
|
||||
keys := v.MapKeys()
|
||||
if len(keys) != 1 {
|
||||
return nil, fmt.Errorf("failed to build field query object")
|
||||
}
|
||||
key := keys[0]
|
||||
if key.Type().Kind() != reflect.String {
|
||||
return nil, fmt.Errorf("failed to build field query. invalid object key type")
|
||||
}
|
||||
name := key.String()
|
||||
def, err := s.build(v.MapIndex(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FieldQuery{
|
||||
Name: name,
|
||||
Fields: def.Fields,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type queryKey struct{}
|
||||
|
||||
func FieldQueryFromContext(ctx context.Context) *FieldQuery {
|
||||
query := ctx.Value(queryKey{})
|
||||
if query == nil {
|
||||
return nil
|
||||
}
|
||||
q, ok := query.(*FieldQuery)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func SetFieldQueryToContext(ctx context.Context, query *FieldQuery) context.Context {
|
||||
return context.WithValue(ctx, queryKey{}, query)
|
||||
}
|
719
vendor/github.com/goccy/go-json/internal/encoder/string.go
generated
vendored
719
vendor/github.com/goccy/go-json/internal/encoder/string.go
generated
vendored
@ -3,7 +3,6 @@ package encoder
|
||||
import (
|
||||
"math/bits"
|
||||
"reflect"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@ -12,390 +11,8 @@ const (
|
||||
msb = 0x8080808080808080
|
||||
)
|
||||
|
||||
var needEscapeWithHTML = [256]bool{
|
||||
'"': true,
|
||||
'&': true,
|
||||
'<': true,
|
||||
'>': true,
|
||||
'\\': true,
|
||||
0x00: true,
|
||||
0x01: true,
|
||||
0x02: true,
|
||||
0x03: true,
|
||||
0x04: true,
|
||||
0x05: true,
|
||||
0x06: true,
|
||||
0x07: true,
|
||||
0x08: true,
|
||||
0x09: true,
|
||||
0x0a: true,
|
||||
0x0b: true,
|
||||
0x0c: true,
|
||||
0x0d: true,
|
||||
0x0e: true,
|
||||
0x0f: true,
|
||||
0x10: true,
|
||||
0x11: true,
|
||||
0x12: true,
|
||||
0x13: true,
|
||||
0x14: true,
|
||||
0x15: true,
|
||||
0x16: true,
|
||||
0x17: true,
|
||||
0x18: true,
|
||||
0x19: true,
|
||||
0x1a: true,
|
||||
0x1b: true,
|
||||
0x1c: true,
|
||||
0x1d: true,
|
||||
0x1e: true,
|
||||
0x1f: true,
|
||||
/* 0x20 - 0x7f */
|
||||
0x80: true,
|
||||
0x81: true,
|
||||
0x82: true,
|
||||
0x83: true,
|
||||
0x84: true,
|
||||
0x85: true,
|
||||
0x86: true,
|
||||
0x87: true,
|
||||
0x88: true,
|
||||
0x89: true,
|
||||
0x8a: true,
|
||||
0x8b: true,
|
||||
0x8c: true,
|
||||
0x8d: true,
|
||||
0x8e: true,
|
||||
0x8f: true,
|
||||
0x90: true,
|
||||
0x91: true,
|
||||
0x92: true,
|
||||
0x93: true,
|
||||
0x94: true,
|
||||
0x95: true,
|
||||
0x96: true,
|
||||
0x97: true,
|
||||
0x98: true,
|
||||
0x99: true,
|
||||
0x9a: true,
|
||||
0x9b: true,
|
||||
0x9c: true,
|
||||
0x9d: true,
|
||||
0x9e: true,
|
||||
0x9f: true,
|
||||
0xa0: true,
|
||||
0xa1: true,
|
||||
0xa2: true,
|
||||
0xa3: true,
|
||||
0xa4: true,
|
||||
0xa5: true,
|
||||
0xa6: true,
|
||||
0xa7: true,
|
||||
0xa8: true,
|
||||
0xa9: true,
|
||||
0xaa: true,
|
||||
0xab: true,
|
||||
0xac: true,
|
||||
0xad: true,
|
||||
0xae: true,
|
||||
0xaf: true,
|
||||
0xb0: true,
|
||||
0xb1: true,
|
||||
0xb2: true,
|
||||
0xb3: true,
|
||||
0xb4: true,
|
||||
0xb5: true,
|
||||
0xb6: true,
|
||||
0xb7: true,
|
||||
0xb8: true,
|
||||
0xb9: true,
|
||||
0xba: true,
|
||||
0xbb: true,
|
||||
0xbc: true,
|
||||
0xbd: true,
|
||||
0xbe: true,
|
||||
0xbf: true,
|
||||
0xc0: true,
|
||||
0xc1: true,
|
||||
0xc2: true,
|
||||
0xc3: true,
|
||||
0xc4: true,
|
||||
0xc5: true,
|
||||
0xc6: true,
|
||||
0xc7: true,
|
||||
0xc8: true,
|
||||
0xc9: true,
|
||||
0xca: true,
|
||||
0xcb: true,
|
||||
0xcc: true,
|
||||
0xcd: true,
|
||||
0xce: true,
|
||||
0xcf: true,
|
||||
0xd0: true,
|
||||
0xd1: true,
|
||||
0xd2: true,
|
||||
0xd3: true,
|
||||
0xd4: true,
|
||||
0xd5: true,
|
||||
0xd6: true,
|
||||
0xd7: true,
|
||||
0xd8: true,
|
||||
0xd9: true,
|
||||
0xda: true,
|
||||
0xdb: true,
|
||||
0xdc: true,
|
||||
0xdd: true,
|
||||
0xde: true,
|
||||
0xdf: true,
|
||||
0xe0: true,
|
||||
0xe1: true,
|
||||
0xe2: true,
|
||||
0xe3: true,
|
||||
0xe4: true,
|
||||
0xe5: true,
|
||||
0xe6: true,
|
||||
0xe7: true,
|
||||
0xe8: true,
|
||||
0xe9: true,
|
||||
0xea: true,
|
||||
0xeb: true,
|
||||
0xec: true,
|
||||
0xed: true,
|
||||
0xee: true,
|
||||
0xef: true,
|
||||
0xf0: true,
|
||||
0xf1: true,
|
||||
0xf2: true,
|
||||
0xf3: true,
|
||||
0xf4: true,
|
||||
0xf5: true,
|
||||
0xf6: true,
|
||||
0xf7: true,
|
||||
0xf8: true,
|
||||
0xf9: true,
|
||||
0xfa: true,
|
||||
0xfb: true,
|
||||
0xfc: true,
|
||||
0xfd: true,
|
||||
0xfe: true,
|
||||
0xff: true,
|
||||
}
|
||||
|
||||
var needEscape = [256]bool{
|
||||
'"': true,
|
||||
'\\': true,
|
||||
0x00: true,
|
||||
0x01: true,
|
||||
0x02: true,
|
||||
0x03: true,
|
||||
0x04: true,
|
||||
0x05: true,
|
||||
0x06: true,
|
||||
0x07: true,
|
||||
0x08: true,
|
||||
0x09: true,
|
||||
0x0a: true,
|
||||
0x0b: true,
|
||||
0x0c: true,
|
||||
0x0d: true,
|
||||
0x0e: true,
|
||||
0x0f: true,
|
||||
0x10: true,
|
||||
0x11: true,
|
||||
0x12: true,
|
||||
0x13: true,
|
||||
0x14: true,
|
||||
0x15: true,
|
||||
0x16: true,
|
||||
0x17: true,
|
||||
0x18: true,
|
||||
0x19: true,
|
||||
0x1a: true,
|
||||
0x1b: true,
|
||||
0x1c: true,
|
||||
0x1d: true,
|
||||
0x1e: true,
|
||||
0x1f: true,
|
||||
/* 0x20 - 0x7f */
|
||||
0x80: true,
|
||||
0x81: true,
|
||||
0x82: true,
|
||||
0x83: true,
|
||||
0x84: true,
|
||||
0x85: true,
|
||||
0x86: true,
|
||||
0x87: true,
|
||||
0x88: true,
|
||||
0x89: true,
|
||||
0x8a: true,
|
||||
0x8b: true,
|
||||
0x8c: true,
|
||||
0x8d: true,
|
||||
0x8e: true,
|
||||
0x8f: true,
|
||||
0x90: true,
|
||||
0x91: true,
|
||||
0x92: true,
|
||||
0x93: true,
|
||||
0x94: true,
|
||||
0x95: true,
|
||||
0x96: true,
|
||||
0x97: true,
|
||||
0x98: true,
|
||||
0x99: true,
|
||||
0x9a: true,
|
||||
0x9b: true,
|
||||
0x9c: true,
|
||||
0x9d: true,
|
||||
0x9e: true,
|
||||
0x9f: true,
|
||||
0xa0: true,
|
||||
0xa1: true,
|
||||
0xa2: true,
|
||||
0xa3: true,
|
||||
0xa4: true,
|
||||
0xa5: true,
|
||||
0xa6: true,
|
||||
0xa7: true,
|
||||
0xa8: true,
|
||||
0xa9: true,
|
||||
0xaa: true,
|
||||
0xab: true,
|
||||
0xac: true,
|
||||
0xad: true,
|
||||
0xae: true,
|
||||
0xaf: true,
|
||||
0xb0: true,
|
||||
0xb1: true,
|
||||
0xb2: true,
|
||||
0xb3: true,
|
||||
0xb4: true,
|
||||
0xb5: true,
|
||||
0xb6: true,
|
||||
0xb7: true,
|
||||
0xb8: true,
|
||||
0xb9: true,
|
||||
0xba: true,
|
||||
0xbb: true,
|
||||
0xbc: true,
|
||||
0xbd: true,
|
||||
0xbe: true,
|
||||
0xbf: true,
|
||||
0xc0: true,
|
||||
0xc1: true,
|
||||
0xc2: true,
|
||||
0xc3: true,
|
||||
0xc4: true,
|
||||
0xc5: true,
|
||||
0xc6: true,
|
||||
0xc7: true,
|
||||
0xc8: true,
|
||||
0xc9: true,
|
||||
0xca: true,
|
||||
0xcb: true,
|
||||
0xcc: true,
|
||||
0xcd: true,
|
||||
0xce: true,
|
||||
0xcf: true,
|
||||
0xd0: true,
|
||||
0xd1: true,
|
||||
0xd2: true,
|
||||
0xd3: true,
|
||||
0xd4: true,
|
||||
0xd5: true,
|
||||
0xd6: true,
|
||||
0xd7: true,
|
||||
0xd8: true,
|
||||
0xd9: true,
|
||||
0xda: true,
|
||||
0xdb: true,
|
||||
0xdc: true,
|
||||
0xdd: true,
|
||||
0xde: true,
|
||||
0xdf: true,
|
||||
0xe0: true,
|
||||
0xe1: true,
|
||||
0xe2: true,
|
||||
0xe3: true,
|
||||
0xe4: true,
|
||||
0xe5: true,
|
||||
0xe6: true,
|
||||
0xe7: true,
|
||||
0xe8: true,
|
||||
0xe9: true,
|
||||
0xea: true,
|
||||
0xeb: true,
|
||||
0xec: true,
|
||||
0xed: true,
|
||||
0xee: true,
|
||||
0xef: true,
|
||||
0xf0: true,
|
||||
0xf1: true,
|
||||
0xf2: true,
|
||||
0xf3: true,
|
||||
0xf4: true,
|
||||
0xf5: true,
|
||||
0xf6: true,
|
||||
0xf7: true,
|
||||
0xf8: true,
|
||||
0xf9: true,
|
||||
0xfa: true,
|
||||
0xfb: true,
|
||||
0xfc: true,
|
||||
0xfd: true,
|
||||
0xfe: true,
|
||||
0xff: true,
|
||||
}
|
||||
|
||||
var hex = "0123456789abcdef"
|
||||
|
||||
// escapeIndex finds the index of the first char in `s` that requires escaping.
|
||||
// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if
|
||||
// it includes a double quote or backslash.
|
||||
// If no chars in `s` require escaping, the return value is -1.
|
||||
func escapeIndex(s string) int {
|
||||
chunks := stringToUint64Slice(s)
|
||||
for _, n := range chunks {
|
||||
// combine masks before checking for the MSB of each byte. We include
|
||||
// `n` in the mask to check whether any of the *input* byte MSBs were
|
||||
// set (i.e. the byte was outside the ASCII range).
|
||||
mask := n | below(n, 0x20) | contains(n, '"') | contains(n, '\\')
|
||||
if (mask & msb) != 0 {
|
||||
return bits.TrailingZeros64(mask&msb) / 8
|
||||
}
|
||||
}
|
||||
|
||||
valLen := len(s)
|
||||
for i := len(chunks) * 8; i < valLen; i++ {
|
||||
if needEscape[s[i]] {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// below return a mask that can be used to determine if any of the bytes
|
||||
// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was
|
||||
// below `b`. The result is only valid if `b`, and each byte in `n`, is below
|
||||
// 0x80.
|
||||
func below(n uint64, b byte) uint64 {
|
||||
return n - expand(b)
|
||||
}
|
||||
|
||||
// contains returns a mask that can be used to determine if any of the
|
||||
// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then
|
||||
// that byte is equal to `b`. The result is only valid if `b`, and each
|
||||
// byte in `n`, is below 0x80.
|
||||
func contains(n uint64, b byte) uint64 {
|
||||
return (n ^ expand(b)) - lsb
|
||||
}
|
||||
|
||||
// expand puts the specified byte into each of the 8 bytes of a uint64.
|
||||
func expand(b byte) uint64 {
|
||||
return lsb * uint64(b)
|
||||
}
|
||||
|
||||
//nolint:govet
|
||||
func stringToUint64Slice(s string) []uint64 {
|
||||
return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{
|
||||
@ -406,9 +23,19 @@ func stringToUint64Slice(s string) []uint64 {
|
||||
}
|
||||
|
||||
func AppendString(ctx *RuntimeContext, buf []byte, s string) []byte {
|
||||
if ctx.Option.Flag&HTMLEscapeOption == 0 {
|
||||
return appendString(buf, s)
|
||||
if ctx.Option.Flag&HTMLEscapeOption != 0 {
|
||||
if ctx.Option.Flag&NormalizeUTF8Option != 0 {
|
||||
return appendNormalizedHTMLString(buf, s)
|
||||
}
|
||||
return appendHTMLString(buf, s)
|
||||
}
|
||||
if ctx.Option.Flag&NormalizeUTF8Option != 0 {
|
||||
return appendNormalizedString(buf, s)
|
||||
}
|
||||
return appendString(buf, s)
|
||||
}
|
||||
|
||||
func appendNormalizedHTMLString(buf []byte, s string) []byte {
|
||||
valLen := len(s)
|
||||
if valLen == 0 {
|
||||
return append(buf, `""`...)
|
||||
@ -435,7 +62,7 @@ func AppendString(ctx *RuntimeContext, buf []byte, s string) []byte {
|
||||
}
|
||||
}
|
||||
for i := len(chunks) * 8; i < valLen; i++ {
|
||||
if needEscapeWithHTML[s[i]] {
|
||||
if needEscapeHTMLNormalizeUTF8[s[i]] {
|
||||
j = i
|
||||
goto ESCAPE_END
|
||||
}
|
||||
@ -447,7 +74,7 @@ ESCAPE_END:
|
||||
for j < valLen {
|
||||
c := s[j]
|
||||
|
||||
if !needEscapeWithHTML[c] {
|
||||
if !needEscapeHTMLNormalizeUTF8[c] {
|
||||
// fast path: most of the time, printable ascii characters are used
|
||||
j++
|
||||
continue
|
||||
@ -489,10 +116,220 @@ ESCAPE_END:
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u00`...)
|
||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
}
|
||||
state, size := decodeRuneInString(s[j:])
|
||||
switch state {
|
||||
case runeErrorState:
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\ufffd`...)
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
// U+2028 is LINE SEPARATOR.
|
||||
// U+2029 is PARAGRAPH SEPARATOR.
|
||||
// They are both technically valid characters in JSON strings,
|
||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||
// and can lead to security holes there. It is valid JSON to
|
||||
// escape them, so we do so unconditionally.
|
||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||
case lineSepState:
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u2028`...)
|
||||
i = j + 3
|
||||
j = j + 3
|
||||
continue
|
||||
case paragraphSepState:
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u2029`...)
|
||||
i = j + 3
|
||||
j = j + 3
|
||||
continue
|
||||
}
|
||||
j += size
|
||||
}
|
||||
|
||||
// This encodes bytes < 0x20 except for \t, \n and \r.
|
||||
if c < 0x20 {
|
||||
return append(append(buf, s[i:]...), '"')
|
||||
}
|
||||
|
||||
func appendHTMLString(buf []byte, s string) []byte {
|
||||
valLen := len(s)
|
||||
if valLen == 0 {
|
||||
return append(buf, `""`...)
|
||||
}
|
||||
buf = append(buf, '"')
|
||||
var (
|
||||
i, j int
|
||||
)
|
||||
if valLen >= 8 {
|
||||
chunks := stringToUint64Slice(s)
|
||||
for _, n := range chunks {
|
||||
// combine masks before checking for the MSB of each byte. We include
|
||||
// `n` in the mask to check whether any of the *input* byte MSBs were
|
||||
// set (i.e. the byte was outside the ASCII range).
|
||||
mask := n | (n - (lsb * 0x20)) |
|
||||
((n ^ (lsb * '"')) - lsb) |
|
||||
((n ^ (lsb * '\\')) - lsb) |
|
||||
((n ^ (lsb * '<')) - lsb) |
|
||||
((n ^ (lsb * '>')) - lsb) |
|
||||
((n ^ (lsb * '&')) - lsb)
|
||||
if (mask & msb) != 0 {
|
||||
j = bits.TrailingZeros64(mask&msb) / 8
|
||||
goto ESCAPE_END
|
||||
}
|
||||
}
|
||||
for i := len(chunks) * 8; i < valLen; i++ {
|
||||
if needEscapeHTML[s[i]] {
|
||||
j = i
|
||||
goto ESCAPE_END
|
||||
}
|
||||
}
|
||||
// no found any escape characters.
|
||||
return append(append(buf, s...), '"')
|
||||
}
|
||||
ESCAPE_END:
|
||||
for j < valLen {
|
||||
c := s[j]
|
||||
|
||||
if !needEscapeHTML[c] {
|
||||
// fast path: most of the time, printable ascii characters are used
|
||||
j++
|
||||
continue
|
||||
}
|
||||
|
||||
switch c {
|
||||
case '\\', '"':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, '\\', c)
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case '\n':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, '\\', 'n')
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case '\r':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, '\\', 'r')
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case '\t':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, '\\', 't')
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case '<', '>', '&':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u00`...)
|
||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u00`...)
|
||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
}
|
||||
j++
|
||||
}
|
||||
|
||||
return append(append(buf, s[i:]...), '"')
|
||||
}
|
||||
|
||||
func appendNormalizedString(buf []byte, s string) []byte {
|
||||
valLen := len(s)
|
||||
if valLen == 0 {
|
||||
return append(buf, `""`...)
|
||||
}
|
||||
buf = append(buf, '"')
|
||||
var (
|
||||
i, j int
|
||||
)
|
||||
if valLen >= 8 {
|
||||
chunks := stringToUint64Slice(s)
|
||||
for _, n := range chunks {
|
||||
// combine masks before checking for the MSB of each byte. We include
|
||||
// `n` in the mask to check whether any of the *input* byte MSBs were
|
||||
// set (i.e. the byte was outside the ASCII range).
|
||||
mask := n | (n - (lsb * 0x20)) |
|
||||
((n ^ (lsb * '"')) - lsb) |
|
||||
((n ^ (lsb * '\\')) - lsb)
|
||||
if (mask & msb) != 0 {
|
||||
j = bits.TrailingZeros64(mask&msb) / 8
|
||||
goto ESCAPE_END
|
||||
}
|
||||
}
|
||||
valLen := len(s)
|
||||
for i := len(chunks) * 8; i < valLen; i++ {
|
||||
if needEscapeNormalizeUTF8[s[i]] {
|
||||
j = i
|
||||
goto ESCAPE_END
|
||||
}
|
||||
}
|
||||
return append(append(buf, s...), '"')
|
||||
}
|
||||
ESCAPE_END:
|
||||
for j < valLen {
|
||||
c := s[j]
|
||||
|
||||
if !needEscapeNormalizeUTF8[c] {
|
||||
// fast path: most of the time, printable ascii characters are used
|
||||
j++
|
||||
continue
|
||||
}
|
||||
|
||||
switch c {
|
||||
case '\\', '"':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, '\\', c)
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case '\n':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, '\\', 'n')
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case '\r':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, '\\', 'r')
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case '\t':
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, '\\', 't')
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u00`...)
|
||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||
@ -501,18 +338,14 @@ ESCAPE_END:
|
||||
continue
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRuneInString(s[j:])
|
||||
|
||||
if r == utf8.RuneError && size == 1 {
|
||||
state, size := decodeRuneInString(s[j:])
|
||||
switch state {
|
||||
case runeErrorState:
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\ufffd`...)
|
||||
i = j + size
|
||||
j = j + size
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
}
|
||||
|
||||
switch r {
|
||||
case '\u2028', '\u2029':
|
||||
// U+2028 is LINE SEPARATOR.
|
||||
// U+2029 is PARAGRAPH SEPARATOR.
|
||||
// They are both technically valid characters in JSON strings,
|
||||
@ -520,14 +353,19 @@ ESCAPE_END:
|
||||
// and can lead to security holes there. It is valid JSON to
|
||||
// escape them, so we do so unconditionally.
|
||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||
case lineSepState:
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u202`...)
|
||||
buf = append(buf, hex[r&0xF])
|
||||
i = j + size
|
||||
j = j + size
|
||||
buf = append(buf, `\u2028`...)
|
||||
i = j + 3
|
||||
j = j + 3
|
||||
continue
|
||||
case paragraphSepState:
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u2029`...)
|
||||
i = j + 3
|
||||
j = j + 3
|
||||
continue
|
||||
}
|
||||
|
||||
j += size
|
||||
}
|
||||
|
||||
@ -540,19 +378,37 @@ func appendString(buf []byte, s string) []byte {
|
||||
return append(buf, `""`...)
|
||||
}
|
||||
buf = append(buf, '"')
|
||||
var escapeIdx int
|
||||
var (
|
||||
i, j int
|
||||
)
|
||||
if valLen >= 8 {
|
||||
if escapeIdx = escapeIndex(s); escapeIdx < 0 {
|
||||
chunks := stringToUint64Slice(s)
|
||||
for _, n := range chunks {
|
||||
// combine masks before checking for the MSB of each byte. We include
|
||||
// `n` in the mask to check whether any of the *input* byte MSBs were
|
||||
// set (i.e. the byte was outside the ASCII range).
|
||||
mask := n | (n - (lsb * 0x20)) |
|
||||
((n ^ (lsb * '"')) - lsb) |
|
||||
((n ^ (lsb * '\\')) - lsb)
|
||||
if (mask & msb) != 0 {
|
||||
j = bits.TrailingZeros64(mask&msb) / 8
|
||||
goto ESCAPE_END
|
||||
}
|
||||
}
|
||||
valLen := len(s)
|
||||
for i := len(chunks) * 8; i < valLen; i++ {
|
||||
if needEscape[s[i]] {
|
||||
j = i
|
||||
goto ESCAPE_END
|
||||
}
|
||||
}
|
||||
return append(append(buf, s...), '"')
|
||||
}
|
||||
}
|
||||
|
||||
i := 0
|
||||
j := escapeIdx
|
||||
ESCAPE_END:
|
||||
for j < valLen {
|
||||
c := s[j]
|
||||
|
||||
if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' {
|
||||
if !needEscape[c] {
|
||||
// fast path: most of the time, printable ascii characters are used
|
||||
j++
|
||||
continue
|
||||
@ -587,7 +443,8 @@ func appendString(buf []byte, s string) []byte {
|
||||
j = j + 1
|
||||
continue
|
||||
|
||||
case '<', '>', '&':
|
||||
case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u00`...)
|
||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||
@ -595,45 +452,7 @@ func appendString(buf []byte, s string) []byte {
|
||||
j = j + 1
|
||||
continue
|
||||
}
|
||||
|
||||
// This encodes bytes < 0x20 except for \t, \n and \r.
|
||||
if c < 0x20 {
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u00`...)
|
||||
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||
i = j + 1
|
||||
j = j + 1
|
||||
continue
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRuneInString(s[j:])
|
||||
|
||||
if r == utf8.RuneError && size == 1 {
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\ufffd`...)
|
||||
i = j + size
|
||||
j = j + size
|
||||
continue
|
||||
}
|
||||
|
||||
switch r {
|
||||
case '\u2028', '\u2029':
|
||||
// U+2028 is LINE SEPARATOR.
|
||||
// U+2029 is PARAGRAPH SEPARATOR.
|
||||
// They are both technically valid characters in JSON strings,
|
||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||
// and can lead to security holes there. It is valid JSON to
|
||||
// escape them, so we do so unconditionally.
|
||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||
buf = append(buf, s[i:j]...)
|
||||
buf = append(buf, `\u202`...)
|
||||
buf = append(buf, hex[r&0xF])
|
||||
i = j + size
|
||||
j = j + size
|
||||
continue
|
||||
}
|
||||
|
||||
j += size
|
||||
j++
|
||||
}
|
||||
|
||||
return append(append(buf, s[i:]...), '"')
|
||||
|
415
vendor/github.com/goccy/go-json/internal/encoder/string_table.go
generated
vendored
Normal file
415
vendor/github.com/goccy/go-json/internal/encoder/string_table.go
generated
vendored
Normal file
@ -0,0 +1,415 @@
|
||||
package encoder
|
||||
|
||||
var needEscapeHTMLNormalizeUTF8 = [256]bool{
|
||||
'"': true,
|
||||
'&': true,
|
||||
'<': true,
|
||||
'>': true,
|
||||
'\\': true,
|
||||
0x00: true,
|
||||
0x01: true,
|
||||
0x02: true,
|
||||
0x03: true,
|
||||
0x04: true,
|
||||
0x05: true,
|
||||
0x06: true,
|
||||
0x07: true,
|
||||
0x08: true,
|
||||
0x09: true,
|
||||
0x0a: true,
|
||||
0x0b: true,
|
||||
0x0c: true,
|
||||
0x0d: true,
|
||||
0x0e: true,
|
||||
0x0f: true,
|
||||
0x10: true,
|
||||
0x11: true,
|
||||
0x12: true,
|
||||
0x13: true,
|
||||
0x14: true,
|
||||
0x15: true,
|
||||
0x16: true,
|
||||
0x17: true,
|
||||
0x18: true,
|
||||
0x19: true,
|
||||
0x1a: true,
|
||||
0x1b: true,
|
||||
0x1c: true,
|
||||
0x1d: true,
|
||||
0x1e: true,
|
||||
0x1f: true,
|
||||
/* 0x20 - 0x7f */
|
||||
0x80: true,
|
||||
0x81: true,
|
||||
0x82: true,
|
||||
0x83: true,
|
||||
0x84: true,
|
||||
0x85: true,
|
||||
0x86: true,
|
||||
0x87: true,
|
||||
0x88: true,
|
||||
0x89: true,
|
||||
0x8a: true,
|
||||
0x8b: true,
|
||||
0x8c: true,
|
||||
0x8d: true,
|
||||
0x8e: true,
|
||||
0x8f: true,
|
||||
0x90: true,
|
||||
0x91: true,
|
||||
0x92: true,
|
||||
0x93: true,
|
||||
0x94: true,
|
||||
0x95: true,
|
||||
0x96: true,
|
||||
0x97: true,
|
||||
0x98: true,
|
||||
0x99: true,
|
||||
0x9a: true,
|
||||
0x9b: true,
|
||||
0x9c: true,
|
||||
0x9d: true,
|
||||
0x9e: true,
|
||||
0x9f: true,
|
||||
0xa0: true,
|
||||
0xa1: true,
|
||||
0xa2: true,
|
||||
0xa3: true,
|
||||
0xa4: true,
|
||||
0xa5: true,
|
||||
0xa6: true,
|
||||
0xa7: true,
|
||||
0xa8: true,
|
||||
0xa9: true,
|
||||
0xaa: true,
|
||||
0xab: true,
|
||||
0xac: true,
|
||||
0xad: true,
|
||||
0xae: true,
|
||||
0xaf: true,
|
||||
0xb0: true,
|
||||
0xb1: true,
|
||||
0xb2: true,
|
||||
0xb3: true,
|
||||
0xb4: true,
|
||||
0xb5: true,
|
||||
0xb6: true,
|
||||
0xb7: true,
|
||||
0xb8: true,
|
||||
0xb9: true,
|
||||
0xba: true,
|
||||
0xbb: true,
|
||||
0xbc: true,
|
||||
0xbd: true,
|
||||
0xbe: true,
|
||||
0xbf: true,
|
||||
0xc0: true,
|
||||
0xc1: true,
|
||||
0xc2: true,
|
||||
0xc3: true,
|
||||
0xc4: true,
|
||||
0xc5: true,
|
||||
0xc6: true,
|
||||
0xc7: true,
|
||||
0xc8: true,
|
||||
0xc9: true,
|
||||
0xca: true,
|
||||
0xcb: true,
|
||||
0xcc: true,
|
||||
0xcd: true,
|
||||
0xce: true,
|
||||
0xcf: true,
|
||||
0xd0: true,
|
||||
0xd1: true,
|
||||
0xd2: true,
|
||||
0xd3: true,
|
||||
0xd4: true,
|
||||
0xd5: true,
|
||||
0xd6: true,
|
||||
0xd7: true,
|
||||
0xd8: true,
|
||||
0xd9: true,
|
||||
0xda: true,
|
||||
0xdb: true,
|
||||
0xdc: true,
|
||||
0xdd: true,
|
||||
0xde: true,
|
||||
0xdf: true,
|
||||
0xe0: true,
|
||||
0xe1: true,
|
||||
0xe2: true,
|
||||
0xe3: true,
|
||||
0xe4: true,
|
||||
0xe5: true,
|
||||
0xe6: true,
|
||||
0xe7: true,
|
||||
0xe8: true,
|
||||
0xe9: true,
|
||||
0xea: true,
|
||||
0xeb: true,
|
||||
0xec: true,
|
||||
0xed: true,
|
||||
0xee: true,
|
||||
0xef: true,
|
||||
0xf0: true,
|
||||
0xf1: true,
|
||||
0xf2: true,
|
||||
0xf3: true,
|
||||
0xf4: true,
|
||||
0xf5: true,
|
||||
0xf6: true,
|
||||
0xf7: true,
|
||||
0xf8: true,
|
||||
0xf9: true,
|
||||
0xfa: true,
|
||||
0xfb: true,
|
||||
0xfc: true,
|
||||
0xfd: true,
|
||||
0xfe: true,
|
||||
0xff: true,
|
||||
}
|
||||
|
||||
var needEscapeNormalizeUTF8 = [256]bool{
|
||||
'"': true,
|
||||
'\\': true,
|
||||
0x00: true,
|
||||
0x01: true,
|
||||
0x02: true,
|
||||
0x03: true,
|
||||
0x04: true,
|
||||
0x05: true,
|
||||
0x06: true,
|
||||
0x07: true,
|
||||
0x08: true,
|
||||
0x09: true,
|
||||
0x0a: true,
|
||||
0x0b: true,
|
||||
0x0c: true,
|
||||
0x0d: true,
|
||||
0x0e: true,
|
||||
0x0f: true,
|
||||
0x10: true,
|
||||
0x11: true,
|
||||
0x12: true,
|
||||
0x13: true,
|
||||
0x14: true,
|
||||
0x15: true,
|
||||
0x16: true,
|
||||
0x17: true,
|
||||
0x18: true,
|
||||
0x19: true,
|
||||
0x1a: true,
|
||||
0x1b: true,
|
||||
0x1c: true,
|
||||
0x1d: true,
|
||||
0x1e: true,
|
||||
0x1f: true,
|
||||
/* 0x20 - 0x7f */
|
||||
0x80: true,
|
||||
0x81: true,
|
||||
0x82: true,
|
||||
0x83: true,
|
||||
0x84: true,
|
||||
0x85: true,
|
||||
0x86: true,
|
||||
0x87: true,
|
||||
0x88: true,
|
||||
0x89: true,
|
||||
0x8a: true,
|
||||
0x8b: true,
|
||||
0x8c: true,
|
||||
0x8d: true,
|
||||
0x8e: true,
|
||||
0x8f: true,
|
||||
0x90: true,
|
||||
0x91: true,
|
||||
0x92: true,
|
||||
0x93: true,
|
||||
0x94: true,
|
||||
0x95: true,
|
||||
0x96: true,
|
||||
0x97: true,
|
||||
0x98: true,
|
||||
0x99: true,
|
||||
0x9a: true,
|
||||
0x9b: true,
|
||||
0x9c: true,
|
||||
0x9d: true,
|
||||
0x9e: true,
|
||||
0x9f: true,
|
||||
0xa0: true,
|
||||
0xa1: true,
|
||||
0xa2: true,
|
||||
0xa3: true,
|
||||
0xa4: true,
|
||||
0xa5: true,
|
||||
0xa6: true,
|
||||
0xa7: true,
|
||||
0xa8: true,
|
||||
0xa9: true,
|
||||
0xaa: true,
|
||||
0xab: true,
|
||||
0xac: true,
|
||||
0xad: true,
|
||||
0xae: true,
|
||||
0xaf: true,
|
||||
0xb0: true,
|
||||
0xb1: true,
|
||||
0xb2: true,
|
||||
0xb3: true,
|
||||
0xb4: true,
|
||||
0xb5: true,
|
||||
0xb6: true,
|
||||
0xb7: true,
|
||||
0xb8: true,
|
||||
0xb9: true,
|
||||
0xba: true,
|
||||
0xbb: true,
|
||||
0xbc: true,
|
||||
0xbd: true,
|
||||
0xbe: true,
|
||||
0xbf: true,
|
||||
0xc0: true,
|
||||
0xc1: true,
|
||||
0xc2: true,
|
||||
0xc3: true,
|
||||
0xc4: true,
|
||||
0xc5: true,
|
||||
0xc6: true,
|
||||
0xc7: true,
|
||||
0xc8: true,
|
||||
0xc9: true,
|
||||
0xca: true,
|
||||
0xcb: true,
|
||||
0xcc: true,
|
||||
0xcd: true,
|
||||
0xce: true,
|
||||
0xcf: true,
|
||||
0xd0: true,
|
||||
0xd1: true,
|
||||
0xd2: true,
|
||||
0xd3: true,
|
||||
0xd4: true,
|
||||
0xd5: true,
|
||||
0xd6: true,
|
||||
0xd7: true,
|
||||
0xd8: true,
|
||||
0xd9: true,
|
||||
0xda: true,
|
||||
0xdb: true,
|
||||
0xdc: true,
|
||||
0xdd: true,
|
||||
0xde: true,
|
||||
0xdf: true,
|
||||
0xe0: true,
|
||||
0xe1: true,
|
||||
0xe2: true,
|
||||
0xe3: true,
|
||||
0xe4: true,
|
||||
0xe5: true,
|
||||
0xe6: true,
|
||||
0xe7: true,
|
||||
0xe8: true,
|
||||
0xe9: true,
|
||||
0xea: true,
|
||||
0xeb: true,
|
||||
0xec: true,
|
||||
0xed: true,
|
||||
0xee: true,
|
||||
0xef: true,
|
||||
0xf0: true,
|
||||
0xf1: true,
|
||||
0xf2: true,
|
||||
0xf3: true,
|
||||
0xf4: true,
|
||||
0xf5: true,
|
||||
0xf6: true,
|
||||
0xf7: true,
|
||||
0xf8: true,
|
||||
0xf9: true,
|
||||
0xfa: true,
|
||||
0xfb: true,
|
||||
0xfc: true,
|
||||
0xfd: true,
|
||||
0xfe: true,
|
||||
0xff: true,
|
||||
}
|
||||
|
||||
var needEscapeHTML = [256]bool{
|
||||
'"': true,
|
||||
'&': true,
|
||||
'<': true,
|
||||
'>': true,
|
||||
'\\': true,
|
||||
0x00: true,
|
||||
0x01: true,
|
||||
0x02: true,
|
||||
0x03: true,
|
||||
0x04: true,
|
||||
0x05: true,
|
||||
0x06: true,
|
||||
0x07: true,
|
||||
0x08: true,
|
||||
0x09: true,
|
||||
0x0a: true,
|
||||
0x0b: true,
|
||||
0x0c: true,
|
||||
0x0d: true,
|
||||
0x0e: true,
|
||||
0x0f: true,
|
||||
0x10: true,
|
||||
0x11: true,
|
||||
0x12: true,
|
||||
0x13: true,
|
||||
0x14: true,
|
||||
0x15: true,
|
||||
0x16: true,
|
||||
0x17: true,
|
||||
0x18: true,
|
||||
0x19: true,
|
||||
0x1a: true,
|
||||
0x1b: true,
|
||||
0x1c: true,
|
||||
0x1d: true,
|
||||
0x1e: true,
|
||||
0x1f: true,
|
||||
/* 0x20 - 0xff */
|
||||
}
|
||||
|
||||
var needEscape = [256]bool{
|
||||
'"': true,
|
||||
'\\': true,
|
||||
0x00: true,
|
||||
0x01: true,
|
||||
0x02: true,
|
||||
0x03: true,
|
||||
0x04: true,
|
||||
0x05: true,
|
||||
0x06: true,
|
||||
0x07: true,
|
||||
0x08: true,
|
||||
0x09: true,
|
||||
0x0a: true,
|
||||
0x0b: true,
|
||||
0x0c: true,
|
||||
0x0d: true,
|
||||
0x0e: true,
|
||||
0x0f: true,
|
||||
0x10: true,
|
||||
0x11: true,
|
||||
0x12: true,
|
||||
0x13: true,
|
||||
0x14: true,
|
||||
0x15: true,
|
||||
0x16: true,
|
||||
0x17: true,
|
||||
0x18: true,
|
||||
0x19: true,
|
||||
0x1a: true,
|
||||
0x1b: true,
|
||||
0x1c: true,
|
||||
0x1d: true,
|
||||
0x1e: true,
|
||||
0x1f: true,
|
||||
/* 0x20 - 0xff */
|
||||
}
|
21
vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go
generated
vendored
21
vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go
generated
vendored
@ -16,16 +16,17 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet)
|
||||
}
|
||||
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("=============[DEBUG]===============")
|
||||
fmt.Println("* [TYPE]")
|
||||
fmt.Println(codeSet.Type)
|
||||
fmt.Printf("\n")
|
||||
fmt.Println("* [ALL OPCODE]")
|
||||
fmt.Println(code.Dump())
|
||||
fmt.Printf("\n")
|
||||
fmt.Println("* [CONTEXT]")
|
||||
fmt.Printf("%+v\n", ctx)
|
||||
fmt.Println("===================================")
|
||||
w := ctx.Option.DebugOut
|
||||
fmt.Fprintln(w, "=============[DEBUG]===============")
|
||||
fmt.Fprintln(w, "* [TYPE]")
|
||||
fmt.Fprintln(w, codeSet.Type)
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintln(w, "* [ALL OPCODE]")
|
||||
fmt.Fprintln(w, code.Dump())
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintln(w, "* [CONTEXT]")
|
||||
fmt.Fprintf(w, "%+v\n", ctx)
|
||||
fmt.Fprintln(w, "===================================")
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
18
vendor/github.com/goccy/go-json/internal/encoder/vm/util.go
generated
vendored
18
vendor/github.com/goccy/go-json/internal/encoder/vm/util.go
generated
vendored
@ -68,7 +68,19 @@ func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
|
||||
return p
|
||||
}
|
||||
|
||||
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||
func ptrToUint64(p uintptr, bitSize uint8) uint64 {
|
||||
switch bitSize {
|
||||
case 8:
|
||||
return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
|
||||
case 16:
|
||||
return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
|
||||
case 32:
|
||||
return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
|
||||
case 64:
|
||||
return **(**uint64)(unsafe.Pointer(&p))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||
@ -114,6 +126,10 @@ func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendNullComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
return append(b, "null,"...)
|
||||
}
|
||||
|
||||
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = ':'
|
||||
|
773
vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go
generated
vendored
773
vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go
generated
vendored
File diff suppressed because it is too large
Load Diff
21
vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go
generated
vendored
21
vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go
generated
vendored
@ -16,16 +16,17 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet)
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("=============[DEBUG]===============")
|
||||
fmt.Println("* [TYPE]")
|
||||
fmt.Println(codeSet.Type)
|
||||
fmt.Printf("\n")
|
||||
fmt.Println("* [ALL OPCODE]")
|
||||
fmt.Println(code.Dump())
|
||||
fmt.Printf("\n")
|
||||
fmt.Println("* [CONTEXT]")
|
||||
fmt.Printf("%+v\n", ctx)
|
||||
fmt.Println("===================================")
|
||||
w := ctx.Option.DebugOut
|
||||
fmt.Fprintln(w, "=============[DEBUG]===============")
|
||||
fmt.Fprintln(w, "* [TYPE]")
|
||||
fmt.Fprintln(w, codeSet.Type)
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintln(w, "* [ALL OPCODE]")
|
||||
fmt.Fprintln(w, code.Dump())
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintln(w, "* [CONTEXT]")
|
||||
fmt.Fprintf(w, "%+v\n", ctx)
|
||||
fmt.Fprintln(w, "===================================")
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
29
vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go
generated
vendored
29
vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go
generated
vendored
@ -61,7 +61,19 @@ func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
|
||||
return p
|
||||
}
|
||||
|
||||
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||
func ptrToUint64(p uintptr, bitSize uint8) uint64 {
|
||||
switch bitSize {
|
||||
case 8:
|
||||
return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
|
||||
case 16:
|
||||
return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
|
||||
case 32:
|
||||
return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
|
||||
case 64:
|
||||
return **(**uint64)(unsafe.Pointer(&p))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||
@ -92,17 +104,17 @@ func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
|
||||
}))
|
||||
}
|
||||
|
||||
func appendInt(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte {
|
||||
func appendInt(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
|
||||
format := ctx.Option.ColorScheme.Int
|
||||
b = append(b, format.Header...)
|
||||
b = encoder.AppendInt(ctx, b, v, code)
|
||||
b = encoder.AppendInt(ctx, b, p, code)
|
||||
return append(b, format.Footer...)
|
||||
}
|
||||
|
||||
func appendUint(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte {
|
||||
func appendUint(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
|
||||
format := ctx.Option.ColorScheme.Uint
|
||||
b = append(b, format.Header...)
|
||||
b = encoder.AppendUint(ctx, b, v, code)
|
||||
b = encoder.AppendUint(ctx, b, p, code)
|
||||
return append(b, format.Footer...)
|
||||
}
|
||||
|
||||
@ -166,6 +178,13 @@ func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte {
|
||||
format := ctx.Option.ColorScheme.Null
|
||||
b = append(b, format.Header...)
|
||||
b = append(b, "null"...)
|
||||
return append(append(b, format.Footer...), ',')
|
||||
}
|
||||
|
||||
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = ':'
|
||||
|
773
vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go
generated
vendored
773
vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go
generated
vendored
File diff suppressed because it is too large
Load Diff
21
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go
generated
vendored
21
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go
generated
vendored
@ -16,16 +16,17 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet)
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("=============[DEBUG]===============")
|
||||
fmt.Println("* [TYPE]")
|
||||
fmt.Println(codeSet.Type)
|
||||
fmt.Printf("\n")
|
||||
fmt.Println("* [ALL OPCODE]")
|
||||
fmt.Println(code.Dump())
|
||||
fmt.Printf("\n")
|
||||
fmt.Println("* [CONTEXT]")
|
||||
fmt.Printf("%+v\n", ctx)
|
||||
fmt.Println("===================================")
|
||||
w := ctx.Option.DebugOut
|
||||
fmt.Fprintln(w, "=============[DEBUG]===============")
|
||||
fmt.Fprintln(w, "* [TYPE]")
|
||||
fmt.Fprintln(w, codeSet.Type)
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintln(w, "* [ALL OPCODE]")
|
||||
fmt.Fprintln(w, code.Dump())
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintln(w, "* [CONTEXT]")
|
||||
fmt.Fprintf(w, "%+v\n", ctx)
|
||||
fmt.Fprintln(w, "===================================")
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
30
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go
generated
vendored
30
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go
generated
vendored
@ -63,7 +63,20 @@ func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
|
||||
return p
|
||||
}
|
||||
|
||||
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||
func ptrToUint64(p uintptr, bitSize uint8) uint64 {
|
||||
switch bitSize {
|
||||
case 8:
|
||||
return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
|
||||
case 16:
|
||||
return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
|
||||
case 32:
|
||||
return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
|
||||
case 64:
|
||||
return **(**uint64)(unsafe.Pointer(&p))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||
@ -94,17 +107,17 @@ func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
|
||||
}))
|
||||
}
|
||||
|
||||
func appendInt(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte {
|
||||
func appendInt(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
|
||||
format := ctx.Option.ColorScheme.Int
|
||||
b = append(b, format.Header...)
|
||||
b = encoder.AppendInt(ctx, b, v, code)
|
||||
b = encoder.AppendInt(ctx, b, p, code)
|
||||
return append(b, format.Footer...)
|
||||
}
|
||||
|
||||
func appendUint(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte {
|
||||
func appendUint(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte {
|
||||
format := ctx.Option.ColorScheme.Uint
|
||||
b = append(b, format.Header...)
|
||||
b = encoder.AppendUint(ctx, b, v, code)
|
||||
b = encoder.AppendUint(ctx, b, p, code)
|
||||
return append(b, format.Footer...)
|
||||
}
|
||||
|
||||
@ -168,6 +181,13 @@ func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
return append(b, ',', '\n')
|
||||
}
|
||||
|
||||
func appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte {
|
||||
format := ctx.Option.ColorScheme.Null
|
||||
b = append(b, format.Header...)
|
||||
b = append(b, "null"...)
|
||||
return append(append(b, format.Footer...), ',', '\n')
|
||||
}
|
||||
|
||||
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
return append(b, ':', ' ')
|
||||
}
|
||||
|
773
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go
generated
vendored
773
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go
generated
vendored
File diff suppressed because it is too large
Load Diff
21
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go
generated
vendored
21
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go
generated
vendored
@ -16,16 +16,17 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet)
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("=============[DEBUG]===============")
|
||||
fmt.Println("* [TYPE]")
|
||||
fmt.Println(codeSet.Type)
|
||||
fmt.Printf("\n")
|
||||
fmt.Println("* [ALL OPCODE]")
|
||||
fmt.Println(code.Dump())
|
||||
fmt.Printf("\n")
|
||||
fmt.Println("* [CONTEXT]")
|
||||
fmt.Printf("%+v\n", ctx)
|
||||
fmt.Println("===================================")
|
||||
w := ctx.Option.DebugOut
|
||||
fmt.Fprintln(w, "=============[DEBUG]===============")
|
||||
fmt.Fprintln(w, "* [TYPE]")
|
||||
fmt.Fprintln(w, codeSet.Type)
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintln(w, "* [ALL OPCODE]")
|
||||
fmt.Fprintln(w, code.Dump())
|
||||
fmt.Fprintf(w, "\n")
|
||||
fmt.Fprintln(w, "* [CONTEXT]")
|
||||
fmt.Fprintf(w, "%+v\n", ctx)
|
||||
fmt.Fprintln(w, "===================================")
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
18
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go
generated
vendored
18
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go
generated
vendored
@ -70,7 +70,19 @@ func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
|
||||
return p
|
||||
}
|
||||
|
||||
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||
func ptrToUint64(p uintptr, bitSize uint8) uint64 {
|
||||
switch bitSize {
|
||||
case 8:
|
||||
return (uint64)(**(**uint8)(unsafe.Pointer(&p)))
|
||||
case 16:
|
||||
return (uint64)(**(**uint16)(unsafe.Pointer(&p)))
|
||||
case 32:
|
||||
return (uint64)(**(**uint32)(unsafe.Pointer(&p)))
|
||||
case 64:
|
||||
return **(**uint64)(unsafe.Pointer(&p))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||
@ -116,6 +128,10 @@ func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
return append(b, ',', '\n')
|
||||
}
|
||||
|
||||
func appendNullComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
return append(b, "null,\n"...)
|
||||
}
|
||||
|
||||
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||
return append(b, ':', ' ')
|
||||
}
|
||||
|
773
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go
generated
vendored
773
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go
generated
vendored
File diff suppressed because it is too large
Load Diff
6
vendor/github.com/goccy/go-json/internal/runtime/struct_field.go
generated
vendored
6
vendor/github.com/goccy/go-json/internal/runtime/struct_field.go
generated
vendored
@ -13,7 +13,11 @@ func getTag(field reflect.StructField) string {
|
||||
func IsIgnoredStructField(field reflect.StructField) bool {
|
||||
if field.PkgPath != "" {
|
||||
if field.Anonymous {
|
||||
if !(field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct) && field.Type.Kind() != reflect.Struct {
|
||||
t := field.Type
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
|
5
vendor/github.com/goccy/go-json/json.go
generated
vendored
5
vendor/github.com/goccy/go-json/json.go
generated
vendored
@ -364,3 +364,8 @@ func Valid(data []byte) bool {
|
||||
}
|
||||
return decoder.InputOffset() >= int64(len(data))
|
||||
}
|
||||
|
||||
func init() {
|
||||
encoder.Marshal = Marshal
|
||||
encoder.Unmarshal = Unmarshal
|
||||
}
|
||||
|
26
vendor/github.com/goccy/go-json/option.go
generated
vendored
26
vendor/github.com/goccy/go-json/option.go
generated
vendored
@ -1,6 +1,8 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/goccy/go-json/internal/decoder"
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
@ -15,6 +17,23 @@ func UnorderedMap() EncodeOptionFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// DisableHTMLEscape disables escaping of HTML characters ( '&', '<', '>' ) when encoding string.
|
||||
func DisableHTMLEscape() EncodeOptionFunc {
|
||||
return func(opt *EncodeOption) {
|
||||
opt.Flag &= ^encoder.HTMLEscapeOption
|
||||
}
|
||||
}
|
||||
|
||||
// DisableNormalizeUTF8
|
||||
// By default, when encoding string, UTF8 characters in the range of 0x80 - 0xFF are processed by applying \ufffd for invalid code and escaping for \u2028 and \u2029.
|
||||
// This option disables this behaviour. You can expect faster speeds by applying this option, but be careful.
|
||||
// encoding/json implements here: https://github.com/golang/go/blob/6178d25fc0b28724b1b5aec2b1b74fc06d9294c7/src/encoding/json/encode.go#L1067-L1093.
|
||||
func DisableNormalizeUTF8() EncodeOptionFunc {
|
||||
return func(opt *EncodeOption) {
|
||||
opt.Flag &= ^encoder.NormalizeUTF8Option
|
||||
}
|
||||
}
|
||||
|
||||
// Debug outputs debug information when panic occurs during encoding.
|
||||
func Debug() EncodeOptionFunc {
|
||||
return func(opt *EncodeOption) {
|
||||
@ -22,6 +41,13 @@ func Debug() EncodeOptionFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// DebugWith sets the destination to write debug messages.
|
||||
func DebugWith(w io.Writer) EncodeOptionFunc {
|
||||
return func(opt *EncodeOption) {
|
||||
opt.DebugOut = w
|
||||
}
|
||||
}
|
||||
|
||||
// Colorize add an identifier for coloring to the string of the encoded result.
|
||||
func Colorize(scheme *ColorScheme) EncodeOptionFunc {
|
||||
return func(opt *EncodeOption) {
|
||||
|
47
vendor/github.com/goccy/go-json/query.go
generated
vendored
Normal file
47
vendor/github.com/goccy/go-json/query.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
)
|
||||
|
||||
type (
|
||||
// FieldQuery you can dynamically filter the fields in the structure by creating a FieldQuery,
|
||||
// adding it to context.Context using SetFieldQueryToContext and then passing it to MarshalContext.
|
||||
// This is a type-safe operation, so it is faster than filtering using map[string]interface{}.
|
||||
FieldQuery = encoder.FieldQuery
|
||||
FieldQueryString = encoder.FieldQueryString
|
||||
)
|
||||
|
||||
var (
|
||||
// FieldQueryFromContext get current FieldQuery from context.Context.
|
||||
FieldQueryFromContext = encoder.FieldQueryFromContext
|
||||
// SetFieldQueryToContext set current FieldQuery to context.Context.
|
||||
SetFieldQueryToContext = encoder.SetFieldQueryToContext
|
||||
)
|
||||
|
||||
// BuildFieldQuery builds FieldQuery by fieldName or sub field query.
|
||||
// First, specify the field name that you want to keep in structure type.
|
||||
// If the field you want to keep is a structure type, by creating a sub field query using BuildSubFieldQuery,
|
||||
// you can select the fields you want to keep in the structure.
|
||||
// This description can be written recursively.
|
||||
func BuildFieldQuery(fields ...FieldQueryString) (*FieldQuery, error) {
|
||||
query, err := Marshal(fields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FieldQueryString(query).Build()
|
||||
}
|
||||
|
||||
// BuildSubFieldQuery builds sub field query.
|
||||
func BuildSubFieldQuery(name string) *SubFieldQuery {
|
||||
return &SubFieldQuery{name: name}
|
||||
}
|
||||
|
||||
type SubFieldQuery struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (q *SubFieldQuery) Fields(fields ...FieldQueryString) FieldQueryString {
|
||||
query, _ := Marshal(map[string][]FieldQueryString{q.name: fields})
|
||||
return FieldQueryString(query)
|
||||
}
|
2
vendor/github.com/json-iterator/go/README.md
generated
vendored
2
vendor/github.com/json-iterator/go/README.md
generated
vendored
@ -8,8 +8,6 @@
|
||||
|
||||
A high-performance 100% compatible drop-in replacement of "encoding/json"
|
||||
|
||||
You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go)
|
||||
|
||||
# Benchmark
|
||||
|
||||
![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png)
|
||||
|
148
vendor/github.com/labstack/echo/v4/CHANGELOG.md
generated
vendored
148
vendor/github.com/labstack/echo/v4/CHANGELOG.md
generated
vendored
@ -1,5 +1,153 @@
|
||||
# Changelog
|
||||
|
||||
## v4.9.1 - 2022-10-12
|
||||
|
||||
**Fixes**
|
||||
|
||||
* Fix logger panicing (when template is set to empty) by bumping dependency version [#2295](https://github.com/labstack/echo/issues/2295)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Improve CORS documentation [#2272](https://github.com/labstack/echo/pull/2272)
|
||||
* Update readme about supported Go versions [#2291](https://github.com/labstack/echo/pull/2291)
|
||||
* Tests: improve error handling on closing body [#2254](https://github.com/labstack/echo/pull/2254)
|
||||
* Tests: refactor some of the assertions in tests [#2275](https://github.com/labstack/echo/pull/2275)
|
||||
* Tests: refactor assertions [#2301](https://github.com/labstack/echo/pull/2301)
|
||||
|
||||
## v4.9.0 - 2022-09-04
|
||||
|
||||
**Security**
|
||||
|
||||
* Fix open redirect vulnerability in handlers serving static directories (e.Static, e.StaticFs, echo.StaticDirectoryHandler) [#2260](https://github.com/labstack/echo/pull/2260)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Allow configuring ErrorHandler in CSRF middleware [#2257](https://github.com/labstack/echo/pull/2257)
|
||||
* Replace HTTP method constants in tests with stdlib constants [#2247](https://github.com/labstack/echo/pull/2247)
|
||||
|
||||
|
||||
## v4.8.0 - 2022-08-10
|
||||
|
||||
**Most notable things**
|
||||
|
||||
You can now add any arbitrary HTTP method type as a route [#2237](https://github.com/labstack/echo/pull/2237)
|
||||
```go
|
||||
e.Add("COPY", "/*", func(c echo.Context) error
|
||||
return c.String(http.StatusOK, "OK COPY")
|
||||
})
|
||||
```
|
||||
|
||||
You can add custom 404 handler for specific paths [#2217](https://github.com/labstack/echo/pull/2217)
|
||||
```go
|
||||
e.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })
|
||||
|
||||
g := e.Group("/images")
|
||||
g.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })
|
||||
```
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Add new value binding methods (UnixTimeMilli,TextUnmarshaler,JSONUnmarshaler) to Valuebinder [#2127](https://github.com/labstack/echo/pull/2127)
|
||||
* Refactor: body_limit middleware unit test [#2145](https://github.com/labstack/echo/pull/2145)
|
||||
* Refactor: Timeout mw: rework how test waits for timeout. [#2187](https://github.com/labstack/echo/pull/2187)
|
||||
* BasicAuth middleware returns 500 InternalServerError on invalid base64 strings but should return 400 [#2191](https://github.com/labstack/echo/pull/2191)
|
||||
* Refactor: duplicated findStaticChild process at findChildWithLabel [#2176](https://github.com/labstack/echo/pull/2176)
|
||||
* Allow different param names in different methods with same path scheme [#2209](https://github.com/labstack/echo/pull/2209)
|
||||
* Add support for registering handlers for different 404 routes [#2217](https://github.com/labstack/echo/pull/2217)
|
||||
* Middlewares should use errors.As() instead of type assertion on HTTPError [#2227](https://github.com/labstack/echo/pull/2227)
|
||||
* Allow arbitrary HTTP method types to be added as routes [#2237](https://github.com/labstack/echo/pull/2237)
|
||||
|
||||
## v4.7.2 - 2022-03-16
|
||||
|
||||
**Fixes**
|
||||
|
||||
* Fix nil pointer exception when calling Start again after address binding error [#2131](https://github.com/labstack/echo/pull/2131)
|
||||
* Fix CSRF middleware not being able to extract token from multipart/form-data form [#2136](https://github.com/labstack/echo/pull/2136)
|
||||
* Fix Timeout middleware write race [#2126](https://github.com/labstack/echo/pull/2126)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Recover middleware should not log panic for aborted handler [#2134](https://github.com/labstack/echo/pull/2134)
|
||||
|
||||
|
||||
## v4.7.1 - 2022-03-13
|
||||
|
||||
**Fixes**
|
||||
|
||||
* Fix `e.Static`, `.File()`, `c.Attachment()` being picky with paths starting with `./`, `../` and `/` after 4.7.0 introduced echo.Filesystem support (Go1.16+) [#2123](https://github.com/labstack/echo/pull/2123)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Remove some unused code [#2116](https://github.com/labstack/echo/pull/2116)
|
||||
|
||||
|
||||
## v4.7.0 - 2022-03-01
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Add JWT, KeyAuth, CSRF multivalue extractors [#2060](https://github.com/labstack/echo/pull/2060)
|
||||
* Add LogErrorFunc to recover middleware [#2072](https://github.com/labstack/echo/pull/2072)
|
||||
* Add support for HEAD method query params binding [#2027](https://github.com/labstack/echo/pull/2027)
|
||||
* Improve filesystem support with echo.FileFS, echo.StaticFS, group.FileFS, group.StaticFS [#2064](https://github.com/labstack/echo/pull/2064)
|
||||
|
||||
**Fixes**
|
||||
|
||||
* Fix X-Real-IP bug, improve tests [#2007](https://github.com/labstack/echo/pull/2007)
|
||||
* Minor syntax fixes [#1994](https://github.com/labstack/echo/pull/1994), [#2102](https://github.com/labstack/echo/pull/2102), [#2102](https://github.com/labstack/echo/pull/2102)
|
||||
|
||||
**General**
|
||||
|
||||
* Add cache-control and connection headers [#2103](https://github.com/labstack/echo/pull/2103)
|
||||
* Add Retry-After header constant [#2078](https://github.com/labstack/echo/pull/2078)
|
||||
* Upgrade `go` directive in `go.mod` to 1.17 [#2049](https://github.com/labstack/echo/pull/2049)
|
||||
* Add Pagoda [#2077](https://github.com/labstack/echo/pull/2077) and Souin [#2069](https://github.com/labstack/echo/pull/2069) to 3rd-party middlewares in README
|
||||
|
||||
## v4.6.3 - 2022-01-10
|
||||
|
||||
**Fixes**
|
||||
|
||||
* Fixed Echo version number in greeting message which was not incremented to `4.6.2` [#2066](https://github.com/labstack/echo/issues/2066)
|
||||
|
||||
|
||||
## v4.6.2 - 2022-01-08
|
||||
|
||||
**Fixes**
|
||||
|
||||
* Fixed route containing escaped colon should be matchable but is not matched to request path [#2047](https://github.com/labstack/echo/pull/2047)
|
||||
* Fixed a problem that returned wrong content-encoding when the gzip compressed content was empty. [#1921](https://github.com/labstack/echo/pull/1921)
|
||||
* Update (test) dependencies [#2021](https://github.com/labstack/echo/pull/2021)
|
||||
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Add support for configurable target header for the request_id middleware [#2040](https://github.com/labstack/echo/pull/2040)
|
||||
* Change decompress middleware to use stream decompression instead of buffering [#2018](https://github.com/labstack/echo/pull/2018)
|
||||
* Documentation updates
|
||||
|
||||
|
||||
## v4.6.1 - 2021-09-26
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Add start time to request logger middleware values [#1991](https://github.com/labstack/echo/pull/1991)
|
||||
|
||||
## v4.6.0 - 2021-09-20
|
||||
|
||||
Introduced a new [request logger](https://github.com/labstack/echo/blob/master/middleware/request_logger.go) middleware
|
||||
to help with cases when you want to use some other logging library in your application.
|
||||
|
||||
**Fixes**
|
||||
|
||||
* fix timeout middleware warning: superfluous response.WriteHeader [#1905](https://github.com/labstack/echo/issues/1905)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Add Cookie to KeyAuth middleware's KeyLookup [#1929](https://github.com/labstack/echo/pull/1929)
|
||||
* JWT middleware should ignore case of auth scheme in request header [#1951](https://github.com/labstack/echo/pull/1951)
|
||||
* Refactor default error handler to return first if response is already committed [#1956](https://github.com/labstack/echo/pull/1956)
|
||||
* Added request logger middleware which helps to use custom logger library for logging requests. [#1980](https://github.com/labstack/echo/pull/1980)
|
||||
* Allow escaping of colon in route path so Google Cloud API "custom methods" could be implemented [#1988](https://github.com/labstack/echo/pull/1988)
|
||||
|
||||
## v4.5.0 - 2021-08-01
|
||||
|
||||
**Important notes**
|
||||
|
6
vendor/github.com/labstack/echo/v4/Makefile
generated
vendored
6
vendor/github.com/labstack/echo/v4/Makefile
generated
vendored
@ -9,7 +9,7 @@ tag:
|
||||
check: lint vet race ## Check project
|
||||
|
||||
init:
|
||||
@go get -u golang.org/x/lint/golint
|
||||
@go install golang.org/x/lint/golint@latest
|
||||
|
||||
lint: ## Lint the files
|
||||
@golint -set_exit_status ${PKG_LIST}
|
||||
@ -29,6 +29,6 @@ benchmark: ## Run benchmarks
|
||||
help: ## Display this help screen
|
||||
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
goversion ?= "1.15"
|
||||
test_version: ## Run tests inside Docker with given version (defaults to 1.15 oldest supported). Example: make test_version goversion=1.15
|
||||
goversion ?= "1.16"
|
||||
test_version: ## Run tests inside Docker with given version (defaults to 1.15 oldest supported). Example: make test_version goversion=1.16
|
||||
@docker run --rm -it -v $(shell pwd):/project golang:$(goversion) /bin/sh -c "cd /project && make init check"
|
||||
|
31
vendor/github.com/labstack/echo/v4/README.md
generated
vendored
31
vendor/github.com/labstack/echo/v4/README.md
generated
vendored
@ -5,19 +5,17 @@
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo)
|
||||
[![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo)
|
||||
[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo)
|
||||
[![Join the chat at https://gitter.im/labstack/echo](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/labstack/echo)
|
||||
[![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://github.com/labstack/echo/discussions)
|
||||
[![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack)
|
||||
[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
|
||||
|
||||
## Supported Go versions
|
||||
|
||||
Latest version of Echo supports last four Go major [releases](https://go.dev/doc/devel/release) and might work with older versions.
|
||||
|
||||
As of version 4.0.0, Echo is available as a [Go module](https://github.com/golang/go/wiki/Modules).
|
||||
Therefore a Go version capable of understanding /vN suffixed imports is required:
|
||||
|
||||
- 1.9.7+
|
||||
- 1.10.3+
|
||||
- 1.14+
|
||||
|
||||
Any of these versions will allow you to import Echo as `github.com/labstack/echo/v4` which is the recommended
|
||||
way of using Echo going forward.
|
||||
@ -66,9 +64,9 @@ go get github.com/labstack/echo/v4
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -92,10 +90,24 @@ func hello(c echo.Context) error {
|
||||
}
|
||||
```
|
||||
|
||||
# Third-party middlewares
|
||||
|
||||
| Repository | Description |
|
||||
|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [github.com/labstack/echo-contrib](https://github.com/labstack/echo-contrib) | (by Echo team) [casbin](https://github.com/casbin/casbin), [gorilla/sessions](https://github.com/gorilla/sessions), [jaegertracing](github.com/uber/jaeger-client-go), [prometheus](https://github.com/prometheus/client_golang/), [pprof](https://pkg.go.dev/net/http/pprof), [zipkin](https://github.com/openzipkin/zipkin-go) middlewares |
|
||||
| [deepmap/oapi-codegen](https://github.com/deepmap/oapi-codegen) | Automatically generate RESTful API documentation with [OpenAPI](https://swagger.io/specification/) Client and Server Code Generator |
|
||||
| [github.com/swaggo/echo-swagger](https://github.com/swaggo/echo-swagger) | Automatically generate RESTful API documentation with [Swagger](https://swagger.io/) 2.0. |
|
||||
| [github.com/ziflex/lecho](https://github.com/ziflex/lecho) | [Zerolog](https://github.com/rs/zerolog) logging library wrapper for Echo logger interface. |
|
||||
| [github.com/brpaz/echozap](https://github.com/brpaz/echozap) | Uber´s [Zap](https://github.com/uber-go/zap) logging library wrapper for Echo logger interface. |
|
||||
| [github.com/darkweak/souin/plugins/echo](https://github.com/darkweak/souin/tree/master/plugins/echo) | HTTP cache system based on [Souin](https://github.com/darkweak/souin) to automatically get your endpoints cached. It supports some distributed and non-distributed storage systems depending your needs. |
|
||||
| [github.com/mikestefanello/pagoda](https://github.com/mikestefanello/pagoda) | Rapid, easy full-stack web development starter kit built with Echo. |
|
||||
| [github.com/go-woo/protoc-gen-echo](https://github.com/go-woo/protoc-gen-echo) | ProtoBuf generate Echo server side code |
|
||||
|
||||
Please send a PR to add your own library here.
|
||||
|
||||
## Help
|
||||
|
||||
- [Forum](https://github.com/labstack/echo/discussions)
|
||||
- [Chat](https://gitter.im/labstack/echo)
|
||||
|
||||
## Contribute
|
||||
|
||||
@ -114,8 +126,11 @@ func hello(c echo.Context) error {
|
||||
|
||||
## Credits
|
||||
|
||||
- [Vishal Rana](https://github.com/vishr) - Author
|
||||
- [Nitin Rana](https://github.com/nr17) - Consultant
|
||||
- [Vishal Rana](https://github.com/vishr) (Author)
|
||||
- [Nitin Rana](https://github.com/nr17) (Consultant)
|
||||
- [Roland Lammel](https://github.com/lammel) (Maintainer)
|
||||
- [Martti T.](https://github.com/aldas) (Maintainer)
|
||||
- [Pablo Andres Fuente](https://github.com/pafuent) (Maintainer)
|
||||
- [Contributors](https://github.com/labstack/echo/graphs/contributors)
|
||||
|
||||
## License
|
||||
|
10
vendor/github.com/labstack/echo/v4/bind.go
generated
vendored
10
vendor/github.com/labstack/echo/v4/bind.go
generated
vendored
@ -111,11 +111,11 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
|
||||
if err := b.BindPathParams(c, i); err != nil {
|
||||
return err
|
||||
}
|
||||
// Issue #1670 - Query params are binded only for GET/DELETE and NOT for usual request with body (POST/PUT/PATCH)
|
||||
// Reasoning here is that parameters in query and bind destination struct could have UNEXPECTED matches and results due that.
|
||||
// i.e. is `&id=1&lang=en` from URL same as `{"id":100,"lang":"de"}` request body and which one should have priority when binding.
|
||||
// This HTTP method check restores pre v4.1.11 behavior and avoids different problems when query is mixed with body
|
||||
if c.Request().Method == http.MethodGet || c.Request().Method == http.MethodDelete {
|
||||
// Only bind query parameters for GET/DELETE/HEAD to avoid unexpected behavior with destination struct binding from body.
|
||||
// For example a request URL `&id=1&lang=en` with body `{"id":100,"lang":"de"}` would lead to precedence issues.
|
||||
// The HTTP method check restores pre-v4.1.11 behavior to avoid these problems (see issue #1670)
|
||||
method := c.Request().Method
|
||||
if method == http.MethodGet || method == http.MethodDelete || method == http.MethodHead {
|
||||
if err = b.BindQueryParams(c, i); err != nil {
|
||||
return err
|
||||
}
|
||||
|
197
vendor/github.com/labstack/echo/v4/binder.go
generated
vendored
197
vendor/github.com/labstack/echo/v4/binder.go
generated
vendored
@ -1,6 +1,8 @@
|
||||
package echo
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@ -52,8 +54,11 @@ import (
|
||||
* time
|
||||
* duration
|
||||
* BindUnmarshaler() interface
|
||||
* TextUnmarshaler() interface
|
||||
* JSONUnmarshaler() interface
|
||||
* UnixTime() - converts unix time (integer) to time.Time
|
||||
* UnixTimeNano() - converts unix time with nano second precision (integer) to time.Time
|
||||
* UnixTimeMilli() - converts unix time with millisecond precision (integer) to time.Time
|
||||
* UnixTimeNano() - converts unix time with nanosecond precision (integer) to time.Time
|
||||
* CustomFunc() - callback function for your custom conversion logic. Signature `func(values []string) []error`
|
||||
*/
|
||||
|
||||
@ -204,7 +209,7 @@ func (b *ValueBinder) CustomFunc(sourceParam string, customFunc func(values []st
|
||||
return b.customFunc(sourceParam, customFunc, false)
|
||||
}
|
||||
|
||||
// MustCustomFunc requires parameter values to exist to be bind with Func. Returns error when value does not exist.
|
||||
// MustCustomFunc requires parameter values to exist to bind with Func. Returns error when value does not exist.
|
||||
func (b *ValueBinder) MustCustomFunc(sourceParam string, customFunc func(values []string) []error) *ValueBinder {
|
||||
return b.customFunc(sourceParam, customFunc, true)
|
||||
}
|
||||
@ -241,7 +246,7 @@ func (b *ValueBinder) String(sourceParam string, dest *string) *ValueBinder {
|
||||
return b
|
||||
}
|
||||
|
||||
// MustString requires parameter value to exist to be bind to string variable. Returns error when value does not exist
|
||||
// MustString requires parameter value to exist to bind to string variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustString(sourceParam string, dest *string) *ValueBinder {
|
||||
if b.failFast && b.errors != nil {
|
||||
return b
|
||||
@ -270,7 +275,7 @@ func (b *ValueBinder) Strings(sourceParam string, dest *[]string) *ValueBinder {
|
||||
return b
|
||||
}
|
||||
|
||||
// MustStrings requires parameter values to exist to be bind to slice of string variables. Returns error when value does not exist
|
||||
// MustStrings requires parameter values to exist to bind to slice of string variables. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustStrings(sourceParam string, dest *[]string) *ValueBinder {
|
||||
if b.failFast && b.errors != nil {
|
||||
return b
|
||||
@ -302,7 +307,7 @@ func (b *ValueBinder) BindUnmarshaler(sourceParam string, dest BindUnmarshaler)
|
||||
return b
|
||||
}
|
||||
|
||||
// MustBindUnmarshaler requires parameter value to exist to be bind to destination implementing BindUnmarshaler interface.
|
||||
// MustBindUnmarshaler requires parameter value to exist to bind to destination implementing BindUnmarshaler interface.
|
||||
// Returns error when value does not exist
|
||||
func (b *ValueBinder) MustBindUnmarshaler(sourceParam string, dest BindUnmarshaler) *ValueBinder {
|
||||
if b.failFast && b.errors != nil {
|
||||
@ -321,13 +326,85 @@ func (b *ValueBinder) MustBindUnmarshaler(sourceParam string, dest BindUnmarshal
|
||||
return b
|
||||
}
|
||||
|
||||
// JSONUnmarshaler binds parameter to destination implementing json.Unmarshaler interface
|
||||
func (b *ValueBinder) JSONUnmarshaler(sourceParam string, dest json.Unmarshaler) *ValueBinder {
|
||||
if b.failFast && b.errors != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
tmp := b.ValueFunc(sourceParam)
|
||||
if tmp == "" {
|
||||
return b
|
||||
}
|
||||
|
||||
if err := dest.UnmarshalJSON([]byte(tmp)); err != nil {
|
||||
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to json.Unmarshaler interface", err))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// MustJSONUnmarshaler requires parameter value to exist to bind to destination implementing json.Unmarshaler interface.
|
||||
// Returns error when value does not exist
|
||||
func (b *ValueBinder) MustJSONUnmarshaler(sourceParam string, dest json.Unmarshaler) *ValueBinder {
|
||||
if b.failFast && b.errors != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
tmp := b.ValueFunc(sourceParam)
|
||||
if tmp == "" {
|
||||
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "required field value is empty", nil))
|
||||
return b
|
||||
}
|
||||
|
||||
if err := dest.UnmarshalJSON([]byte(tmp)); err != nil {
|
||||
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to json.Unmarshaler interface", err))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// TextUnmarshaler binds parameter to destination implementing encoding.TextUnmarshaler interface
|
||||
func (b *ValueBinder) TextUnmarshaler(sourceParam string, dest encoding.TextUnmarshaler) *ValueBinder {
|
||||
if b.failFast && b.errors != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
tmp := b.ValueFunc(sourceParam)
|
||||
if tmp == "" {
|
||||
return b
|
||||
}
|
||||
|
||||
if err := dest.UnmarshalText([]byte(tmp)); err != nil {
|
||||
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to encoding.TextUnmarshaler interface", err))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// MustTextUnmarshaler requires parameter value to exist to bind to destination implementing encoding.TextUnmarshaler interface.
|
||||
// Returns error when value does not exist
|
||||
func (b *ValueBinder) MustTextUnmarshaler(sourceParam string, dest encoding.TextUnmarshaler) *ValueBinder {
|
||||
if b.failFast && b.errors != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
tmp := b.ValueFunc(sourceParam)
|
||||
if tmp == "" {
|
||||
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "required field value is empty", nil))
|
||||
return b
|
||||
}
|
||||
|
||||
if err := dest.UnmarshalText([]byte(tmp)); err != nil {
|
||||
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to encoding.TextUnmarshaler interface", err))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// BindWithDelimiter binds parameter to destination by suitable conversion function.
|
||||
// Delimiter is used before conversion to split parameter value to separate values
|
||||
func (b *ValueBinder) BindWithDelimiter(sourceParam string, dest interface{}, delimiter string) *ValueBinder {
|
||||
return b.bindWithDelimiter(sourceParam, dest, delimiter, false)
|
||||
}
|
||||
|
||||
// MustBindWithDelimiter requires parameter value to exist to be bind destination by suitable conversion function.
|
||||
// MustBindWithDelimiter requires parameter value to exist to bind destination by suitable conversion function.
|
||||
// Delimiter is used before conversion to split parameter value to separate values
|
||||
func (b *ValueBinder) MustBindWithDelimiter(sourceParam string, dest interface{}, delimiter string) *ValueBinder {
|
||||
return b.bindWithDelimiter(sourceParam, dest, delimiter, true)
|
||||
@ -376,7 +453,7 @@ func (b *ValueBinder) Int64(sourceParam string, dest *int64) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 64, false)
|
||||
}
|
||||
|
||||
// MustInt64 requires parameter value to exist to be bind to int64 variable. Returns error when value does not exist
|
||||
// MustInt64 requires parameter value to exist to bind to int64 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt64(sourceParam string, dest *int64) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 64, true)
|
||||
}
|
||||
@ -386,7 +463,7 @@ func (b *ValueBinder) Int32(sourceParam string, dest *int32) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 32, false)
|
||||
}
|
||||
|
||||
// MustInt32 requires parameter value to exist to be bind to int32 variable. Returns error when value does not exist
|
||||
// MustInt32 requires parameter value to exist to bind to int32 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt32(sourceParam string, dest *int32) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 32, true)
|
||||
}
|
||||
@ -396,7 +473,7 @@ func (b *ValueBinder) Int16(sourceParam string, dest *int16) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 16, false)
|
||||
}
|
||||
|
||||
// MustInt16 requires parameter value to exist to be bind to int16 variable. Returns error when value does not exist
|
||||
// MustInt16 requires parameter value to exist to bind to int16 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt16(sourceParam string, dest *int16) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 16, true)
|
||||
}
|
||||
@ -406,7 +483,7 @@ func (b *ValueBinder) Int8(sourceParam string, dest *int8) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 8, false)
|
||||
}
|
||||
|
||||
// MustInt8 requires parameter value to exist to be bind to int8 variable. Returns error when value does not exist
|
||||
// MustInt8 requires parameter value to exist to bind to int8 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt8(sourceParam string, dest *int8) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 8, true)
|
||||
}
|
||||
@ -416,7 +493,7 @@ func (b *ValueBinder) Int(sourceParam string, dest *int) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 0, false)
|
||||
}
|
||||
|
||||
// MustInt requires parameter value to exist to be bind to int variable. Returns error when value does not exist
|
||||
// MustInt requires parameter value to exist to bind to int variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt(sourceParam string, dest *int) *ValueBinder {
|
||||
return b.intValue(sourceParam, dest, 0, true)
|
||||
}
|
||||
@ -544,7 +621,7 @@ func (b *ValueBinder) Int64s(sourceParam string, dest *[]int64) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustInt64s requires parameter value to exist to be bind to int64 slice variable. Returns error when value does not exist
|
||||
// MustInt64s requires parameter value to exist to bind to int64 slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt64s(sourceParam string, dest *[]int64) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -554,7 +631,7 @@ func (b *ValueBinder) Int32s(sourceParam string, dest *[]int32) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustInt32s requires parameter value to exist to be bind to int32 slice variable. Returns error when value does not exist
|
||||
// MustInt32s requires parameter value to exist to bind to int32 slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt32s(sourceParam string, dest *[]int32) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -564,7 +641,7 @@ func (b *ValueBinder) Int16s(sourceParam string, dest *[]int16) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustInt16s requires parameter value to exist to be bind to int16 slice variable. Returns error when value does not exist
|
||||
// MustInt16s requires parameter value to exist to bind to int16 slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt16s(sourceParam string, dest *[]int16) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -574,7 +651,7 @@ func (b *ValueBinder) Int8s(sourceParam string, dest *[]int8) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustInt8s requires parameter value to exist to be bind to int8 slice variable. Returns error when value does not exist
|
||||
// MustInt8s requires parameter value to exist to bind to int8 slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInt8s(sourceParam string, dest *[]int8) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -584,7 +661,7 @@ func (b *ValueBinder) Ints(sourceParam string, dest *[]int) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustInts requires parameter value to exist to be bind to int slice variable. Returns error when value does not exist
|
||||
// MustInts requires parameter value to exist to bind to int slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustInts(sourceParam string, dest *[]int) *ValueBinder {
|
||||
return b.intsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -594,7 +671,7 @@ func (b *ValueBinder) Uint64(sourceParam string, dest *uint64) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 64, false)
|
||||
}
|
||||
|
||||
// MustUint64 requires parameter value to exist to be bind to uint64 variable. Returns error when value does not exist
|
||||
// MustUint64 requires parameter value to exist to bind to uint64 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint64(sourceParam string, dest *uint64) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 64, true)
|
||||
}
|
||||
@ -604,7 +681,7 @@ func (b *ValueBinder) Uint32(sourceParam string, dest *uint32) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 32, false)
|
||||
}
|
||||
|
||||
// MustUint32 requires parameter value to exist to be bind to uint32 variable. Returns error when value does not exist
|
||||
// MustUint32 requires parameter value to exist to bind to uint32 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint32(sourceParam string, dest *uint32) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 32, true)
|
||||
}
|
||||
@ -614,7 +691,7 @@ func (b *ValueBinder) Uint16(sourceParam string, dest *uint16) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 16, false)
|
||||
}
|
||||
|
||||
// MustUint16 requires parameter value to exist to be bind to uint16 variable. Returns error when value does not exist
|
||||
// MustUint16 requires parameter value to exist to bind to uint16 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint16(sourceParam string, dest *uint16) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 16, true)
|
||||
}
|
||||
@ -624,7 +701,7 @@ func (b *ValueBinder) Uint8(sourceParam string, dest *uint8) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 8, false)
|
||||
}
|
||||
|
||||
// MustUint8 requires parameter value to exist to be bind to uint8 variable. Returns error when value does not exist
|
||||
// MustUint8 requires parameter value to exist to bind to uint8 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint8(sourceParam string, dest *uint8) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 8, true)
|
||||
}
|
||||
@ -634,7 +711,7 @@ func (b *ValueBinder) Byte(sourceParam string, dest *byte) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 8, false)
|
||||
}
|
||||
|
||||
// MustByte requires parameter value to exist to be bind to byte variable. Returns error when value does not exist
|
||||
// MustByte requires parameter value to exist to bind to byte variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustByte(sourceParam string, dest *byte) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 8, true)
|
||||
}
|
||||
@ -644,7 +721,7 @@ func (b *ValueBinder) Uint(sourceParam string, dest *uint) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 0, false)
|
||||
}
|
||||
|
||||
// MustUint requires parameter value to exist to be bind to uint variable. Returns error when value does not exist
|
||||
// MustUint requires parameter value to exist to bind to uint variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint(sourceParam string, dest *uint) *ValueBinder {
|
||||
return b.uintValue(sourceParam, dest, 0, true)
|
||||
}
|
||||
@ -772,7 +849,7 @@ func (b *ValueBinder) Uint64s(sourceParam string, dest *[]uint64) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustUint64s requires parameter value to exist to be bind to uint64 slice variable. Returns error when value does not exist
|
||||
// MustUint64s requires parameter value to exist to bind to uint64 slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint64s(sourceParam string, dest *[]uint64) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -782,7 +859,7 @@ func (b *ValueBinder) Uint32s(sourceParam string, dest *[]uint32) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustUint32s requires parameter value to exist to be bind to uint32 slice variable. Returns error when value does not exist
|
||||
// MustUint32s requires parameter value to exist to bind to uint32 slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint32s(sourceParam string, dest *[]uint32) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -792,7 +869,7 @@ func (b *ValueBinder) Uint16s(sourceParam string, dest *[]uint16) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustUint16s requires parameter value to exist to be bind to uint16 slice variable. Returns error when value does not exist
|
||||
// MustUint16s requires parameter value to exist to bind to uint16 slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint16s(sourceParam string, dest *[]uint16) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -802,7 +879,7 @@ func (b *ValueBinder) Uint8s(sourceParam string, dest *[]uint8) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustUint8s requires parameter value to exist to be bind to uint8 slice variable. Returns error when value does not exist
|
||||
// MustUint8s requires parameter value to exist to bind to uint8 slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUint8s(sourceParam string, dest *[]uint8) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -812,7 +889,7 @@ func (b *ValueBinder) Uints(sourceParam string, dest *[]uint) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustUints requires parameter value to exist to be bind to uint slice variable. Returns error when value does not exist
|
||||
// MustUints requires parameter value to exist to bind to uint slice variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustUints(sourceParam string, dest *[]uint) *ValueBinder {
|
||||
return b.uintsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -822,7 +899,7 @@ func (b *ValueBinder) Bool(sourceParam string, dest *bool) *ValueBinder {
|
||||
return b.boolValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustBool requires parameter value to exist to be bind to bool variable. Returns error when value does not exist
|
||||
// MustBool requires parameter value to exist to bind to bool variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustBool(sourceParam string, dest *bool) *ValueBinder {
|
||||
return b.boolValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -887,7 +964,7 @@ func (b *ValueBinder) Bools(sourceParam string, dest *[]bool) *ValueBinder {
|
||||
return b.boolsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustBools requires parameter values to exist to be bind to slice of bool variables. Returns error when values does not exist
|
||||
// MustBools requires parameter values to exist to bind to slice of bool variables. Returns error when values does not exist
|
||||
func (b *ValueBinder) MustBools(sourceParam string, dest *[]bool) *ValueBinder {
|
||||
return b.boolsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -897,7 +974,7 @@ func (b *ValueBinder) Float64(sourceParam string, dest *float64) *ValueBinder {
|
||||
return b.floatValue(sourceParam, dest, 64, false)
|
||||
}
|
||||
|
||||
// MustFloat64 requires parameter value to exist to be bind to float64 variable. Returns error when value does not exist
|
||||
// MustFloat64 requires parameter value to exist to bind to float64 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustFloat64(sourceParam string, dest *float64) *ValueBinder {
|
||||
return b.floatValue(sourceParam, dest, 64, true)
|
||||
}
|
||||
@ -907,7 +984,7 @@ func (b *ValueBinder) Float32(sourceParam string, dest *float32) *ValueBinder {
|
||||
return b.floatValue(sourceParam, dest, 32, false)
|
||||
}
|
||||
|
||||
// MustFloat32 requires parameter value to exist to be bind to float32 variable. Returns error when value does not exist
|
||||
// MustFloat32 requires parameter value to exist to bind to float32 variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustFloat32(sourceParam string, dest *float32) *ValueBinder {
|
||||
return b.floatValue(sourceParam, dest, 32, true)
|
||||
}
|
||||
@ -992,7 +1069,7 @@ func (b *ValueBinder) Float64s(sourceParam string, dest *[]float64) *ValueBinder
|
||||
return b.floatsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustFloat64s requires parameter values to exist to be bind to slice of float64 variables. Returns error when values does not exist
|
||||
// MustFloat64s requires parameter values to exist to bind to slice of float64 variables. Returns error when values does not exist
|
||||
func (b *ValueBinder) MustFloat64s(sourceParam string, dest *[]float64) *ValueBinder {
|
||||
return b.floatsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -1002,7 +1079,7 @@ func (b *ValueBinder) Float32s(sourceParam string, dest *[]float32) *ValueBinder
|
||||
return b.floatsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustFloat32s requires parameter values to exist to be bind to slice of float32 variables. Returns error when values does not exist
|
||||
// MustFloat32s requires parameter values to exist to bind to slice of float32 variables. Returns error when values does not exist
|
||||
func (b *ValueBinder) MustFloat32s(sourceParam string, dest *[]float32) *ValueBinder {
|
||||
return b.floatsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -1012,7 +1089,7 @@ func (b *ValueBinder) Time(sourceParam string, dest *time.Time, layout string) *
|
||||
return b.time(sourceParam, dest, layout, false)
|
||||
}
|
||||
|
||||
// MustTime requires parameter value to exist to be bind to time.Time variable. Returns error when value does not exist
|
||||
// MustTime requires parameter value to exist to bind to time.Time variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustTime(sourceParam string, dest *time.Time, layout string) *ValueBinder {
|
||||
return b.time(sourceParam, dest, layout, true)
|
||||
}
|
||||
@ -1043,7 +1120,7 @@ func (b *ValueBinder) Times(sourceParam string, dest *[]time.Time, layout string
|
||||
return b.times(sourceParam, dest, layout, false)
|
||||
}
|
||||
|
||||
// MustTimes requires parameter values to exist to be bind to slice of time.Time variables. Returns error when values does not exist
|
||||
// MustTimes requires parameter values to exist to bind to slice of time.Time variables. Returns error when values does not exist
|
||||
func (b *ValueBinder) MustTimes(sourceParam string, dest *[]time.Time, layout string) *ValueBinder {
|
||||
return b.times(sourceParam, dest, layout, true)
|
||||
}
|
||||
@ -1084,7 +1161,7 @@ func (b *ValueBinder) Duration(sourceParam string, dest *time.Duration) *ValueBi
|
||||
return b.duration(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustDuration requires parameter value to exist to be bind to time.Duration variable. Returns error when value does not exist
|
||||
// MustDuration requires parameter value to exist to bind to time.Duration variable. Returns error when value does not exist
|
||||
func (b *ValueBinder) MustDuration(sourceParam string, dest *time.Duration) *ValueBinder {
|
||||
return b.duration(sourceParam, dest, true)
|
||||
}
|
||||
@ -1115,7 +1192,7 @@ func (b *ValueBinder) Durations(sourceParam string, dest *[]time.Duration) *Valu
|
||||
return b.durationsValue(sourceParam, dest, false)
|
||||
}
|
||||
|
||||
// MustDurations requires parameter values to exist to be bind to slice of time.Duration variables. Returns error when values does not exist
|
||||
// MustDurations requires parameter values to exist to bind to slice of time.Duration variables. Returns error when values does not exist
|
||||
func (b *ValueBinder) MustDurations(sourceParam string, dest *[]time.Duration) *ValueBinder {
|
||||
return b.durationsValue(sourceParam, dest, true)
|
||||
}
|
||||
@ -1161,10 +1238,10 @@ func (b *ValueBinder) durations(sourceParam string, values []string, dest *[]tim
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, false, false)
|
||||
return b.unixTime(sourceParam, dest, false, time.Second)
|
||||
}
|
||||
|
||||
// MustUnixTime requires parameter value to exist to be bind to time.Duration variable (in local Time corresponding
|
||||
// MustUnixTime requires parameter value to exist to bind to time.Duration variable (in local time corresponding
|
||||
// to the given Unix time). Returns error when value does not exist.
|
||||
//
|
||||
// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
|
||||
@ -1172,10 +1249,31 @@ func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, true, false)
|
||||
return b.unixTime(sourceParam, dest, true, time.Second)
|
||||
}
|
||||
|
||||
// UnixTimeNano binds parameter to time.Time variable (in local Time corresponding to the given Unix time in nano second precision).
|
||||
// UnixTimeMilli binds parameter to time.Time variable (in local time corresponding to the given Unix time in millisecond precision).
|
||||
//
|
||||
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
|
||||
//
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
func (b *ValueBinder) UnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, false, time.Millisecond)
|
||||
}
|
||||
|
||||
// MustUnixTimeMilli requires parameter value to exist to bind to time.Duration variable (in local time corresponding
|
||||
// to the given Unix time in millisecond precision). Returns error when value does not exist.
|
||||
//
|
||||
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
|
||||
//
|
||||
// Note:
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
func (b *ValueBinder) MustUnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, true, time.Millisecond)
|
||||
}
|
||||
|
||||
// UnixTimeNano binds parameter to time.Time variable (in local time corresponding to the given Unix time in nanosecond precision).
|
||||
//
|
||||
// Example: 1609180603123456789 binds to 2020-12-28T18:36:43.123456789+00:00
|
||||
// Example: 1000000000 binds to 1970-01-01T00:00:01.000000000+00:00
|
||||
@ -1185,10 +1283,10 @@ func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBi
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
||||
func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, false, true)
|
||||
return b.unixTime(sourceParam, dest, false, time.Nanosecond)
|
||||
}
|
||||
|
||||
// MustUnixTimeNano requires parameter value to exist to be bind to time.Duration variable (in local Time corresponding
|
||||
// MustUnixTimeNano requires parameter value to exist to bind to time.Duration variable (in local Time corresponding
|
||||
// to the given Unix time value in nano second precision). Returns error when value does not exist.
|
||||
//
|
||||
// Example: 1609180603123456789 binds to 2020-12-28T18:36:43.123456789+00:00
|
||||
@ -1199,10 +1297,10 @@ func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBi
|
||||
// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
||||
// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
||||
func (b *ValueBinder) MustUnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
|
||||
return b.unixTime(sourceParam, dest, true, true)
|
||||
return b.unixTime(sourceParam, dest, true, time.Nanosecond)
|
||||
}
|
||||
|
||||
func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExist bool, isNano bool) *ValueBinder {
|
||||
func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExist bool, precision time.Duration) *ValueBinder {
|
||||
if b.failFast && b.errors != nil {
|
||||
return b
|
||||
}
|
||||
@ -1221,10 +1319,13 @@ func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExi
|
||||
return b
|
||||
}
|
||||
|
||||
if isNano {
|
||||
*dest = time.Unix(0, n)
|
||||
} else {
|
||||
switch precision {
|
||||
case time.Second:
|
||||
*dest = time.Unix(n, 0)
|
||||
case time.Millisecond:
|
||||
*dest = time.Unix(n/1e3, (n%1e3)*1e6) // TODO: time.UnixMilli(n) exists since Go1.17 switch to that when min version allows
|
||||
case time.Nanosecond:
|
||||
*dest = time.Unix(0, n)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
34
vendor/github.com/labstack/echo/v4/context.go
generated
vendored
34
vendor/github.com/labstack/echo/v4/context.go
generated
vendored
@ -9,8 +9,6 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
@ -183,7 +181,7 @@ type (
|
||||
// Logger returns the `Logger` instance.
|
||||
Logger() Logger
|
||||
|
||||
// Set the logger
|
||||
// SetLogger Set the logger
|
||||
SetLogger(l Logger)
|
||||
|
||||
// Echo returns the `Echo` instance.
|
||||
@ -210,6 +208,13 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
// ContextKeyHeaderAllow is set by Router for getting value for `Allow` header in later stages of handler call chain.
|
||||
// Allow header is mandatory for status 405 (method not found) and useful for OPTIONS method requests.
|
||||
// It is added to context only when Router does not find matching method handler for request.
|
||||
ContextKeyHeaderAllow = "echo_header_allow"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMemory = 32 << 20 // 32 MB
|
||||
indexPage = "index.html"
|
||||
@ -562,29 +567,6 @@ func (c *context) Stream(code int, contentType string, r io.Reader) (err error)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) File(file string) (err error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return NotFoundHandler(c)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, _ := f.Stat()
|
||||
if fi.IsDir() {
|
||||
file = filepath.Join(file, indexPage)
|
||||
f, err = os.Open(file)
|
||||
if err != nil {
|
||||
return NotFoundHandler(c)
|
||||
}
|
||||
defer f.Close()
|
||||
if fi, err = f.Stat(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) Attachment(file, name string) error {
|
||||
return c.contentDisposition(file, name, "attachment")
|
||||
}
|
||||
|
49
vendor/github.com/labstack/echo/v4/context_fs.go
generated
vendored
Normal file
49
vendor/github.com/labstack/echo/v4/context_fs.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
package echo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func (c *context) File(file string) error {
|
||||
return fsFile(c, file, c.echo.Filesystem)
|
||||
}
|
||||
|
||||
// FileFS serves file from given file system.
|
||||
//
|
||||
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
|
||||
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
|
||||
// including `assets/images` as their prefix.
|
||||
func (c *context) FileFS(file string, filesystem fs.FS) error {
|
||||
return fsFile(c, file, filesystem)
|
||||
}
|
||||
|
||||
func fsFile(c Context, file string, filesystem fs.FS) error {
|
||||
f, err := filesystem.Open(file)
|
||||
if err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, _ := f.Stat()
|
||||
if fi.IsDir() {
|
||||
file = filepath.ToSlash(filepath.Join(file, indexPage)) // ToSlash is necessary for Windows. fs.Open and os.Open are different in that aspect.
|
||||
f, err = filesystem.Open(file)
|
||||
if err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
defer f.Close()
|
||||
if fi, err = f.Stat(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ff, ok := f.(io.ReadSeeker)
|
||||
if !ok {
|
||||
return errors.New("file does not implement io.ReadSeeker")
|
||||
}
|
||||
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), ff)
|
||||
return nil
|
||||
}
|
116
vendor/github.com/labstack/echo/v4/echo.go
generated
vendored
116
vendor/github.com/labstack/echo/v4/echo.go
generated
vendored
@ -47,9 +47,6 @@ import (
|
||||
stdLog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
@ -66,6 +63,7 @@ import (
|
||||
type (
|
||||
// Echo is the top-level framework instance.
|
||||
Echo struct {
|
||||
filesystem
|
||||
common
|
||||
// startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
|
||||
// listener address info (on which interface/port was listener binded) without having data races.
|
||||
@ -77,7 +75,6 @@ type (
|
||||
maxParam *int
|
||||
router *Router
|
||||
routers map[string]*Router
|
||||
notFoundHandler HandlerFunc
|
||||
pool sync.Pool
|
||||
Server *http.Server
|
||||
TLSServer *http.Server
|
||||
@ -113,10 +110,10 @@ type (
|
||||
}
|
||||
|
||||
// MiddlewareFunc defines a function to process middleware.
|
||||
MiddlewareFunc func(HandlerFunc) HandlerFunc
|
||||
MiddlewareFunc func(next HandlerFunc) HandlerFunc
|
||||
|
||||
// HandlerFunc defines a function to serve HTTP requests.
|
||||
HandlerFunc func(Context) error
|
||||
HandlerFunc func(c Context) error
|
||||
|
||||
// HTTPErrorHandler is a centralized HTTP error handler.
|
||||
HTTPErrorHandler func(error, Context)
|
||||
@ -186,12 +183,18 @@ const (
|
||||
PROPFIND = "PROPFIND"
|
||||
// REPORT Method can be used to get information about a resource, see rfc 3253
|
||||
REPORT = "REPORT"
|
||||
// RouteNotFound is special method type for routes handling "route not found" (404) cases
|
||||
RouteNotFound = "echo_route_not_found"
|
||||
)
|
||||
|
||||
// Headers
|
||||
const (
|
||||
HeaderAccept = "Accept"
|
||||
HeaderAcceptEncoding = "Accept-Encoding"
|
||||
// HeaderAllow is the name of the "Allow" header field used to list the set of methods
|
||||
// advertised as supported by the target resource. Returning an Allow header is mandatory
|
||||
// for status 405 (method not found) and useful for the OPTIONS method in responses.
|
||||
// See RFC 7231: https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1
|
||||
HeaderAllow = "Allow"
|
||||
HeaderAuthorization = "Authorization"
|
||||
HeaderContentDisposition = "Content-Disposition"
|
||||
@ -203,6 +206,7 @@ const (
|
||||
HeaderIfModifiedSince = "If-Modified-Since"
|
||||
HeaderLastModified = "Last-Modified"
|
||||
HeaderLocation = "Location"
|
||||
HeaderRetryAfter = "Retry-After"
|
||||
HeaderUpgrade = "Upgrade"
|
||||
HeaderVary = "Vary"
|
||||
HeaderWWWAuthenticate = "WWW-Authenticate"
|
||||
@ -212,11 +216,14 @@ const (
|
||||
HeaderXForwardedSsl = "X-Forwarded-Ssl"
|
||||
HeaderXUrlScheme = "X-Url-Scheme"
|
||||
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
|
||||
HeaderXRealIP = "X-Real-IP"
|
||||
HeaderXRequestID = "X-Request-ID"
|
||||
HeaderXRealIP = "X-Real-Ip"
|
||||
HeaderXRequestID = "X-Request-Id"
|
||||
HeaderXCorrelationID = "X-Correlation-Id"
|
||||
HeaderXRequestedWith = "X-Requested-With"
|
||||
HeaderServer = "Server"
|
||||
HeaderOrigin = "Origin"
|
||||
HeaderCacheControl = "Cache-Control"
|
||||
HeaderConnection = "Connection"
|
||||
|
||||
// Access control
|
||||
HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
|
||||
@ -241,7 +248,7 @@ const (
|
||||
|
||||
const (
|
||||
// Version of Echo
|
||||
Version = "4.5.0"
|
||||
Version = "4.9.0"
|
||||
website = "https://echo.labstack.com"
|
||||
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
|
||||
banner = `
|
||||
@ -301,6 +308,12 @@ var (
|
||||
}
|
||||
|
||||
MethodNotAllowedHandler = func(c Context) error {
|
||||
// See RFC 7231 section 7.4.1: An origin server MUST generate an Allow field in a 405 (Method Not Allowed)
|
||||
// response and MAY do so in any other response. For disabled resources an empty Allow header may be returned
|
||||
routerAllowMethods, ok := c.Get(ContextKeyHeaderAllow).(string)
|
||||
if ok && routerAllowMethods != "" {
|
||||
c.Response().Header().Set(HeaderAllow, routerAllowMethods)
|
||||
}
|
||||
return ErrMethodNotAllowed
|
||||
}
|
||||
)
|
||||
@ -308,6 +321,7 @@ var (
|
||||
// New creates an instance of Echo.
|
||||
func New() (e *Echo) {
|
||||
e = &Echo{
|
||||
filesystem: createFilesystem(),
|
||||
Server: new(http.Server),
|
||||
TLSServer: new(http.Server),
|
||||
AutoTLSManager: autocert.Manager{
|
||||
@ -357,7 +371,17 @@ func (e *Echo) Routers() map[string]*Router {
|
||||
|
||||
// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
|
||||
// with status code.
|
||||
//
|
||||
// NOTE: In case errors happens in middleware call-chain that is returning from handler (which did not return an error).
|
||||
// When handler has already sent response (ala c.JSON()) and there is error in middleware that is returning from
|
||||
// handler. Then the error that global error handler received will be ignored because we have already "commited" the
|
||||
// response and status code header has been sent to the client.
|
||||
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
||||
|
||||
if c.Response().Committed {
|
||||
return
|
||||
}
|
||||
|
||||
he, ok := err.(*HTTPError)
|
||||
if ok {
|
||||
if he.Internal != nil {
|
||||
@ -384,7 +408,6 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
||||
}
|
||||
|
||||
// Send response
|
||||
if !c.Response().Committed {
|
||||
if c.Request().Method == http.MethodHead { // Issue #608
|
||||
err = c.NoContent(he.Code)
|
||||
} else {
|
||||
@ -393,7 +416,6 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pre adds middleware to the chain which is run before router.
|
||||
@ -460,8 +482,21 @@ func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodTrace, path, h, m...)
|
||||
}
|
||||
|
||||
// Any registers a new route for all HTTP methods and path with matching handler
|
||||
// RouteNotFound registers a special-case route which is executed when no other route is found (i.e. HTTP 404 cases)
|
||||
// for current request URL.
|
||||
// Path supports static and named/any parameters just like other http method is defined. Generally path is ended with
|
||||
// wildcard/match-any character (`/*`, `/download/*` etc).
|
||||
//
|
||||
// Example: `e.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })`
|
||||
func (e *Echo) RouteNotFound(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(RouteNotFound, path, h, m...)
|
||||
}
|
||||
|
||||
// Any registers a new route for all HTTP methods (supported by Echo) and path with matching handler
|
||||
// in the router with optional route-level middleware.
|
||||
//
|
||||
// Note: this method only adds specific set of supported HTTP methods as handler and is not true
|
||||
// "catch-any-arbitrary-method" way of matching requests.
|
||||
func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
|
||||
routes := make([]*Route, len(methods))
|
||||
for i, m := range methods {
|
||||
@ -480,50 +515,6 @@ func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middlew
|
||||
return routes
|
||||
}
|
||||
|
||||
// Static registers a new route with path prefix to serve static files from the
|
||||
// provided root directory.
|
||||
func (e *Echo) Static(prefix, root string) *Route {
|
||||
if root == "" {
|
||||
root = "." // For security we want to restrict to CWD.
|
||||
}
|
||||
return e.static(prefix, root, e.GET)
|
||||
}
|
||||
|
||||
func (common) static(prefix, root string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route) *Route {
|
||||
h := func(c Context) error {
|
||||
p, err := url.PathUnescape(c.Param("*"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security
|
||||
fi, err := os.Stat(name)
|
||||
if err != nil {
|
||||
// The access path does not exist
|
||||
return NotFoundHandler(c)
|
||||
}
|
||||
|
||||
// If the request is for a directory and does not end with "/"
|
||||
p = c.Request().URL.Path // path must not be empty.
|
||||
if fi.IsDir() && p[len(p)-1] != '/' {
|
||||
// Redirect to ends with "/"
|
||||
return c.Redirect(http.StatusMovedPermanently, p+"/")
|
||||
}
|
||||
return c.File(name)
|
||||
}
|
||||
// Handle added routes based on trailing slash:
|
||||
// /prefix => exact route "/prefix" + any route "/prefix/*"
|
||||
// /prefix/ => only any route "/prefix/*"
|
||||
if prefix != "" {
|
||||
if prefix[len(prefix)-1] == '/' {
|
||||
// Only add any route for intentional trailing slash
|
||||
return get(prefix+"*", h)
|
||||
}
|
||||
get(prefix, h)
|
||||
}
|
||||
return get(prefix+"/*", h)
|
||||
}
|
||||
|
||||
func (common) file(path, file string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route,
|
||||
m ...MiddlewareFunc) *Route {
|
||||
return get(path, func(c Context) error {
|
||||
@ -539,6 +530,7 @@ func (e *Echo) File(path, file string, m ...MiddlewareFunc) *Route {
|
||||
func (e *Echo) add(host, method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
|
||||
name := handlerName(handler)
|
||||
router := e.findRouter(host)
|
||||
// FIXME: when handler+middleware are both nil ... make it behave like handler removal
|
||||
router.Add(method, path, func(c Context) error {
|
||||
h := applyMiddleware(handler, middleware...)
|
||||
return h(c)
|
||||
@ -634,7 +626,7 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Acquire context
|
||||
c := e.pool.Get().(*context)
|
||||
c.Reset(r, w)
|
||||
h := NotFoundHandler
|
||||
var h func(Context) error
|
||||
|
||||
if e.premiddleware == nil {
|
||||
e.findRouter(r.Host).Find(r.Method, GetPath(r), c)
|
||||
@ -756,7 +748,7 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
|
||||
return s.Serve(e.Listener)
|
||||
}
|
||||
|
||||
func (e *Echo) configureServer(s *http.Server) (err error) {
|
||||
func (e *Echo) configureServer(s *http.Server) error {
|
||||
// Setup
|
||||
e.colorer.SetOutput(e.Logger.Output())
|
||||
s.ErrorLog = e.StdLogger
|
||||
@ -771,10 +763,11 @@ func (e *Echo) configureServer(s *http.Server) (err error) {
|
||||
|
||||
if s.TLSConfig == nil {
|
||||
if e.Listener == nil {
|
||||
e.Listener, err = newListener(s.Addr, e.ListenerNetwork)
|
||||
l, err := newListener(s.Addr, e.ListenerNetwork)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.Listener = l
|
||||
}
|
||||
if !e.HidePort {
|
||||
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
|
||||
@ -815,7 +808,7 @@ func (e *Echo) TLSListenerAddr() net.Addr {
|
||||
}
|
||||
|
||||
// StartH2CServer starts a custom http/2 server with h2c (HTTP/2 Cleartext).
|
||||
func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) {
|
||||
func (e *Echo) StartH2CServer(address string, h2s *http2.Server) error {
|
||||
e.startupMutex.Lock()
|
||||
// Setup
|
||||
s := e.Server
|
||||
@ -832,11 +825,12 @@ func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) {
|
||||
}
|
||||
|
||||
if e.Listener == nil {
|
||||
e.Listener, err = newListener(s.Addr, e.ListenerNetwork)
|
||||
l, err := newListener(s.Addr, e.ListenerNetwork)
|
||||
if err != nil {
|
||||
e.startupMutex.Unlock()
|
||||
return err
|
||||
}
|
||||
e.Listener = l
|
||||
}
|
||||
if !e.HidePort {
|
||||
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
|
||||
|
175
vendor/github.com/labstack/echo/v4/echo_fs.go
generated
vendored
Normal file
175
vendor/github.com/labstack/echo/v4/echo_fs.go
generated
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
package echo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type filesystem struct {
|
||||
// Filesystem is file system used by Static and File handlers to access files.
|
||||
// Defaults to os.DirFS(".")
|
||||
//
|
||||
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
|
||||
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
|
||||
// including `assets/images` as their prefix.
|
||||
Filesystem fs.FS
|
||||
}
|
||||
|
||||
func createFilesystem() filesystem {
|
||||
return filesystem{
|
||||
Filesystem: newDefaultFS(),
|
||||
}
|
||||
}
|
||||
|
||||
// Static registers a new route with path prefix to serve static files from the provided root directory.
|
||||
func (e *Echo) Static(pathPrefix, fsRoot string) *Route {
|
||||
subFs := MustSubFS(e.Filesystem, fsRoot)
|
||||
return e.Add(
|
||||
http.MethodGet,
|
||||
pathPrefix+"*",
|
||||
StaticDirectoryHandler(subFs, false),
|
||||
)
|
||||
}
|
||||
|
||||
// StaticFS registers a new route with path prefix to serve static files from the provided file system.
|
||||
//
|
||||
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
|
||||
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
|
||||
// including `assets/images` as their prefix.
|
||||
func (e *Echo) StaticFS(pathPrefix string, filesystem fs.FS) *Route {
|
||||
return e.Add(
|
||||
http.MethodGet,
|
||||
pathPrefix+"*",
|
||||
StaticDirectoryHandler(filesystem, false),
|
||||
)
|
||||
}
|
||||
|
||||
// StaticDirectoryHandler creates handler function to serve files from provided file system
|
||||
// When disablePathUnescaping is set then file name from path is not unescaped and is served as is.
|
||||
func StaticDirectoryHandler(fileSystem fs.FS, disablePathUnescaping bool) HandlerFunc {
|
||||
return func(c Context) error {
|
||||
p := c.Param("*")
|
||||
if !disablePathUnescaping { // when router is already unescaping we do not want to do is twice
|
||||
tmpPath, err := url.PathUnescape(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unescape path variable: %w", err)
|
||||
}
|
||||
p = tmpPath
|
||||
}
|
||||
|
||||
// fs.FS.Open() already assumes that file names are relative to FS root path and considers name with prefix `/` as invalid
|
||||
name := filepath.ToSlash(filepath.Clean(strings.TrimPrefix(p, "/")))
|
||||
fi, err := fs.Stat(fileSystem, name)
|
||||
if err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
// If the request is for a directory and does not end with "/"
|
||||
p = c.Request().URL.Path // path must not be empty.
|
||||
if fi.IsDir() && len(p) > 0 && p[len(p)-1] != '/' {
|
||||
// Redirect to ends with "/"
|
||||
return c.Redirect(http.StatusMovedPermanently, sanitizeURI(p+"/"))
|
||||
}
|
||||
return fsFile(c, name, fileSystem)
|
||||
}
|
||||
}
|
||||
|
||||
// FileFS registers a new route with path to serve file from the provided file system.
|
||||
func (e *Echo) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
|
||||
return e.GET(path, StaticFileHandler(file, filesystem), m...)
|
||||
}
|
||||
|
||||
// StaticFileHandler creates handler function to serve file from provided file system
|
||||
func StaticFileHandler(file string, filesystem fs.FS) HandlerFunc {
|
||||
return func(c Context) error {
|
||||
return fsFile(c, file, filesystem)
|
||||
}
|
||||
}
|
||||
|
||||
// defaultFS exists to preserve pre v4.7.0 behaviour where files were open by `os.Open`.
|
||||
// v4.7 introduced `echo.Filesystem` field which is Go1.16+ `fs.Fs` interface.
|
||||
// Difference between `os.Open` and `fs.Open` is that FS does not allow opening path that start with `.`, `..` or `/`
|
||||
// etc. For example previously you could have `../images` in your application but `fs := os.DirFS("./")` would not
|
||||
// allow you to use `fs.Open("../images")` and this would break all old applications that rely on being able to
|
||||
// traverse up from current executable run path.
|
||||
// NB: private because you really should use fs.FS implementation instances
|
||||
type defaultFS struct {
|
||||
prefix string
|
||||
fs fs.FS
|
||||
}
|
||||
|
||||
func newDefaultFS() *defaultFS {
|
||||
dir, _ := os.Getwd()
|
||||
return &defaultFS{
|
||||
prefix: dir,
|
||||
fs: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (fs defaultFS) Open(name string) (fs.File, error) {
|
||||
if fs.fs == nil {
|
||||
return os.Open(name)
|
||||
}
|
||||
return fs.fs.Open(name)
|
||||
}
|
||||
|
||||
func subFS(currentFs fs.FS, root string) (fs.FS, error) {
|
||||
root = filepath.ToSlash(filepath.Clean(root)) // note: fs.FS operates only with slashes. `ToSlash` is necessary for Windows
|
||||
if dFS, ok := currentFs.(*defaultFS); ok {
|
||||
// we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS.
|
||||
// fs.Fs.Open does not like relative paths ("./", "../") and absolute paths at all but prior echo.Filesystem we
|
||||
// were able to use paths like `./myfile.log`, `/etc/hosts` and these would work fine with `os.Open` but not with fs.Fs
|
||||
if isRelativePath(root) {
|
||||
root = filepath.Join(dFS.prefix, root)
|
||||
}
|
||||
return &defaultFS{
|
||||
prefix: root,
|
||||
fs: os.DirFS(root),
|
||||
}, nil
|
||||
}
|
||||
return fs.Sub(currentFs, root)
|
||||
}
|
||||
|
||||
func isRelativePath(path string) bool {
|
||||
if path == "" {
|
||||
return true
|
||||
}
|
||||
if path[0] == '/' {
|
||||
return false
|
||||
}
|
||||
if runtime.GOOS == "windows" && strings.IndexByte(path, ':') != -1 {
|
||||
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#file_and_directory_names
|
||||
// https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MustSubFS creates sub FS from current filesystem or panic on failure.
|
||||
// Panic happens when `fsRoot` contains invalid path according to `fs.ValidPath` rules.
|
||||
//
|
||||
// MustSubFS is helpful when dealing with `embed.FS` because for example `//go:embed assets/images` embeds files with
|
||||
// paths including `assets/images` as their prefix. In that case use `fs := echo.MustSubFS(fs, "rootDirectory") to
|
||||
// create sub fs which uses necessary prefix for directory path.
|
||||
func MustSubFS(currentFs fs.FS, fsRoot string) fs.FS {
|
||||
subFs, err := subFS(currentFs, fsRoot)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("can not create sub FS, invalid root given, err: %w", err))
|
||||
}
|
||||
return subFs
|
||||
}
|
||||
|
||||
func sanitizeURI(uri string) string {
|
||||
// double slash `\\`, `//` or even `\/` is absolute uri for browsers and by redirecting request to that uri
|
||||
// we are vulnerable to open redirect attack. so replace all slashes from the beginning with single slash
|
||||
if len(uri) > 1 && (uri[0] == '\\' || uri[0] == '/') && (uri[1] == '\\' || uri[1] == '/') {
|
||||
uri = "/" + strings.TrimLeft(uri, `/\`)
|
||||
}
|
||||
return uri
|
||||
}
|
12
vendor/github.com/labstack/echo/v4/group.go
generated
vendored
12
vendor/github.com/labstack/echo/v4/group.go
generated
vendored
@ -102,16 +102,18 @@ func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) (sg *Group) {
|
||||
return
|
||||
}
|
||||
|
||||
// Static implements `Echo#Static()` for sub-routes within the Group.
|
||||
func (g *Group) Static(prefix, root string) {
|
||||
g.static(prefix, root, g.GET)
|
||||
}
|
||||
|
||||
// File implements `Echo#File()` for sub-routes within the Group.
|
||||
func (g *Group) File(path, file string) {
|
||||
g.file(path, file, g.GET)
|
||||
}
|
||||
|
||||
// RouteNotFound implements `Echo#RouteNotFound()` for sub-routes within the Group.
|
||||
//
|
||||
// Example: `g.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })`
|
||||
func (g *Group) RouteNotFound(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(RouteNotFound, path, h, m...)
|
||||
}
|
||||
|
||||
// Add implements `Echo#Add()` for sub-routes within the Group.
|
||||
func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
|
||||
// Combine into a new slice to avoid accidentally passing the same slice for
|
||||
|
30
vendor/github.com/labstack/echo/v4/group_fs.go
generated
vendored
Normal file
30
vendor/github.com/labstack/echo/v4/group_fs.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
package echo
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Static implements `Echo#Static()` for sub-routes within the Group.
|
||||
func (g *Group) Static(pathPrefix, fsRoot string) {
|
||||
subFs := MustSubFS(g.echo.Filesystem, fsRoot)
|
||||
g.StaticFS(pathPrefix, subFs)
|
||||
}
|
||||
|
||||
// StaticFS implements `Echo#StaticFS()` for sub-routes within the Group.
|
||||
//
|
||||
// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
|
||||
// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
|
||||
// including `assets/images` as their prefix.
|
||||
func (g *Group) StaticFS(pathPrefix string, filesystem fs.FS) {
|
||||
g.Add(
|
||||
http.MethodGet,
|
||||
pathPrefix+"*",
|
||||
StaticDirectoryHandler(filesystem, false),
|
||||
)
|
||||
}
|
||||
|
||||
// FileFS implements `Echo#FileFS()` for sub-routes within the Group.
|
||||
func (g *Group) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
|
||||
return g.GET(path, StaticFileHandler(file, filesystem), m...)
|
||||
}
|
138
vendor/github.com/labstack/echo/v4/ip.go
generated
vendored
138
vendor/github.com/labstack/echo/v4/ip.go
generated
vendored
@ -6,6 +6,130 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
/**
|
||||
By: https://github.com/tmshn (See: https://github.com/labstack/echo/pull/1478 , https://github.com/labstack/echox/pull/134 )
|
||||
Source: https://echo.labstack.com/guide/ip-address/
|
||||
|
||||
IP address plays fundamental role in HTTP; it's used for access control, auditing, geo-based access analysis and more.
|
||||
Echo provides handy method [`Context#RealIP()`](https://godoc.org/github.com/labstack/echo#Context) for that.
|
||||
|
||||
However, it is not trivial to retrieve the _real_ IP address from requests especially when you put L7 proxies before the application.
|
||||
In such situation, _real_ IP needs to be relayed on HTTP layer from proxies to your app, but you must not trust HTTP headers unconditionally.
|
||||
Otherwise, you might give someone a chance of deceiving you. **A security risk!**
|
||||
|
||||
To retrieve IP address reliably/securely, you must let your application be aware of the entire architecture of your infrastructure.
|
||||
In Echo, this can be done by configuring `Echo#IPExtractor` appropriately.
|
||||
This guides show you why and how.
|
||||
|
||||
> Note: if you dont' set `Echo#IPExtractor` explicitly, Echo fallback to legacy behavior, which is not a good choice.
|
||||
|
||||
Let's start from two questions to know the right direction:
|
||||
|
||||
1. Do you put any HTTP (L7) proxy in front of the application?
|
||||
- It includes both cloud solutions (such as AWS ALB or GCP HTTP LB) and OSS ones (such as Nginx, Envoy or Istio ingress gateway).
|
||||
2. If yes, what HTTP header do your proxies use to pass client IP to the application?
|
||||
|
||||
## Case 1. With no proxy
|
||||
|
||||
If you put no proxy (e.g.: directory facing to the internet), all you need to (and have to) see is IP address from network layer.
|
||||
Any HTTP header is untrustable because the clients have full control what headers to be set.
|
||||
|
||||
In this case, use `echo.ExtractIPDirect()`.
|
||||
|
||||
```go
|
||||
e.IPExtractor = echo.ExtractIPDirect()
|
||||
```
|
||||
|
||||
## Case 2. With proxies using `X-Forwarded-For` header
|
||||
|
||||
[`X-Forwared-For` (XFF)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) is the popular header
|
||||
to relay clients' IP addresses.
|
||||
At each hop on the proxies, they append the request IP address at the end of the header.
|
||||
|
||||
Following example diagram illustrates this behavior.
|
||||
|
||||
```text
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ "Origin" │───────────>│ Proxy 1 │───────────>│ Proxy 2 │───────────>│ Your app │
|
||||
│ (IP: a) │ │ (IP: b) │ │ (IP: c) │ │ │
|
||||
└──────────┘ └──────────┘ └──────────┘ └──────────┘
|
||||
|
||||
Case 1.
|
||||
XFF: "" "a" "a, b"
|
||||
~~~~~~
|
||||
Case 2.
|
||||
XFF: "x" "x, a" "x, a, b"
|
||||
~~~~~~~~~
|
||||
↑ What your app will see
|
||||
```
|
||||
|
||||
In this case, use **first _untrustable_ IP reading from right**. Never use first one reading from left, as it is
|
||||
configurable by client. Here "trustable" means "you are sure the IP address belongs to your infrastructre".
|
||||
In above example, if `b` and `c` are trustable, the IP address of the client is `a` for both cases, never be `x`.
|
||||
|
||||
In Echo, use `ExtractIPFromXFFHeader(...TrustOption)`.
|
||||
|
||||
```go
|
||||
e.IPExtractor = echo.ExtractIPFromXFFHeader()
|
||||
```
|
||||
|
||||
By default, it trusts internal IP addresses (loopback, link-local unicast, private-use and unique local address
|
||||
from [RFC6890](https://tools.ietf.org/html/rfc6890), [RFC4291](https://tools.ietf.org/html/rfc4291) and
|
||||
[RFC4193](https://tools.ietf.org/html/rfc4193)).
|
||||
To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption)s.
|
||||
|
||||
E.g.:
|
||||
|
||||
```go
|
||||
e.IPExtractor = echo.ExtractIPFromXFFHeader(
|
||||
TrustLinkLocal(false),
|
||||
TrustIPRanges(lbIPRange),
|
||||
)
|
||||
```
|
||||
|
||||
- Ref: https://godoc.org/github.com/labstack/echo#TrustOption
|
||||
|
||||
## Case 3. With proxies using `X-Real-IP` header
|
||||
|
||||
`X-Real-IP` is another HTTP header to relay clients' IP addresses, but it carries only one address unlike XFF.
|
||||
|
||||
If your proxies set this header, use `ExtractIPFromRealIPHeader(...TrustOption)`.
|
||||
|
||||
```go
|
||||
e.IPExtractor = echo.ExtractIPFromRealIPHeader()
|
||||
```
|
||||
|
||||
Again, it trusts internal IP addresses by default (loopback, link-local unicast, private-use and unique local address
|
||||
from [RFC6890](https://tools.ietf.org/html/rfc6890), [RFC4291](https://tools.ietf.org/html/rfc4291) and
|
||||
[RFC4193](https://tools.ietf.org/html/rfc4193)).
|
||||
To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption)s.
|
||||
|
||||
- Ref: https://godoc.org/github.com/labstack/echo#TrustOption
|
||||
|
||||
> **Never forget** to configure the outermost proxy (i.e.; at the edge of your infrastructure) **not to pass through incoming headers**.
|
||||
> Otherwise there is a chance of fraud, as it is what clients can control.
|
||||
|
||||
## About default behavior
|
||||
|
||||
In default behavior, Echo sees all of first XFF header, X-Real-IP header and IP from network layer.
|
||||
|
||||
As you might already notice, after reading this article, this is not good.
|
||||
Sole reason this is default is just backward compatibility.
|
||||
|
||||
## Private IP ranges
|
||||
|
||||
See: https://en.wikipedia.org/wiki/Private_network
|
||||
|
||||
Private IPv4 address ranges (RFC 1918):
|
||||
* 10.0.0.0 – 10.255.255.255 (24-bit block)
|
||||
* 172.16.0.0 – 172.31.255.255 (20-bit block)
|
||||
* 192.168.0.0 – 192.168.255.255 (16-bit block)
|
||||
|
||||
Private IPv6 address ranges:
|
||||
* fc00::/7 address block = RFC 4193 Unique Local Addresses (ULA)
|
||||
|
||||
*/
|
||||
|
||||
type ipChecker struct {
|
||||
trustLoopback bool
|
||||
trustLinkLocal bool
|
||||
@ -52,6 +176,7 @@ func newIPChecker(configs []TrustOption) *ipChecker {
|
||||
return checker
|
||||
}
|
||||
|
||||
// Go1.16+ added `ip.IsPrivate()` but until that use this implementation
|
||||
func isPrivateIPRange(ip net.IP) bool {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
return ip4[0] == 10 ||
|
||||
@ -87,10 +212,12 @@ type IPExtractor func(*http.Request) string
|
||||
// ExtractIPDirect extracts IP address using actual IP address.
|
||||
// Use this if your server faces to internet directory (i.e.: uses no proxy).
|
||||
func ExtractIPDirect() IPExtractor {
|
||||
return func(req *http.Request) string {
|
||||
return extractIP
|
||||
}
|
||||
|
||||
func extractIP(req *http.Request) string {
|
||||
ra, _, _ := net.SplitHostPort(req.RemoteAddr)
|
||||
return ra
|
||||
}
|
||||
}
|
||||
|
||||
// ExtractIPFromRealIPHeader extracts IP address using x-real-ip header.
|
||||
@ -98,14 +225,13 @@ func ExtractIPDirect() IPExtractor {
|
||||
func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor {
|
||||
checker := newIPChecker(options)
|
||||
return func(req *http.Request) string {
|
||||
directIP := ExtractIPDirect()(req)
|
||||
realIP := req.Header.Get(HeaderXRealIP)
|
||||
if realIP != "" {
|
||||
if ip := net.ParseIP(directIP); ip != nil && checker.trust(ip) {
|
||||
if ip := net.ParseIP(realIP); ip != nil && checker.trust(ip) {
|
||||
return realIP
|
||||
}
|
||||
}
|
||||
return directIP
|
||||
return extractIP(req)
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +241,7 @@ func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor {
|
||||
func ExtractIPFromXFFHeader(options ...TrustOption) IPExtractor {
|
||||
checker := newIPChecker(options)
|
||||
return func(req *http.Request) string {
|
||||
directIP := ExtractIPDirect()(req)
|
||||
directIP := extractIP(req)
|
||||
xffs := req.Header[HeaderXForwardedFor]
|
||||
if len(xffs) == 0 {
|
||||
return directIP
|
||||
|
6
vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
generated
vendored
6
vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
generated
vendored
@ -4,6 +4,7 @@ import (
|
||||
"encoding/base64"
|
||||
"strconv"
|
||||
"strings"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
@ -74,10 +75,13 @@ func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
|
||||
l := len(basic)
|
||||
|
||||
if len(auth) > l+1 && strings.EqualFold(auth[:l], basic) {
|
||||
// Invalid base64 shouldn't be treated as error
|
||||
// instead should be treated as invalid client input
|
||||
b, err := base64.StdEncoding.DecodeString(auth[l+1:])
|
||||
if err != nil {
|
||||
return err
|
||||
return echo.NewHTTPError(http.StatusBadRequest).SetInternal(err)
|
||||
}
|
||||
|
||||
cred := string(b)
|
||||
for i := 0; i < len(cred); i++ {
|
||||
if cred[i] == ':' {
|
||||
|
9
vendor/github.com/labstack/echo/v4/middleware/compress.go
generated
vendored
9
vendor/github.com/labstack/echo/v4/middleware/compress.go
generated
vendored
@ -27,6 +27,7 @@ type (
|
||||
gzipResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
wroteBody bool
|
||||
}
|
||||
)
|
||||
|
||||
@ -78,8 +79,9 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
rw := res.Writer
|
||||
w.Reset(rw)
|
||||
grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}
|
||||
defer func() {
|
||||
if res.Size == 0 {
|
||||
if !grw.wroteBody {
|
||||
if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
|
||||
res.Header().Del(echo.HeaderContentEncoding)
|
||||
}
|
||||
@ -92,7 +94,6 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
||||
w.Close()
|
||||
pool.Put(w)
|
||||
}()
|
||||
grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}
|
||||
res.Writer = grw
|
||||
}
|
||||
return next(c)
|
||||
@ -101,9 +102,6 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
|
||||
func (w *gzipResponseWriter) WriteHeader(code int) {
|
||||
if code == http.StatusNoContent { // Issue #489
|
||||
w.ResponseWriter.Header().Del(echo.HeaderContentEncoding)
|
||||
}
|
||||
w.Header().Del(echo.HeaderContentLength) // Issue #444
|
||||
w.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
@ -112,6 +110,7 @@ func (w *gzipResponseWriter) Write(b []byte) (int, error) {
|
||||
if w.Header().Get(echo.HeaderContentType) == "" {
|
||||
w.Header().Set(echo.HeaderContentType, http.DetectContentType(b))
|
||||
}
|
||||
w.wroteBody = true
|
||||
return w.Writer.Write(b)
|
||||
}
|
||||
|
||||
|
141
vendor/github.com/labstack/echo/v4/middleware/cors.go
generated
vendored
141
vendor/github.com/labstack/echo/v4/middleware/cors.go
generated
vendored
@ -15,42 +15,85 @@ type (
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// AllowOrigin defines a list of origins that may access the resource.
|
||||
// AllowOrigins determines the value of the Access-Control-Allow-Origin
|
||||
// response header. This header defines a list of origins that may access the
|
||||
// resource. The wildcard characters '*' and '?' are supported and are
|
||||
// converted to regex fragments '.*' and '.' accordingly.
|
||||
//
|
||||
// Security: use extreme caution when handling the origin, and carefully
|
||||
// validate any logic. Remember that attackers may register hostile domain names.
|
||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// Optional. Default value []string{"*"}.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
AllowOrigins []string `yaml:"allow_origins"`
|
||||
|
||||
// AllowOriginFunc is a custom function to validate the origin. It takes the
|
||||
// origin as an argument and returns true if allowed or false otherwise. If
|
||||
// an error is returned, it is returned by the handler. If this option is
|
||||
// set, AllowOrigins is ignored.
|
||||
//
|
||||
// Security: use extreme caution when handling the origin, and carefully
|
||||
// validate any logic. Remember that attackers may register hostile domain names.
|
||||
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// Optional.
|
||||
AllowOriginFunc func(origin string) (bool, error) `yaml:"allow_origin_func"`
|
||||
|
||||
// AllowMethods defines a list methods allowed when accessing the resource.
|
||||
// This is used in response to a preflight request.
|
||||
// AllowMethods determines the value of the Access-Control-Allow-Methods
|
||||
// response header. This header specified the list of methods allowed when
|
||||
// accessing the resource. This is used in response to a preflight request.
|
||||
//
|
||||
// Optional. Default value DefaultCORSConfig.AllowMethods.
|
||||
// If `allowMethods` is left empty, this middleware will fill for preflight
|
||||
// request `Access-Control-Allow-Methods` header value
|
||||
// from `Allow` header that echo.Router set into context.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
||||
AllowMethods []string `yaml:"allow_methods"`
|
||||
|
||||
// AllowHeaders defines a list of request headers that can be used when
|
||||
// making the actual request. This is in response to a preflight request.
|
||||
// AllowHeaders determines the value of the Access-Control-Allow-Headers
|
||||
// response header. This header is used in response to a preflight request to
|
||||
// indicate which HTTP headers can be used when making the actual request.
|
||||
//
|
||||
// Optional. Default value []string{}.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
||||
AllowHeaders []string `yaml:"allow_headers"`
|
||||
|
||||
// AllowCredentials indicates whether or not the response to the request
|
||||
// can be exposed when the credentials flag is true. When used as part of
|
||||
// a response to a preflight request, this indicates whether or not the
|
||||
// actual request can be made using credentials.
|
||||
// Optional. Default value false.
|
||||
// AllowCredentials determines the value of the
|
||||
// Access-Control-Allow-Credentials response header. This header indicates
|
||||
// whether or not the response to the request can be exposed when the
|
||||
// credentials mode (Request.credentials) is true. When used as part of a
|
||||
// response to a preflight request, this indicates whether or not the actual
|
||||
// request can be made using credentials. See also
|
||||
// [MDN: Access-Control-Allow-Credentials].
|
||||
//
|
||||
// Optional. Default value false, in which case the header is not set.
|
||||
//
|
||||
// Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`.
|
||||
// See "Exploiting CORS misconfigurations for Bitcoins and bounties",
|
||||
// https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
||||
AllowCredentials bool `yaml:"allow_credentials"`
|
||||
|
||||
// ExposeHeaders defines a whitelist headers that clients are allowed to
|
||||
// access.
|
||||
// Optional. Default value []string{}.
|
||||
// ExposeHeaders determines the value of Access-Control-Expose-Headers, which
|
||||
// defines a list of headers that clients are allowed to access.
|
||||
//
|
||||
// Optional. Default value []string{}, in which case the header is not set.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header
|
||||
ExposeHeaders []string `yaml:"expose_headers"`
|
||||
|
||||
// MaxAge indicates how long (in seconds) the results of a preflight request
|
||||
// can be cached.
|
||||
// Optional. Default value 0.
|
||||
// MaxAge determines the value of the Access-Control-Max-Age response header.
|
||||
// This header indicates how long (in seconds) the results of a preflight
|
||||
// request can be cached.
|
||||
//
|
||||
// Optional. Default value 0. The header is set only if MaxAge > 0.
|
||||
//
|
||||
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
||||
MaxAge int `yaml:"max_age"`
|
||||
}
|
||||
)
|
||||
@ -65,13 +108,22 @@ var (
|
||||
)
|
||||
|
||||
// CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
|
||||
// See: https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS
|
||||
// See also [MDN: Cross-Origin Resource Sharing (CORS)].
|
||||
//
|
||||
// Security: Poorly configured CORS can compromise security because it allows
|
||||
// relaxation of the browser's Same-Origin policy. See [Exploiting CORS
|
||||
// misconfigurations for Bitcoins and bounties] and [Portswigger: Cross-origin
|
||||
// resource sharing (CORS)] for more details.
|
||||
//
|
||||
// [MDN: Cross-Origin Resource Sharing (CORS)]: https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS
|
||||
// [Exploiting CORS misconfigurations for Bitcoins and bounties]: https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
|
||||
// [Portswigger: Cross-origin resource sharing (CORS)]: https://portswigger.net/web-security/cors
|
||||
func CORS() echo.MiddlewareFunc {
|
||||
return CORSWithConfig(DefaultCORSConfig)
|
||||
}
|
||||
|
||||
// CORSWithConfig returns a CORS middleware with config.
|
||||
// See: `CORS()`.
|
||||
// See: [CORS].
|
||||
func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
// Defaults
|
||||
if config.Skipper == nil {
|
||||
@ -80,7 +132,9 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
if len(config.AllowOrigins) == 0 {
|
||||
config.AllowOrigins = DefaultCORSConfig.AllowOrigins
|
||||
}
|
||||
hasCustomAllowMethods := true
|
||||
if len(config.AllowMethods) == 0 {
|
||||
hasCustomAllowMethods = false
|
||||
config.AllowMethods = DefaultCORSConfig.AllowMethods
|
||||
}
|
||||
|
||||
@ -109,10 +163,28 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
origin := req.Header.Get(echo.HeaderOrigin)
|
||||
allowOrigin := ""
|
||||
|
||||
preflight := req.Method == http.MethodOptions
|
||||
res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
|
||||
|
||||
// No Origin provided
|
||||
// Preflight request is an OPTIONS request, using three HTTP request headers: Access-Control-Request-Method,
|
||||
// Access-Control-Request-Headers, and the Origin header. See: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
|
||||
// For simplicity we just consider method type and later `Origin` header.
|
||||
preflight := req.Method == http.MethodOptions
|
||||
|
||||
// Although router adds special handler in case of OPTIONS method we avoid calling next for OPTIONS in this middleware
|
||||
// as CORS requests do not have cookies / authentication headers by default, so we could get stuck in auth
|
||||
// middlewares by calling next(c).
|
||||
// But we still want to send `Allow` header as response in case of Non-CORS OPTIONS request as router default
|
||||
// handler does.
|
||||
routerAllowMethods := ""
|
||||
if preflight {
|
||||
tmpAllowMethods, ok := c.Get(echo.ContextKeyHeaderAllow).(string)
|
||||
if ok && tmpAllowMethods != "" {
|
||||
routerAllowMethods = tmpAllowMethods
|
||||
c.Response().Header().Set(echo.HeaderAllow, routerAllowMethods)
|
||||
}
|
||||
}
|
||||
|
||||
// No Origin provided. This is (probably) not request from actual browser - proceed executing middleware chain
|
||||
if origin == "" {
|
||||
if !preflight {
|
||||
return next(c)
|
||||
@ -145,19 +217,15 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// Check allowed origin patterns
|
||||
for _, re := range allowOriginPatterns {
|
||||
checkPatterns := false
|
||||
if allowOrigin == "" {
|
||||
didx := strings.Index(origin, "://")
|
||||
if didx == -1 {
|
||||
continue
|
||||
// to avoid regex cost by invalid (long) domains (253 is domain name max limit)
|
||||
if len(origin) <= (253+3+5) && strings.Contains(origin, "://") {
|
||||
checkPatterns = true
|
||||
}
|
||||
domAuth := origin[didx+3:]
|
||||
// to avoid regex cost by invalid long domain
|
||||
if len(domAuth) > 253 {
|
||||
break
|
||||
}
|
||||
|
||||
if checkPatterns {
|
||||
for _, re := range allowOriginPatterns {
|
||||
if match, _ := regexp.MatchString(re, origin); match {
|
||||
allowOrigin = origin
|
||||
break
|
||||
@ -174,12 +242,13 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// Simple request
|
||||
if !preflight {
|
||||
res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
|
||||
if config.AllowCredentials {
|
||||
res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
|
||||
}
|
||||
|
||||
// Simple request
|
||||
if !preflight {
|
||||
if exposeHeaders != "" {
|
||||
res.Header().Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
|
||||
}
|
||||
@ -189,11 +258,13 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
||||
// Preflight request
|
||||
res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
|
||||
res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
|
||||
res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
|
||||
|
||||
if !hasCustomAllowMethods && routerAllowMethods != "" {
|
||||
res.Header().Set(echo.HeaderAccessControlAllowMethods, routerAllowMethods)
|
||||
} else {
|
||||
res.Header().Set(echo.HeaderAccessControlAllowMethods, allowMethods)
|
||||
if config.AllowCredentials {
|
||||
res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
|
||||
}
|
||||
|
||||
if allowHeaders != "" {
|
||||
res.Header().Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
|
||||
} else {
|
||||
|
120
vendor/github.com/labstack/echo/v4/middleware/csrf.go
generated
vendored
120
vendor/github.com/labstack/echo/v4/middleware/csrf.go
generated
vendored
@ -2,9 +2,7 @@ package middleware
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
@ -21,13 +19,15 @@ type (
|
||||
TokenLength uint8 `yaml:"token_length"`
|
||||
// Optional. Default value 32.
|
||||
|
||||
// TokenLookup is a string in the form of "<source>:<key>" that is used
|
||||
// TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
|
||||
// to extract token from the request.
|
||||
// Optional. Default value "header:X-CSRF-Token".
|
||||
// Possible values:
|
||||
// - "header:<name>"
|
||||
// - "form:<name>"
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// - "query:<name>"
|
||||
// - "form:<name>"
|
||||
// Multiple sources example:
|
||||
// - "header:X-CSRF-Token,query:csrf"
|
||||
TokenLookup string `yaml:"token_lookup"`
|
||||
|
||||
// Context key to store generated CSRF token into context.
|
||||
@ -61,13 +61,18 @@ type (
|
||||
// Indicates SameSite mode of the CSRF cookie.
|
||||
// Optional. Default value SameSiteDefaultMode.
|
||||
CookieSameSite http.SameSite `yaml:"cookie_same_site"`
|
||||
|
||||
// ErrorHandler defines a function which is executed for returning custom errors.
|
||||
ErrorHandler CSRFErrorHandler
|
||||
}
|
||||
|
||||
// csrfTokenExtractor defines a function that takes `echo.Context` and returns
|
||||
// either a token or an error.
|
||||
csrfTokenExtractor func(echo.Context) (string, error)
|
||||
// CSRFErrorHandler is a function which is executed for creating custom errors.
|
||||
CSRFErrorHandler func(err error, c echo.Context) error
|
||||
)
|
||||
|
||||
// ErrCSRFInvalid is returned when CSRF check fails
|
||||
var ErrCSRFInvalid = echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
|
||||
|
||||
var (
|
||||
// DefaultCSRFConfig is the default CSRF middleware config.
|
||||
DefaultCSRFConfig = CSRFConfig{
|
||||
@ -114,14 +119,9 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
|
||||
config.CookieSecure = true
|
||||
}
|
||||
|
||||
// Initialize
|
||||
parts := strings.Split(config.TokenLookup, ":")
|
||||
extractor := csrfTokenFromHeader(parts[1])
|
||||
switch parts[0] {
|
||||
case "form":
|
||||
extractor = csrfTokenFromForm(parts[1])
|
||||
case "query":
|
||||
extractor = csrfTokenFromQuery(parts[1])
|
||||
extractors, err := createExtractors(config.TokenLookup, "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
@ -130,28 +130,58 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
req := c.Request()
|
||||
k, err := c.Cookie(config.CookieName)
|
||||
token := ""
|
||||
|
||||
// Generate token
|
||||
if err != nil {
|
||||
token = random.String(config.TokenLength)
|
||||
if k, err := c.Cookie(config.CookieName); err != nil {
|
||||
token = random.String(config.TokenLength) // Generate token
|
||||
} else {
|
||||
// Reuse token
|
||||
token = k.Value
|
||||
token = k.Value // Reuse token
|
||||
}
|
||||
|
||||
switch req.Method {
|
||||
switch c.Request().Method {
|
||||
case http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodTrace:
|
||||
default:
|
||||
// Validate token only for requests which are not defined as 'safe' by RFC7231
|
||||
clientToken, err := extractor(c)
|
||||
var lastExtractorErr error
|
||||
var lastTokenErr error
|
||||
outer:
|
||||
for _, extractor := range extractors {
|
||||
clientTokens, err := extractor(c)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
||||
lastExtractorErr = err
|
||||
continue
|
||||
}
|
||||
if !validateCSRFToken(token, clientToken) {
|
||||
return echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
|
||||
|
||||
for _, clientToken := range clientTokens {
|
||||
if validateCSRFToken(token, clientToken) {
|
||||
lastTokenErr = nil
|
||||
lastExtractorErr = nil
|
||||
break outer
|
||||
}
|
||||
lastTokenErr = ErrCSRFInvalid
|
||||
}
|
||||
}
|
||||
var finalErr error
|
||||
if lastTokenErr != nil {
|
||||
finalErr = lastTokenErr
|
||||
} else if lastExtractorErr != nil {
|
||||
// ugly part to preserve backwards compatible errors. someone could rely on them
|
||||
if lastExtractorErr == errQueryExtractorValueMissing {
|
||||
lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, "missing csrf token in the query string")
|
||||
} else if lastExtractorErr == errFormExtractorValueMissing {
|
||||
lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, "missing csrf token in the form parameter")
|
||||
} else if lastExtractorErr == errHeaderExtractorValueMissing {
|
||||
lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, "missing csrf token in request header")
|
||||
} else {
|
||||
lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, lastExtractorErr.Error())
|
||||
}
|
||||
finalErr = lastExtractorErr
|
||||
}
|
||||
|
||||
if finalErr != nil {
|
||||
if config.ErrorHandler != nil {
|
||||
return config.ErrorHandler(finalErr, c)
|
||||
}
|
||||
return finalErr
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,38 +214,6 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// csrfTokenFromForm returns a `csrfTokenExtractor` that extracts token from the
|
||||
// provided request header.
|
||||
func csrfTokenFromHeader(header string) csrfTokenExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
return c.Request().Header.Get(header), nil
|
||||
}
|
||||
}
|
||||
|
||||
// csrfTokenFromForm returns a `csrfTokenExtractor` that extracts token from the
|
||||
// provided form parameter.
|
||||
func csrfTokenFromForm(param string) csrfTokenExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
token := c.FormValue(param)
|
||||
if token == "" {
|
||||
return "", errors.New("missing csrf token in the form parameter")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
// csrfTokenFromQuery returns a `csrfTokenExtractor` that extracts token from the
|
||||
// provided query parameter.
|
||||
func csrfTokenFromQuery(param string) csrfTokenExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
token := c.QueryParam(param)
|
||||
if token == "" {
|
||||
return "", errors.New("missing csrf token in the query string")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
func validateCSRFToken(token, clientToken string) bool {
|
||||
return subtle.ConstantTimeCompare([]byte(token), []byte(clientToken)) == 1
|
||||
}
|
||||
|
49
vendor/github.com/labstack/echo/v4/middleware/decompress.go
generated
vendored
49
vendor/github.com/labstack/echo/v4/middleware/decompress.go
generated
vendored
@ -1,10 +1,8 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
@ -43,26 +41,7 @@ type DefaultGzipDecompressPool struct {
|
||||
}
|
||||
|
||||
func (d *DefaultGzipDecompressPool) gzipDecompressPool() sync.Pool {
|
||||
return sync.Pool{
|
||||
New: func() interface{} {
|
||||
// create with an empty reader (but with GZIP header)
|
||||
w, err := gzip.NewWriterLevel(ioutil.Discard, gzip.BestSpeed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
w.Reset(b)
|
||||
w.Flush()
|
||||
w.Close()
|
||||
|
||||
r, err := gzip.NewReader(bytes.NewReader(b.Bytes()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r
|
||||
},
|
||||
}
|
||||
return sync.Pool{New: func() interface{} { return new(gzip.Reader) }}
|
||||
}
|
||||
|
||||
//Decompress decompresses request body based if content encoding type is set to "gzip" with default config
|
||||
@ -82,38 +61,38 @@ func DecompressWithConfig(config DecompressConfig) echo.MiddlewareFunc {
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
pool := config.GzipDecompressPool.gzipDecompressPool()
|
||||
|
||||
return func(c echo.Context) error {
|
||||
if config.Skipper(c) {
|
||||
return next(c)
|
||||
}
|
||||
switch c.Request().Header.Get(echo.HeaderContentEncoding) {
|
||||
case GZIPEncoding:
|
||||
b := c.Request().Body
|
||||
|
||||
if c.Request().Header.Get(echo.HeaderContentEncoding) != GZIPEncoding {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
i := pool.Get()
|
||||
gr, ok := i.(*gzip.Reader)
|
||||
if !ok {
|
||||
if !ok || gr == nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, i.(error).Error())
|
||||
}
|
||||
defer pool.Put(gr)
|
||||
|
||||
b := c.Request().Body
|
||||
defer b.Close()
|
||||
|
||||
if err := gr.Reset(b); err != nil {
|
||||
pool.Put(gr)
|
||||
if err == io.EOF { //ignore if body is empty
|
||||
return next(c)
|
||||
}
|
||||
return err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, gr)
|
||||
|
||||
gr.Close()
|
||||
pool.Put(gr)
|
||||
// only Close gzip reader if it was set to a proper gzip source otherwise it will panic on close.
|
||||
defer gr.Close()
|
||||
|
||||
b.Close() // http.Request.Body is closed by the Server, but because we are replacing it, it must be closed here
|
||||
c.Request().Body = gr
|
||||
|
||||
r := ioutil.NopCloser(&buf)
|
||||
c.Request().Body = r
|
||||
}
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
184
vendor/github.com/labstack/echo/v4/middleware/extractor.go
generated
vendored
Normal file
184
vendor/github.com/labstack/echo/v4/middleware/extractor.go
generated
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/textproto"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// extractorLimit is arbitrary number to limit values extractor can return. this limits possible resource exhaustion
|
||||
// attack vector
|
||||
extractorLimit = 20
|
||||
)
|
||||
|
||||
var errHeaderExtractorValueMissing = errors.New("missing value in request header")
|
||||
var errHeaderExtractorValueInvalid = errors.New("invalid value in request header")
|
||||
var errQueryExtractorValueMissing = errors.New("missing value in the query string")
|
||||
var errParamExtractorValueMissing = errors.New("missing value in path params")
|
||||
var errCookieExtractorValueMissing = errors.New("missing value in cookies")
|
||||
var errFormExtractorValueMissing = errors.New("missing value in the form")
|
||||
|
||||
// ValuesExtractor defines a function for extracting values (keys/tokens) from the given context.
|
||||
type ValuesExtractor func(c echo.Context) ([]string, error)
|
||||
|
||||
func createExtractors(lookups string, authScheme string) ([]ValuesExtractor, error) {
|
||||
if lookups == "" {
|
||||
return nil, nil
|
||||
}
|
||||
sources := strings.Split(lookups, ",")
|
||||
var extractors = make([]ValuesExtractor, 0)
|
||||
for _, source := range sources {
|
||||
parts := strings.Split(source, ":")
|
||||
if len(parts) < 2 {
|
||||
return nil, fmt.Errorf("extractor source for lookup could not be split into needed parts: %v", source)
|
||||
}
|
||||
|
||||
switch parts[0] {
|
||||
case "query":
|
||||
extractors = append(extractors, valuesFromQuery(parts[1]))
|
||||
case "param":
|
||||
extractors = append(extractors, valuesFromParam(parts[1]))
|
||||
case "cookie":
|
||||
extractors = append(extractors, valuesFromCookie(parts[1]))
|
||||
case "form":
|
||||
extractors = append(extractors, valuesFromForm(parts[1]))
|
||||
case "header":
|
||||
prefix := ""
|
||||
if len(parts) > 2 {
|
||||
prefix = parts[2]
|
||||
} else if authScheme != "" && parts[1] == echo.HeaderAuthorization {
|
||||
// backwards compatibility for JWT and KeyAuth:
|
||||
// * we only apply this fix to Authorization as header we use and uses prefixes like "Bearer <token-value>" etc
|
||||
// * previously header extractor assumed that auth-scheme/prefix had a space as suffix we need to retain that
|
||||
// behaviour for default values and Authorization header.
|
||||
prefix = authScheme
|
||||
if !strings.HasSuffix(prefix, " ") {
|
||||
prefix += " "
|
||||
}
|
||||
}
|
||||
extractors = append(extractors, valuesFromHeader(parts[1], prefix))
|
||||
}
|
||||
}
|
||||
return extractors, nil
|
||||
}
|
||||
|
||||
// valuesFromHeader returns a functions that extracts values from the request header.
|
||||
// valuePrefix is parameter to remove first part (prefix) of the extracted value. This is useful if header value has static
|
||||
// prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we want to remove is `<auth-scheme> `
|
||||
// note the space at the end. In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove
|
||||
// is `Basic `. In case of JWT tokens `Authorization: Bearer <token>` prefix is `Bearer `.
|
||||
// If prefix is left empty the whole value is returned.
|
||||
func valuesFromHeader(header string, valuePrefix string) ValuesExtractor {
|
||||
prefixLen := len(valuePrefix)
|
||||
// standard library parses http.Request header keys in canonical form but we may provide something else so fix this
|
||||
header = textproto.CanonicalMIMEHeaderKey(header)
|
||||
return func(c echo.Context) ([]string, error) {
|
||||
values := c.Request().Header.Values(header)
|
||||
if len(values) == 0 {
|
||||
return nil, errHeaderExtractorValueMissing
|
||||
}
|
||||
|
||||
result := make([]string, 0)
|
||||
for i, value := range values {
|
||||
if prefixLen == 0 {
|
||||
result = append(result, value)
|
||||
if i >= extractorLimit-1 {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
if len(value) > prefixLen && strings.EqualFold(value[:prefixLen], valuePrefix) {
|
||||
result = append(result, value[prefixLen:])
|
||||
if i >= extractorLimit-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
if prefixLen > 0 {
|
||||
return nil, errHeaderExtractorValueInvalid
|
||||
}
|
||||
return nil, errHeaderExtractorValueMissing
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
// valuesFromQuery returns a function that extracts values from the query string.
|
||||
func valuesFromQuery(param string) ValuesExtractor {
|
||||
return func(c echo.Context) ([]string, error) {
|
||||
result := c.QueryParams()[param]
|
||||
if len(result) == 0 {
|
||||
return nil, errQueryExtractorValueMissing
|
||||
} else if len(result) > extractorLimit-1 {
|
||||
result = result[:extractorLimit]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
// valuesFromParam returns a function that extracts values from the url param string.
|
||||
func valuesFromParam(param string) ValuesExtractor {
|
||||
return func(c echo.Context) ([]string, error) {
|
||||
result := make([]string, 0)
|
||||
paramVales := c.ParamValues()
|
||||
for i, p := range c.ParamNames() {
|
||||
if param == p {
|
||||
result = append(result, paramVales[i])
|
||||
if i >= extractorLimit-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return nil, errParamExtractorValueMissing
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
// valuesFromCookie returns a function that extracts values from the named cookie.
|
||||
func valuesFromCookie(name string) ValuesExtractor {
|
||||
return func(c echo.Context) ([]string, error) {
|
||||
cookies := c.Cookies()
|
||||
if len(cookies) == 0 {
|
||||
return nil, errCookieExtractorValueMissing
|
||||
}
|
||||
|
||||
result := make([]string, 0)
|
||||
for i, cookie := range cookies {
|
||||
if name == cookie.Name {
|
||||
result = append(result, cookie.Value)
|
||||
if i >= extractorLimit-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return nil, errCookieExtractorValueMissing
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
// valuesFromForm returns a function that extracts values from the form field.
|
||||
func valuesFromForm(name string) ValuesExtractor {
|
||||
return func(c echo.Context) ([]string, error) {
|
||||
if c.Request().Form == nil {
|
||||
_ = c.Request().ParseMultipartForm(32 << 20) // same what `c.Request().FormValue(name)` does
|
||||
}
|
||||
values := c.Request().Form[name]
|
||||
if len(values) == 0 {
|
||||
return nil, errFormExtractorValueMissing
|
||||
}
|
||||
if len(values) > extractorLimit-1 {
|
||||
values = values[:extractorLimit]
|
||||
}
|
||||
result := append([]string{}, values...)
|
||||
return result, nil
|
||||
}
|
||||
}
|
173
vendor/github.com/labstack/echo/v4/middleware/jwt.go
generated
vendored
173
vendor/github.com/labstack/echo/v4/middleware/jwt.go
generated
vendored
@ -1,3 +1,4 @@
|
||||
//go:build go1.15
|
||||
// +build go1.15
|
||||
|
||||
package middleware
|
||||
@ -5,12 +6,10 @@ package middleware
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -22,7 +21,8 @@ type (
|
||||
// BeforeFunc defines a function which is executed just before the middleware.
|
||||
BeforeFunc BeforeFunc
|
||||
|
||||
// SuccessHandler defines a function which is executed for a valid token.
|
||||
// SuccessHandler defines a function which is executed for a valid token before middleware chain continues with next
|
||||
// middleware or handler.
|
||||
SuccessHandler JWTSuccessHandler
|
||||
|
||||
// ErrorHandler defines a function which is executed for an invalid token.
|
||||
@ -32,6 +32,13 @@ type (
|
||||
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
|
||||
ErrorHandlerWithContext JWTErrorHandlerWithContext
|
||||
|
||||
// ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandlerWithContext decides to
|
||||
// ignore the error (by returning `nil`).
|
||||
// This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
|
||||
// In that case you can use ErrorHandlerWithContext to set a default public JWT token value in the request context
|
||||
// and continue. Some logic down the remaining execution chain needs to check that (public) token value then.
|
||||
ContinueOnIgnoredError bool
|
||||
|
||||
// Signing key to validate token.
|
||||
// This is one of the three options to provide a token validation key.
|
||||
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
|
||||
@ -61,16 +68,26 @@ type (
|
||||
// to extract token from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>"
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
|
||||
// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
|
||||
// want to cut is `<auth-scheme> ` note the space at the end.
|
||||
// In case of JWT tokens `Authorization: Bearer <token>` prefix we cut is `Bearer `.
|
||||
// If prefix is left empty the whole value is returned.
|
||||
// - "query:<name>"
|
||||
// - "param:<name>"
|
||||
// - "cookie:<name>"
|
||||
// - "form:<name>"
|
||||
// Multiply sources example:
|
||||
// - "header: Authorization,cookie: myowncookie"
|
||||
|
||||
// Multiple sources example:
|
||||
// - "header:Authorization,cookie:myowncookie"
|
||||
TokenLookup string
|
||||
|
||||
// TokenLookupFuncs defines a list of user-defined functions that extract JWT token from the given context.
|
||||
// This is one of the two options to provide a token extractor.
|
||||
// The order of precedence is user-defined TokenLookupFuncs, and TokenLookup.
|
||||
// You can also provide both if you want.
|
||||
TokenLookupFuncs []ValuesExtractor
|
||||
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default value "Bearer".
|
||||
AuthScheme string
|
||||
@ -95,15 +112,13 @@ type (
|
||||
}
|
||||
|
||||
// JWTSuccessHandler defines a function which is executed for a valid token.
|
||||
JWTSuccessHandler func(echo.Context)
|
||||
JWTSuccessHandler func(c echo.Context)
|
||||
|
||||
// JWTErrorHandler defines a function which is executed for an invalid token.
|
||||
JWTErrorHandler func(error) error
|
||||
JWTErrorHandler func(err error) error
|
||||
|
||||
// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
|
||||
JWTErrorHandlerWithContext func(error, echo.Context) error
|
||||
|
||||
jwtExtractor func(echo.Context) (string, error)
|
||||
JWTErrorHandlerWithContext func(err error, c echo.Context) error
|
||||
)
|
||||
|
||||
// Algorithms
|
||||
@ -124,6 +139,7 @@ var (
|
||||
SigningMethod: AlgorithmHS256,
|
||||
ContextKey: "user",
|
||||
TokenLookup: "header:" + echo.HeaderAuthorization,
|
||||
TokenLookupFuncs: nil,
|
||||
AuthScheme: "Bearer",
|
||||
Claims: jwt.MapClaims{},
|
||||
KeyFunc: nil,
|
||||
@ -163,7 +179,7 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
|
||||
if config.Claims == nil {
|
||||
config.Claims = DefaultJWTConfig.Claims
|
||||
}
|
||||
if config.TokenLookup == "" {
|
||||
if config.TokenLookup == "" && len(config.TokenLookupFuncs) == 0 {
|
||||
config.TokenLookup = DefaultJWTConfig.TokenLookup
|
||||
}
|
||||
if config.AuthScheme == "" {
|
||||
@ -176,25 +192,12 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
|
||||
config.ParseTokenFunc = config.defaultParseToken
|
||||
}
|
||||
|
||||
// Initialize
|
||||
// Split sources
|
||||
sources := strings.Split(config.TokenLookup, ",")
|
||||
var extractors []jwtExtractor
|
||||
for _, source := range sources {
|
||||
parts := strings.Split(source, ":")
|
||||
|
||||
switch parts[0] {
|
||||
case "query":
|
||||
extractors = append(extractors, jwtFromQuery(parts[1]))
|
||||
case "param":
|
||||
extractors = append(extractors, jwtFromParam(parts[1]))
|
||||
case "cookie":
|
||||
extractors = append(extractors, jwtFromCookie(parts[1]))
|
||||
case "form":
|
||||
extractors = append(extractors, jwtFromForm(parts[1]))
|
||||
case "header":
|
||||
extractors = append(extractors, jwtFromHeader(parts[1], config.AuthScheme))
|
||||
extractors, err := createExtractors(config.TokenLookup, config.AuthScheme)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(config.TokenLookupFuncs) > 0 {
|
||||
extractors = append(config.TokenLookupFuncs, extractors...)
|
||||
}
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
@ -206,30 +209,21 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
|
||||
if config.BeforeFunc != nil {
|
||||
config.BeforeFunc(c)
|
||||
}
|
||||
var auth string
|
||||
var err error
|
||||
|
||||
var lastExtractorErr error
|
||||
var lastTokenErr error
|
||||
for _, extractor := range extractors {
|
||||
// Extract token from extractor, if it's not fail break the loop and
|
||||
// set auth
|
||||
auth, err = extractor(c)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
// If none of extractor has a token, handle error
|
||||
auths, err := extractor(c)
|
||||
if err != nil {
|
||||
if config.ErrorHandler != nil {
|
||||
return config.ErrorHandler(err)
|
||||
lastExtractorErr = ErrJWTMissing // backwards compatibility: all extraction errors are same (unlike KeyAuth)
|
||||
continue
|
||||
}
|
||||
|
||||
if config.ErrorHandlerWithContext != nil {
|
||||
return config.ErrorHandlerWithContext(err, c)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
for _, auth := range auths {
|
||||
token, err := config.ParseTokenFunc(auth, c)
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
lastTokenErr = err
|
||||
continue
|
||||
}
|
||||
// Store user information from token into context.
|
||||
c.Set(config.ContextKey, token)
|
||||
if config.SuccessHandler != nil {
|
||||
@ -237,18 +231,33 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
|
||||
}
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
// we are here only when we did not successfully extract or parse any of the tokens
|
||||
err := lastTokenErr
|
||||
if err == nil { // prioritize token errors over extracting errors
|
||||
err = lastExtractorErr
|
||||
}
|
||||
if config.ErrorHandler != nil {
|
||||
return config.ErrorHandler(err)
|
||||
}
|
||||
if config.ErrorHandlerWithContext != nil {
|
||||
return config.ErrorHandlerWithContext(err, c)
|
||||
tmpErr := config.ErrorHandlerWithContext(err, c)
|
||||
if config.ContinueOnIgnoredError && tmpErr == nil {
|
||||
return next(c)
|
||||
}
|
||||
return tmpErr
|
||||
}
|
||||
|
||||
// backwards compatible errors codes
|
||||
if lastTokenErr != nil {
|
||||
return &echo.HTTPError{
|
||||
Code: ErrJWTInvalid.Code,
|
||||
Message: ErrJWTInvalid.Message,
|
||||
Internal: err,
|
||||
}
|
||||
}
|
||||
return err // this is lastExtractorErr value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,59 +298,3 @@ func (config *JWTConfig) defaultKeyFunc(t *jwt.Token) (interface{}, error) {
|
||||
|
||||
return config.SigningKey, nil
|
||||
}
|
||||
|
||||
// jwtFromHeader returns a `jwtExtractor` that extracts token from the request header.
|
||||
func jwtFromHeader(header string, authScheme string) jwtExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
auth := c.Request().Header.Get(header)
|
||||
l := len(authScheme)
|
||||
if len(auth) > l+1 && auth[:l] == authScheme {
|
||||
return auth[l+1:], nil
|
||||
}
|
||||
return "", ErrJWTMissing
|
||||
}
|
||||
}
|
||||
|
||||
// jwtFromQuery returns a `jwtExtractor` that extracts token from the query string.
|
||||
func jwtFromQuery(param string) jwtExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
token := c.QueryParam(param)
|
||||
if token == "" {
|
||||
return "", ErrJWTMissing
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
// jwtFromParam returns a `jwtExtractor` that extracts token from the url param string.
|
||||
func jwtFromParam(param string) jwtExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
token := c.Param(param)
|
||||
if token == "" {
|
||||
return "", ErrJWTMissing
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
// jwtFromCookie returns a `jwtExtractor` that extracts token from the named cookie.
|
||||
func jwtFromCookie(name string) jwtExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
cookie, err := c.Cookie(name)
|
||||
if err != nil {
|
||||
return "", ErrJWTMissing
|
||||
}
|
||||
return cookie.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
// jwtFromForm returns a `jwtExtractor` that extracts token from the form field.
|
||||
func jwtFromForm(name string) jwtExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
field := c.FormValue(name)
|
||||
if field == "" {
|
||||
return "", ErrJWTMissing
|
||||
}
|
||||
return field, nil
|
||||
}
|
||||
}
|
||||
|
166
vendor/github.com/labstack/echo/v4/middleware/key_auth.go
generated
vendored
166
vendor/github.com/labstack/echo/v4/middleware/key_auth.go
generated
vendored
@ -2,10 +2,8 @@ package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -14,14 +12,21 @@ type (
|
||||
// Skipper defines a function to skip middleware.
|
||||
Skipper Skipper
|
||||
|
||||
// KeyLookup is a string in the form of "<source>:<name>" that is used
|
||||
// KeyLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
|
||||
// to extract key from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>"
|
||||
// - "header:<name>" or "header:<name>:<cut-prefix>"
|
||||
// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
|
||||
// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
|
||||
// want to cut is `<auth-scheme> ` note the space at the end.
|
||||
// In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove is `Basic `.
|
||||
// - "query:<name>"
|
||||
// - "form:<name>"
|
||||
KeyLookup string `yaml:"key_lookup"`
|
||||
// - "cookie:<name>"
|
||||
// Multiple sources example:
|
||||
// - "header:Authorization,header:X-Api-Key"
|
||||
KeyLookup string
|
||||
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default value "Bearer".
|
||||
@ -34,15 +39,20 @@ type (
|
||||
// ErrorHandler defines a function which is executed for an invalid key.
|
||||
// It may be used to define a custom error.
|
||||
ErrorHandler KeyAuthErrorHandler
|
||||
|
||||
// ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandler decides to
|
||||
// ignore the error (by returning `nil`).
|
||||
// This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
|
||||
// In that case you can use ErrorHandler to set a default public key auth value in the request context
|
||||
// and continue. Some logic down the remaining execution chain needs to check that (public) key auth value then.
|
||||
ContinueOnIgnoredError bool
|
||||
}
|
||||
|
||||
// KeyAuthValidator defines a function to validate KeyAuth credentials.
|
||||
KeyAuthValidator func(string, echo.Context) (bool, error)
|
||||
|
||||
keyExtractor func(echo.Context) (string, error)
|
||||
KeyAuthValidator func(auth string, c echo.Context) (bool, error)
|
||||
|
||||
// KeyAuthErrorHandler defines a function which is executed for an invalid key.
|
||||
KeyAuthErrorHandler func(error, echo.Context) error
|
||||
KeyAuthErrorHandler func(err error, c echo.Context) error
|
||||
)
|
||||
|
||||
var (
|
||||
@ -54,6 +64,21 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// ErrKeyAuthMissing is error type when KeyAuth middleware is unable to extract value from lookups
|
||||
type ErrKeyAuthMissing struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// Error returns errors text
|
||||
func (e *ErrKeyAuthMissing) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
// Unwrap unwraps error
|
||||
func (e *ErrKeyAuthMissing) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// KeyAuth returns an KeyAuth middleware.
|
||||
//
|
||||
// For valid key it calls the next handler.
|
||||
@ -83,14 +108,9 @@ func KeyAuthWithConfig(config KeyAuthConfig) echo.MiddlewareFunc {
|
||||
panic("echo: key-auth middleware requires a validator function")
|
||||
}
|
||||
|
||||
// Initialize
|
||||
parts := strings.Split(config.KeyLookup, ":")
|
||||
extractor := keyFromHeader(parts[1], config.AuthScheme)
|
||||
switch parts[0] {
|
||||
case "query":
|
||||
extractor = keyFromQuery(parts[1])
|
||||
case "form":
|
||||
extractor = keyFromForm(parts[1])
|
||||
extractors, err := createExtractors(config.KeyLookup, config.AuthScheme)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
@ -99,68 +119,62 @@ func KeyAuthWithConfig(config KeyAuthConfig) echo.MiddlewareFunc {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
// Extract and verify key
|
||||
key, err := extractor(c)
|
||||
var lastExtractorErr error
|
||||
var lastValidatorErr error
|
||||
for _, extractor := range extractors {
|
||||
keys, err := extractor(c)
|
||||
if err != nil {
|
||||
lastExtractorErr = err
|
||||
continue
|
||||
}
|
||||
for _, key := range keys {
|
||||
valid, err := config.Validator(key, c)
|
||||
if err != nil {
|
||||
lastValidatorErr = err
|
||||
continue
|
||||
}
|
||||
if valid {
|
||||
return next(c)
|
||||
}
|
||||
lastValidatorErr = errors.New("invalid key")
|
||||
}
|
||||
}
|
||||
|
||||
// we are here only when we did not successfully extract and validate any of keys
|
||||
err := lastValidatorErr
|
||||
if err == nil { // prioritize validator errors over extracting errors
|
||||
// ugly part to preserve backwards compatible errors. someone could rely on them
|
||||
if lastExtractorErr == errQueryExtractorValueMissing {
|
||||
err = errors.New("missing key in the query string")
|
||||
} else if lastExtractorErr == errCookieExtractorValueMissing {
|
||||
err = errors.New("missing key in cookies")
|
||||
} else if lastExtractorErr == errFormExtractorValueMissing {
|
||||
err = errors.New("missing key in the form")
|
||||
} else if lastExtractorErr == errHeaderExtractorValueMissing {
|
||||
err = errors.New("missing key in request header")
|
||||
} else if lastExtractorErr == errHeaderExtractorValueInvalid {
|
||||
err = errors.New("invalid key in the request header")
|
||||
} else {
|
||||
err = lastExtractorErr
|
||||
}
|
||||
err = &ErrKeyAuthMissing{Err: err}
|
||||
}
|
||||
|
||||
if config.ErrorHandler != nil {
|
||||
return config.ErrorHandler(err, c)
|
||||
tmpErr := config.ErrorHandler(err, c)
|
||||
if config.ContinueOnIgnoredError && tmpErr == nil {
|
||||
return next(c)
|
||||
}
|
||||
return tmpErr
|
||||
}
|
||||
if lastValidatorErr != nil { // prioritize validator errors over extracting errors
|
||||
return &echo.HTTPError{
|
||||
Code: http.StatusUnauthorized,
|
||||
Message: "Unauthorized",
|
||||
Internal: lastValidatorErr,
|
||||
}
|
||||
}
|
||||
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
valid, err := config.Validator(key, c)
|
||||
if err != nil {
|
||||
if config.ErrorHandler != nil {
|
||||
return config.ErrorHandler(err, c)
|
||||
}
|
||||
return &echo.HTTPError{
|
||||
Code: http.StatusUnauthorized,
|
||||
Message: "invalid key",
|
||||
Internal: err,
|
||||
}
|
||||
} else if valid {
|
||||
return next(c)
|
||||
}
|
||||
return echo.ErrUnauthorized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromHeader returns a `keyExtractor` that extracts key from the request header.
|
||||
func keyFromHeader(header string, authScheme string) keyExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
auth := c.Request().Header.Get(header)
|
||||
if auth == "" {
|
||||
return "", errors.New("missing key in request header")
|
||||
}
|
||||
if header == echo.HeaderAuthorization {
|
||||
l := len(authScheme)
|
||||
if len(auth) > l+1 && auth[:l] == authScheme {
|
||||
return auth[l+1:], nil
|
||||
}
|
||||
return "", errors.New("invalid key in the request header")
|
||||
}
|
||||
return auth, nil
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromQuery returns a `keyExtractor` that extracts key from the query string.
|
||||
func keyFromQuery(param string) keyExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
key := c.QueryParam(param)
|
||||
if key == "" {
|
||||
return "", errors.New("missing key in the query string")
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromForm returns a `keyExtractor` that extracts key from the form.
|
||||
func keyFromForm(param string) keyExtractor {
|
||||
return func(c echo.Context) (string, error) {
|
||||
key := c.FormValue(param)
|
||||
if key == "" {
|
||||
return "", errors.New("missing key in the form")
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
|
8
vendor/github.com/labstack/echo/v4/middleware/logger.go
generated
vendored
8
vendor/github.com/labstack/echo/v4/middleware/logger.go
generated
vendored
@ -23,6 +23,8 @@ type (
|
||||
// Tags to construct the logger format.
|
||||
//
|
||||
// - time_unix
|
||||
// - time_unix_milli
|
||||
// - time_unix_micro
|
||||
// - time_unix_nano
|
||||
// - time_rfc3339
|
||||
// - time_rfc3339_nano
|
||||
@ -126,6 +128,12 @@ func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
|
||||
switch tag {
|
||||
case "time_unix":
|
||||
return buf.WriteString(strconv.FormatInt(time.Now().Unix(), 10))
|
||||
case "time_unix_milli":
|
||||
// go 1.17 or later, it supports time#UnixMilli()
|
||||
return buf.WriteString(strconv.FormatInt(time.Now().UnixNano()/1000000, 10))
|
||||
case "time_unix_micro":
|
||||
// go 1.17 or later, it supports time#UnixMicro()
|
||||
return buf.WriteString(strconv.FormatInt(time.Now().UnixNano()/1000, 10))
|
||||
case "time_unix_nano":
|
||||
return buf.WriteString(strconv.FormatInt(time.Now().UnixNano(), 10))
|
||||
case "time_rfc3339":
|
||||
|
4
vendor/github.com/labstack/echo/v4/middleware/middleware.go
generated
vendored
4
vendor/github.com/labstack/echo/v4/middleware/middleware.go
generated
vendored
@ -12,10 +12,10 @@ import (
|
||||
type (
|
||||
// Skipper defines a function to skip middleware. Returning true skips processing
|
||||
// the middleware.
|
||||
Skipper func(echo.Context) bool
|
||||
Skipper func(c echo.Context) bool
|
||||
|
||||
// BeforeFunc defines a function which is executed just before the middleware.
|
||||
BeforeFunc func(echo.Context)
|
||||
BeforeFunc func(c echo.Context)
|
||||
)
|
||||
|
||||
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
|
||||
|
9
vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
generated
vendored
9
vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
generated
vendored
@ -155,7 +155,8 @@ type (
|
||||
RateLimiterMemoryStore struct {
|
||||
visitors map[string]*Visitor
|
||||
mutex sync.Mutex
|
||||
rate rate.Limit
|
||||
rate rate.Limit //for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
|
||||
|
||||
burst int
|
||||
expiresIn time.Duration
|
||||
lastCleanup time.Time
|
||||
@ -170,6 +171,8 @@ type (
|
||||
/*
|
||||
NewRateLimiterMemoryStore returns an instance of RateLimiterMemoryStore with
|
||||
the provided rate (as req/s). The provided rate less than 1 will be treated as zero.
|
||||
for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
|
||||
|
||||
Burst and ExpiresIn will be set to default values.
|
||||
|
||||
Example (with 20 requests/sec):
|
||||
@ -199,7 +202,7 @@ Characteristics:
|
||||
Example:
|
||||
|
||||
limiterStore := middleware.NewRateLimiterMemoryStoreWithConfig(
|
||||
middleware.RateLimiterMemoryStoreConfig{Rate: 50, Burst: 200, ExpiresIn: 5 * time.Minutes},
|
||||
middleware.RateLimiterMemoryStoreConfig{Rate: 50, Burst: 200, ExpiresIn: 5 * time.Minute},
|
||||
)
|
||||
*/
|
||||
func NewRateLimiterMemoryStoreWithConfig(config RateLimiterMemoryStoreConfig) (store *RateLimiterMemoryStore) {
|
||||
@ -221,7 +224,7 @@ func NewRateLimiterMemoryStoreWithConfig(config RateLimiterMemoryStoreConfig) (s
|
||||
|
||||
// RateLimiterMemoryStoreConfig represents configuration for RateLimiterMemoryStore
|
||||
type RateLimiterMemoryStoreConfig struct {
|
||||
Rate rate.Limit // Rate of requests allowed to pass as req/s
|
||||
Rate rate.Limit // Rate of requests allowed to pass as req/s. For more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
|
||||
Burst int // Burst additionally allows a number of requests to pass when rate limit is reached
|
||||
ExpiresIn time.Duration // ExpiresIn is the duration after that a rate limiter is cleaned up
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user