github.com/TykTechnologies/tyk/internal/httputil
No package summary is available.
Package
Files: 7. Third party imports: 1. Imports from organisation: 0. Tests: 0. Benchmarks: 0.
Constants
const (
headerContentType = "Content-Type"
headerUpgrade = "Upgrade"
headerConnection = "Connection"
)
Vars
CORSHeaders is a list of CORS headers.
var CORSHeaders = []string{
"Access-Control-Allow-Origin",
"Access-Control-Expose-Headers",
"Access-Control-Max-Age",
"Access-Control-Allow-Credentials",
"Access-Control-Allow-Methods",
"Access-Control-Allow-Headers",
}
var DumpRequest = httputil.DumpRequest
var DumpResponse = httputil.DumpResponse
apiLandIDsRegex matches mux-style parameters like {id}.
var apiLangIDsRegex = regexp.MustCompile(`{([^}]+)}`)
routeCache holds the raw routes as they are mapped from mux parameters to regular expressions.
e.g. /foo/{id} becomes ^/foo/([^/]+)$ or similar.
var pathRegexpCache = maps.NewStringMap()
Types
ConnectionWatcher
ConnectionWatcher counts http server connections.
| Field name | Field type | Comment |
|---|---|---|
| n |
|
No comment on field. |
type ConnectionWatcher struct {
n int64
}
Functions
func AuthHeader
AuthHeader will take username and password and return
"Basic " + base64 encoded username:password for use
in an Authorization header.
func AuthHeader(username, password string) string {
toEncode := strings.Join([]string{username, password}, ":")
encodedPass := base64.StdEncoding.EncodeToString([]byte(toEncode))
return fmt.Sprintf("Basic %s", encodedPass)
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func EntityTooLarge
EntityTooLarge responds with HTTP 413 Request Entity Too Large. The function is used for a response when blocking requests by size.
func EntityTooLarge(w http.ResponseWriter, _ *http.Request) {
status := http.StatusRequestEntityTooLarge
http.Error(w, http.StatusText(status), status)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func HasTransferEncoding
HasTransferEncoding returns true if a transfer encoding header is present.
func HasTransferEncoding(req *http.Request) bool {
return TransferEncoding(req) != ""
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func InternalServerError
InternalServerError responds with HTTP 503 Internal Server Error.
func InternalServerError(w http.ResponseWriter, _ *http.Request) {
status := http.StatusInternalServerError
http.Error(w, http.StatusText(status), status)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func IsGrpcStreaming
IsGrpcStreaming returns true if the request designates gRPC streaming.
func IsGrpcStreaming(r *http.Request) bool {
return r.ContentLength == -1 && r.Header.Get(headerContentType) == "application/grpc"
}
Cognitive complexity: 0, Cyclomatic complexity: 2
func IsMuxTemplate
IsMuxTemplate determines if a pattern is a mux template by counting the number of opening and closing braces.
func IsMuxTemplate(pattern string) bool {
openBraces := strings.Count(pattern, "{")
closeBraces := strings.Count(pattern, "}")
return openBraces > 0 && openBraces == closeBraces
}
Cognitive complexity: 0, Cyclomatic complexity: 2
func IsSseStreamingResponse
IsSseStreamingResponse returns true if the response designates SSE streaming.
func IsSseStreamingResponse(r *http.Response) bool {
return r.Header.Get(headerContentType) == "text/event-stream"
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func IsStreamingRequest
IsStreamingRequest returns true if the request designates streaming (gRPC or WebSocket).
func IsStreamingRequest(r *http.Request) bool {
_, upgrade := IsUpgrade(r)
return upgrade || IsGrpcStreaming(r)
}
Cognitive complexity: 0, Cyclomatic complexity: 2
func IsStreamingResponse
IsStreamingResponse returns true if the response designates streaming (SSE).
func IsStreamingResponse(r *http.Response) bool {
return IsSseStreamingResponse(r)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func IsUpgrade
IsUpgrade checks if the request is an upgrade request and returns the upgrade type.
func IsUpgrade(req *http.Request) (string, bool) {
connection := strings.ToLower(strings.TrimSpace(req.Header.Get(headerConnection)))
if connection != "upgrade" {
return "", false
}
upgrade := strings.ToLower(strings.TrimSpace(req.Header.Get(headerUpgrade)))
if upgrade != "" {
return upgrade, true
}
return "", false
}
Cognitive complexity: 4, Cyclomatic complexity: 3
func LengthRequired
LengthRequired responds with HTTP 411 Length Required. The function is used in places where Content-Length is required.
func LengthRequired(w http.ResponseWriter, _ *http.Request) {
status := http.StatusLengthRequired
http.Error(w, http.StatusText(status), status)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func MatchPath
MatchPath matches regexp pattern with request endpoint.
func MatchPath(pattern string, endpoint string) (bool, error) {
if strings.Trim(pattern, "^$") == "" || endpoint == "" {
return false, nil
}
if pattern == endpoint || pattern == "^"+endpoint+"$" {
return true, nil
}
asRegex, err := regexp.Compile(pattern)
if err != nil {
return false, err
}
return asRegex.MatchString(endpoint), nil
}
Cognitive complexity: 6, Cyclomatic complexity: 6
func MatchPaths
MatchPaths matches regexp pattern with multiple request URLs endpoint paths. It will return true if any of them is correctly matched, with no error. If no matches occur, any errors will be retured joined with errors.Join.
func MatchPaths(pattern string, endpoints []string) (bool, error) {
var errs []error
for _, endpoint := range endpoints {
match, err := MatchPath(pattern, endpoint)
if err != nil {
errs = append(errs, err)
continue
}
if match {
return true, nil
}
}
return false, errors.Join(errs...)
}
Cognitive complexity: 7, Cyclomatic complexity: 4
func NewConnectionWatcher
NewConnectionWatcher returns a new *ConnectionWatcher.
func NewConnectionWatcher() *ConnectionWatcher {
return &ConnectionWatcher{}
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func PreparePathRegexp
PreparePathRexep will replace mux-style parameters in input with a compatible regular expression.
Parameters like {id} would be replaced to ([^/]+). If the input pattern provides a starting
or ending delimiters (^ or $), the pattern is returned.
If prefix is true, and pattern starts with /, the returned pattern prefixes a ^ to the regex.
No other prefix matches are possible so only / to ^/ conversion is considered.
If suffix is true, the returned pattern suffixes a $ to the regex.
If both prefix and suffixes are achieved, an explicit match is made.
func PreparePathRegexp(pattern string, prefix bool, suffix bool) string {
// Construct cache key from pattern and flags
key := fmt.Sprintf("%s:%v:%v", pattern, prefix, suffix)
val, ok := pathRegexpCache.Get(key)
if ok {
return val
}
// Replace mux named parameters with regex path match.
if IsMuxTemplate(pattern) {
pattern = apiLangIDsRegex.ReplaceAllString(pattern, `([^/]+)`)
}
// Replace mux wildcard path with a `.*` (match 0 or more characters)
if strings.Contains(pattern, "/*") {
pattern = strings.ReplaceAll(pattern, "/*/", "/[^/]+/")
pattern = strings.ReplaceAll(pattern, "/*", "/.*")
}
// Pattern `/users` becomes `^/users`.
if prefix && strings.HasPrefix(pattern, "/") {
pattern = "^" + pattern
}
// Append $ if necessary to enforce suffix matching.
// Pattern `/users` becomes `/users$`.
// Pattern `^/users` becomes `^/users$`.
if suffix && !strings.HasSuffix(pattern, "$") {
pattern = pattern + "$"
}
// Save cache for following invocations.
pathRegexpCache.Set(key, pattern)
return pattern
}
Cognitive complexity: 9, Cyclomatic complexity: 8
func RemoveResponseTransferEncoding
RemoveResponseTransferEncoding will remove a transfer encoding hint from the response.
func RemoveResponseTransferEncoding(response *http.Response, victim string) {
for i, value := range response.TransferEncoding {
if value == victim {
response.TransferEncoding = append(response.TransferEncoding[:i], response.TransferEncoding[i+1:]...)
}
}
}
Cognitive complexity: 5, Cyclomatic complexity: 3
func StripListenPath
StripListenPath will strip the listenPath from the passed urlPath. If the listenPath contains mux variables, it will trim away the matching pattern with a regular expression that mux provides.
func StripListenPath(listenPath, urlPath string) (res string) {
defer func() {
if !strings.HasPrefix(res, "/") {
res = "/" + res
}
}()
res = urlPath
// early return on the simple case
if strings.HasPrefix(urlPath, listenPath) {
res = strings.TrimPrefix(res, listenPath)
return res
}
if !IsMuxTemplate(listenPath) {
return res
}
tmp := new(mux.Route).PathPrefix(listenPath)
s, err := tmp.GetPathRegexp()
if err != nil {
return res
}
reg := regexp.MustCompile(s)
return reg.ReplaceAllString(res, "")
}
Cognitive complexity: 9, Cyclomatic complexity: 5
func TransferEncoding
TransferEncoding gets the header value from the request.
func TransferEncoding(req *http.Request) string {
for _, val := range req.TransferEncoding {
if val != "" {
return val
}
}
return ""
}
Cognitive complexity: 5, Cyclomatic complexity: 3
func ValidatePath
ValidatePath validates if the path is valid. Returns an error.
func ValidatePath(in string) error {
router := mux.NewRouter()
route := router.PathPrefix(in)
return route.GetError()
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*ConnectionWatcher) Add
Add adds c to the number of active connections.
func (cw *ConnectionWatcher) Add(c int64) {
atomic.AddInt64(&cw.n, c)
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*ConnectionWatcher) Count
Count returns the number of connections at the time the call.
func (cw *ConnectionWatcher) Count() int {
return int(atomic.LoadInt64(&cw.n))
}
Cognitive complexity: 0, Cyclomatic complexity: 1
func (*ConnectionWatcher) OnStateChange
OnStateChange records open connections in response to connection state changes. Set net/http Server.ConnState to this method as value.
func (cw *ConnectionWatcher) OnStateChange(_ net.Conn, state http.ConnState) {
switch state {
case http.StateNew:
cw.Add(1)
case http.StateHijacked, http.StateClosed:
cw.Add(-1)
}
}
Cognitive complexity: 4, Cyclomatic complexity: 4
Tests
Files: 1. Third party imports: 1. Imports from organisation: 0. Tests: 2. Benchmarks: 0.