aboutsummaryrefslogtreecommitdiffstats
path: root/library/go/httputil
diff options
context:
space:
mode:
authorqrort <qrort@yandex-team.com>2022-12-02 11:31:25 +0300
committerqrort <qrort@yandex-team.com>2022-12-02 11:31:25 +0300
commitb1f4ffc9c8abff3ba58dc1ec9a9f92d2f0de6806 (patch)
tree2a23209faf0fea5586a6d4b9cee60d1b318d29fe /library/go/httputil
parent559174a9144de40d6bb3997ea4073c82289b4974 (diff)
downloadydb-b1f4ffc9c8abff3ba58dc1ec9a9f92d2f0de6806.tar.gz
remove kikimr/driver DEPENDS
Diffstat (limited to 'library/go/httputil')
-rw-r--r--library/go/httputil/headers/accept.go259
-rw-r--r--library/go/httputil/headers/authorization.go31
-rw-r--r--library/go/httputil/headers/content.go57
-rw-r--r--library/go/httputil/headers/cookie.go5
-rw-r--r--library/go/httputil/headers/user_agent.go5
-rw-r--r--library/go/httputil/headers/warning.go167
-rw-r--r--library/go/httputil/middleware/tvm/middleware.go91
-rw-r--r--library/go/httputil/middleware/tvm/middleware_opts.go47
8 files changed, 0 insertions, 662 deletions
diff --git a/library/go/httputil/headers/accept.go b/library/go/httputil/headers/accept.go
deleted file mode 100644
index 394bed73600..00000000000
--- a/library/go/httputil/headers/accept.go
+++ /dev/null
@@ -1,259 +0,0 @@
-package headers
-
-import (
- "fmt"
- "sort"
- "strconv"
- "strings"
-)
-
-const (
- AcceptKey = "Accept"
- AcceptEncodingKey = "Accept-Encoding"
-)
-
-type AcceptableEncodings []AcceptableEncoding
-
-type AcceptableEncoding struct {
- Encoding ContentEncoding
- Weight float32
-
- pos int
-}
-
-func (as AcceptableEncodings) IsAcceptable(encoding ContentEncoding) bool {
- for _, ae := range as {
- if ae.Encoding == encoding {
- return ae.Weight != 0
- }
- }
- return false
-}
-
-func (as AcceptableEncodings) String() string {
- if len(as) == 0 {
- return ""
- }
-
- var b strings.Builder
- for i, ae := range as {
- b.WriteString(ae.Encoding.String())
-
- if ae.Weight > 0.0 && ae.Weight < 1.0 {
- b.WriteString(";q=" + strconv.FormatFloat(float64(ae.Weight), 'f', 1, 32))
- }
-
- if i < len(as)-1 {
- b.WriteString(", ")
- }
- }
- return b.String()
-}
-
-type AcceptableTypes []AcceptableType
-
-func (as AcceptableTypes) IsAcceptable(contentType ContentType) bool {
- for _, ae := range as {
- if ae.Type == contentType {
- return ae.Weight != 0
- }
- }
- return false
-}
-
-type AcceptableType struct {
- Type ContentType
- Weight float32
- Extension map[string]string
-
- pos int
-}
-
-func (as AcceptableTypes) String() string {
- if len(as) == 0 {
- return ""
- }
-
- var b strings.Builder
- for i, at := range as {
- b.WriteString(at.Type.String())
-
- if at.Weight > 0.0 && at.Weight < 1.0 {
- b.WriteString(";q=" + strconv.FormatFloat(float64(at.Weight), 'f', 1, 32))
- }
-
- for k, v := range at.Extension {
- b.WriteString(";" + k + "=" + v)
- }
-
- if i < len(as)-1 {
- b.WriteString(", ")
- }
- }
- return b.String()
-}
-
-// ParseAccept parses Accept HTTP header.
-// It will sort acceptable types by weight, specificity and position.
-// See: https://tools.ietf.org/html/rfc2616#section-14.1
-func ParseAccept(headerValue string) (AcceptableTypes, error) {
- if headerValue == "" {
- return nil, nil
- }
-
- parsedValues, err := parseAcceptFamilyHeader(headerValue)
- if err != nil {
- return nil, err
- }
- ah := make(AcceptableTypes, 0, len(parsedValues))
- for _, parsedValue := range parsedValues {
- ah = append(ah, AcceptableType{
- Type: ContentType(parsedValue.Value),
- Weight: parsedValue.Weight,
- Extension: parsedValue.Extension,
- pos: parsedValue.pos,
- })
- }
-
- sort.Slice(ah, func(i, j int) bool {
- // sort by weight only
- if ah[i].Weight != ah[j].Weight {
- return ah[i].Weight > ah[j].Weight
- }
-
- // sort by most specific if types are equal
- if ah[i].Type == ah[j].Type {
- return len(ah[i].Extension) > len(ah[j].Extension)
- }
-
- // move counterpart up if one of types is ANY
- if ah[i].Type == ContentTypeAny {
- return false
- }
- if ah[j].Type == ContentTypeAny {
- return true
- }
-
- // i type has j type as prefix
- if strings.HasSuffix(string(ah[j].Type), "/*") &&
- strings.HasPrefix(string(ah[i].Type), string(ah[j].Type)[:len(ah[j].Type)-1]) {
- return true
- }
-
- // j type has i type as prefix
- if strings.HasSuffix(string(ah[i].Type), "/*") &&
- strings.HasPrefix(string(ah[j].Type), string(ah[i].Type)[:len(ah[i].Type)-1]) {
- return false
- }
-
- // sort by position if nothing else left
- return ah[i].pos < ah[j].pos
- })
-
- return ah, nil
-}
-
-// ParseAcceptEncoding parses Accept-Encoding HTTP header.
-// It will sort acceptable encodings by weight and position.
-// See: https://tools.ietf.org/html/rfc2616#section-14.3
-func ParseAcceptEncoding(headerValue string) (AcceptableEncodings, error) {
- if headerValue == "" {
- return nil, nil
- }
-
- // e.g. gzip;q=1.0, compress, identity
- parsedValues, err := parseAcceptFamilyHeader(headerValue)
- if err != nil {
- return nil, err
- }
- acceptableEncodings := make(AcceptableEncodings, 0, len(parsedValues))
- for _, parsedValue := range parsedValues {
- acceptableEncodings = append(acceptableEncodings, AcceptableEncoding{
- Encoding: ContentEncoding(parsedValue.Value),
- Weight: parsedValue.Weight,
- pos: parsedValue.pos,
- })
- }
- sort.Slice(acceptableEncodings, func(i, j int) bool {
- // sort by weight only
- if acceptableEncodings[i].Weight != acceptableEncodings[j].Weight {
- return acceptableEncodings[i].Weight > acceptableEncodings[j].Weight
- }
-
- // move counterpart up if one of encodings is ANY
- if acceptableEncodings[i].Encoding == EncodingAny {
- return false
- }
- if acceptableEncodings[j].Encoding == EncodingAny {
- return true
- }
-
- // sort by position if nothing else left
- return acceptableEncodings[i].pos < acceptableEncodings[j].pos
- })
-
- return acceptableEncodings, nil
-}
-
-type acceptHeaderValue struct {
- Value string
- Weight float32
- Extension map[string]string
-
- pos int
-}
-
-// parseAcceptFamilyHeader parses family of Accept* HTTP headers
-// See: https://tools.ietf.org/html/rfc2616#section-14.1
-func parseAcceptFamilyHeader(header string) ([]acceptHeaderValue, error) {
- headerValues := strings.Split(header, ",")
-
- parsedValues := make([]acceptHeaderValue, 0, len(headerValues))
- for i, headerValue := range headerValues {
- valueParams := strings.Split(headerValue, ";")
-
- parsedValue := acceptHeaderValue{
- Value: strings.TrimSpace(valueParams[0]),
- Weight: 1.0,
- pos: i,
- }
-
- // parse quality factor and/or accept extension
- if len(valueParams) > 1 {
- for _, rawParam := range valueParams[1:] {
- rawParam = strings.TrimSpace(rawParam)
- params := strings.SplitN(rawParam, "=", 2)
- key := strings.TrimSpace(params[0])
-
- // quality factor
- if key == "q" {
- if len(params) != 2 {
- return nil, fmt.Errorf("invalid quality factor format: %q", rawParam)
- }
-
- w, err := strconv.ParseFloat(params[1], 32)
- if err != nil {
- return nil, err
- }
- parsedValue.Weight = float32(w)
-
- continue
- }
-
- // extension
- if parsedValue.Extension == nil {
- parsedValue.Extension = make(map[string]string)
- }
-
- var value string
- if len(params) == 2 {
- value = strings.TrimSpace(params[1])
- }
- parsedValue.Extension[key] = value
- }
- }
-
- parsedValues = append(parsedValues, parsedValue)
- }
- return parsedValues, nil
-}
diff --git a/library/go/httputil/headers/authorization.go b/library/go/httputil/headers/authorization.go
deleted file mode 100644
index 145e04f9312..00000000000
--- a/library/go/httputil/headers/authorization.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package headers
-
-import "strings"
-
-const (
- AuthorizationKey = "Authorization"
-
- TokenTypeBearer TokenType = "bearer"
- TokenTypeMAC TokenType = "mac"
-)
-
-type TokenType string
-
-// String implements stringer interface
-func (tt TokenType) String() string {
- return string(tt)
-}
-
-func AuthorizationTokenType(token string) TokenType {
- if len(token) > len(TokenTypeBearer) &&
- strings.ToLower(token[:len(TokenTypeBearer)]) == TokenTypeBearer.String() {
- return TokenTypeBearer
- }
-
- if len(token) > len(TokenTypeMAC) &&
- strings.ToLower(token[:len(TokenTypeMAC)]) == TokenTypeMAC.String() {
- return TokenTypeMAC
- }
-
- return TokenType("unknown")
-}
diff --git a/library/go/httputil/headers/content.go b/library/go/httputil/headers/content.go
deleted file mode 100644
index b92e013cc32..00000000000
--- a/library/go/httputil/headers/content.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package headers
-
-type ContentType string
-
-// String implements stringer interface
-func (ct ContentType) String() string {
- return string(ct)
-}
-
-type ContentEncoding string
-
-// String implements stringer interface
-func (ce ContentEncoding) String() string {
- return string(ce)
-}
-
-const (
- ContentTypeKey = "Content-Type"
- ContentLength = "Content-Length"
- ContentEncodingKey = "Content-Encoding"
-
- ContentTypeAny ContentType = "*/*"
-
- TypeApplicationJSON ContentType = "application/json"
- TypeApplicationXML ContentType = "application/xml"
- TypeApplicationOctetStream ContentType = "application/octet-stream"
- TypeApplicationProtobuf ContentType = "application/protobuf"
- TypeApplicationMsgpack ContentType = "application/msgpack"
- TypeApplicationXSolomonSpack ContentType = "application/x-solomon-spack"
-
- EncodingAny ContentEncoding = "*"
- EncodingZSTD ContentEncoding = "zstd"
- EncodingLZ4 ContentEncoding = "lz4"
- EncodingGZIP ContentEncoding = "gzip"
- EncodingDeflate ContentEncoding = "deflate"
-
- TypeTextPlain ContentType = "text/plain"
- TypeTextHTML ContentType = "text/html"
- TypeTextCSV ContentType = "text/csv"
- TypeTextCmd ContentType = "text/cmd"
- TypeTextCSS ContentType = "text/css"
- TypeTextXML ContentType = "text/xml"
- TypeTextMarkdown ContentType = "text/markdown"
-
- TypeImageAny ContentType = "image/*"
- TypeImageJPEG ContentType = "image/jpeg"
- TypeImageGIF ContentType = "image/gif"
- TypeImagePNG ContentType = "image/png"
- TypeImageSVG ContentType = "image/svg+xml"
- TypeImageTIFF ContentType = "image/tiff"
- TypeImageWebP ContentType = "image/webp"
-
- TypeVideoMPEG ContentType = "video/mpeg"
- TypeVideoMP4 ContentType = "video/mp4"
- TypeVideoOgg ContentType = "video/ogg"
- TypeVideoWebM ContentType = "video/webm"
-)
diff --git a/library/go/httputil/headers/cookie.go b/library/go/httputil/headers/cookie.go
deleted file mode 100644
index bcc685c4740..00000000000
--- a/library/go/httputil/headers/cookie.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package headers
-
-const (
- CookieKey = "Cookie"
-)
diff --git a/library/go/httputil/headers/user_agent.go b/library/go/httputil/headers/user_agent.go
deleted file mode 100644
index 366606a01dc..00000000000
--- a/library/go/httputil/headers/user_agent.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package headers
-
-const (
- UserAgentKey = "User-Agent"
-)
diff --git a/library/go/httputil/headers/warning.go b/library/go/httputil/headers/warning.go
deleted file mode 100644
index 2013fdf08dd..00000000000
--- a/library/go/httputil/headers/warning.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package headers
-
-import (
- "errors"
- "net/http"
- "strconv"
- "strings"
- "time"
-
- "a.yandex-team.ru/library/go/core/xerrors"
-)
-
-const (
- WarningKey = "Warning"
-
- WarningResponseIsStale = 110 // RFC 7234, 5.5.1
- WarningRevalidationFailed = 111 // RFC 7234, 5.5.2
- WarningDisconnectedOperation = 112 // RFC 7234, 5.5.3
- WarningHeuristicExpiration = 113 // RFC 7234, 5.5.4
- WarningMiscellaneousWarning = 199 // RFC 7234, 5.5.5
- WarningTransformationApplied = 214 // RFC 7234, 5.5.6
- WarningMiscellaneousPersistentWarning = 299 // RFC 7234, 5.5.7
-)
-
-var warningStatusText = map[int]string{
- WarningResponseIsStale: "Response is Stale",
- WarningRevalidationFailed: "Revalidation Failed",
- WarningDisconnectedOperation: "Disconnected Operation",
- WarningHeuristicExpiration: "Heuristic Expiration",
- WarningMiscellaneousWarning: "Miscellaneous Warning",
- WarningTransformationApplied: "Transformation Applied",
- WarningMiscellaneousPersistentWarning: "Miscellaneous Persistent Warning",
-}
-
-// WarningText returns a text for the warning header code. It returns the empty
-// string if the code is unknown.
-func WarningText(warn int) string {
- return warningStatusText[warn]
-}
-
-// AddWarning adds Warning to http.Header with proper formatting
-// see: https://tools.ietf.org/html/rfc7234#section-5.5
-func AddWarning(h http.Header, warn int, agent, reason string, date time.Time) {
- values := make([]string, 0, 4)
- values = append(values, strconv.Itoa(warn))
-
- if agent != "" {
- values = append(values, agent)
- } else {
- values = append(values, "-")
- }
-
- if reason != "" {
- values = append(values, strconv.Quote(reason))
- }
-
- if !date.IsZero() {
- values = append(values, strconv.Quote(date.Format(time.RFC1123)))
- }
-
- h.Add(WarningKey, strings.Join(values, " "))
-}
-
-type WarningHeader struct {
- Code int
- Agent string
- Reason string
- Date time.Time
-}
-
-// ParseWarnings reads and parses Warning headers from http.Header
-func ParseWarnings(h http.Header) ([]WarningHeader, error) {
- warnings, ok := h[WarningKey]
- if !ok {
- return nil, nil
- }
-
- res := make([]WarningHeader, 0, len(warnings))
- for _, warn := range warnings {
- wh, err := parseWarning(warn)
- if err != nil {
- return nil, xerrors.Errorf("cannot parse '%s' header: %w", warn, err)
- }
- res = append(res, wh)
- }
-
- return res, nil
-}
-
-func parseWarning(warn string) (WarningHeader, error) {
- var res WarningHeader
-
- // parse code
- {
- codeSP := strings.Index(warn, " ")
-
- // fast path - code only warning
- if codeSP == -1 {
- code, err := strconv.Atoi(warn)
- res.Code = code
- return res, err
- }
-
- code, err := strconv.Atoi(warn[:codeSP])
- if err != nil {
- return WarningHeader{}, err
- }
- res.Code = code
-
- warn = strings.TrimSpace(warn[codeSP+1:])
- }
-
- // parse agent
- {
- agentSP := strings.Index(warn, " ")
-
- // fast path - no data after agent
- if agentSP == -1 {
- res.Agent = warn
- return res, nil
- }
-
- res.Agent = warn[:agentSP]
- warn = strings.TrimSpace(warn[agentSP+1:])
- }
-
- // parse reason
- {
- if len(warn) == 0 {
- return res, nil
- }
-
- // reason must by quoted, so we search for second quote
- reasonSP := strings.Index(warn[1:], `"`)
-
- // fast path - bad reason
- if reasonSP == -1 {
- return WarningHeader{}, errors.New("bad reason formatting")
- }
-
- res.Reason = warn[1 : reasonSP+1]
- warn = strings.TrimSpace(warn[reasonSP+2:])
- }
-
- // parse date
- {
- if len(warn) == 0 {
- return res, nil
- }
-
- // optional date must by quoted, so we search for second quote
- dateSP := strings.Index(warn[1:], `"`)
-
- // fast path - bad date
- if dateSP == -1 {
- return WarningHeader{}, errors.New("bad date formatting")
- }
-
- dt, err := time.Parse(time.RFC1123, warn[1:dateSP+1])
- if err != nil {
- return WarningHeader{}, err
- }
- res.Date = dt
- }
-
- return res, nil
-}
diff --git a/library/go/httputil/middleware/tvm/middleware.go b/library/go/httputil/middleware/tvm/middleware.go
deleted file mode 100644
index cbcf1aae1d4..00000000000
--- a/library/go/httputil/middleware/tvm/middleware.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package tvm
-
-import (
- "context"
- "net/http"
-
- "golang.org/x/xerrors"
-
- "a.yandex-team.ru/library/go/core/log"
- "a.yandex-team.ru/library/go/core/log/ctxlog"
- "a.yandex-team.ru/library/go/core/log/nop"
- "a.yandex-team.ru/library/go/yandex/tvm"
-)
-
-const (
- // XYaServiceTicket is http header that should be used for service ticket transfer.
- XYaServiceTicket = "X-Ya-Service-Ticket"
- // XYaUserTicket is http header that should be used for user ticket transfer.
- XYaUserTicket = "X-Ya-User-Ticket"
-)
-
-type (
- MiddlewareOption func(*middleware)
-
- middleware struct {
- l log.Structured
-
- tvm tvm.Client
-
- authClient func(context.Context, tvm.ClientID) error
-
- onError func(w http.ResponseWriter, r *http.Request, err error)
- }
-)
-
-func defaultErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
- http.Error(w, err.Error(), http.StatusForbidden)
-}
-
-// CheckServiceTicket returns http middleware that validates service tickets for all incoming requests.
-//
-// ServiceTicket is stored on request context. It might be retrieved by calling tvm.ContextServiceTicket.
-func CheckServiceTicket(tvm tvm.Client, opts ...MiddlewareOption) func(next http.Handler) http.Handler {
- m := middleware{
- tvm: tvm,
- onError: defaultErrorHandler,
- }
-
- for _, opt := range opts {
- opt(&m)
- }
-
- if m.authClient == nil {
- panic("must provide authorization policy")
- }
-
- if m.l == nil {
- m.l = &nop.Logger{}
- }
-
- return m.wrap
-}
-
-func (m *middleware) wrap(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- serviceTicket := r.Header.Get(XYaServiceTicket)
- if serviceTicket == "" {
- ctxlog.Error(r.Context(), m.l.Logger(), "missing service ticket")
- m.onError(w, r, xerrors.New("missing service ticket"))
- return
- }
-
- ticket, err := m.tvm.CheckServiceTicket(r.Context(), serviceTicket)
- if err != nil {
- ctxlog.Error(r.Context(), m.l.Logger(), "service ticket check failed", log.Error(err))
- m.onError(w, r, xerrors.Errorf("service ticket check failed: %w", err))
- return
- }
-
- if err := m.authClient(r.Context(), ticket.SrcID); err != nil {
- ctxlog.Error(r.Context(), m.l.Logger(), "client authorization failed",
- log.String("ticket", ticket.LogInfo),
- log.Error(err))
- m.onError(w, r, xerrors.Errorf("client authorization failed: %w", err))
- return
- }
-
- r = r.WithContext(tvm.WithServiceTicket(r.Context(), ticket))
- next.ServeHTTP(w, r)
- })
-}
diff --git a/library/go/httputil/middleware/tvm/middleware_opts.go b/library/go/httputil/middleware/tvm/middleware_opts.go
deleted file mode 100644
index 86df5d4796e..00000000000
--- a/library/go/httputil/middleware/tvm/middleware_opts.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package tvm
-
-import (
- "context"
- "net/http"
-
- "golang.org/x/xerrors"
-
- "a.yandex-team.ru/library/go/core/log"
- "a.yandex-team.ru/library/go/yandex/tvm"
-)
-
-// WithAllowedClients sets list of allowed clients.
-func WithAllowedClients(allowedClients []tvm.ClientID) MiddlewareOption {
- return func(m *middleware) {
- m.authClient = func(_ context.Context, cid tvm.ClientID) error {
- for _, allowed := range allowedClients {
- if allowed == cid {
- return nil
- }
- }
-
- return xerrors.Errorf("client with tvm_id=%d is not whitelisted", cid)
- }
- }
-}
-
-// WithClientAuth sets custom function for client authorization.
-func WithClientAuth(authClient func(context.Context, tvm.ClientID) error) MiddlewareOption {
- return func(m *middleware) {
- m.authClient = authClient
- }
-}
-
-// WithErrorHandler sets http handler invoked for rejected requests.
-func WithErrorHandler(h func(w http.ResponseWriter, r *http.Request, err error)) MiddlewareOption {
- return func(m *middleware) {
- m.onError = h
- }
-}
-
-// WithLogger sets logger.
-func WithLogger(l log.Structured) MiddlewareOption {
- return func(m *middleware) {
- m.l = l
- }
-}