mirror of
https://github.com/containers/skopeo.git
synced 2025-09-23 02:48:26 +00:00
Vendor after merging mtrmac/image:ParseNormalizedNamed
… and use the master branch of docker/distribution which provides docker/distribution/reference.ParseNormalizedNamed.
This commit is contained in:
51
vendor/github.com/docker/distribution/registry/api/v2/descriptors.go
generated
vendored
51
vendor/github.com/docker/distribution/registry/api/v2/descriptors.go
generated
vendored
@@ -4,9 +4,9 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -175,6 +175,27 @@ var (
|
||||
errcode.ErrorCodeDenied,
|
||||
},
|
||||
}
|
||||
|
||||
tooManyRequestsDescriptor = ResponseDescriptor{
|
||||
Name: "Too Many Requests",
|
||||
StatusCode: http.StatusTooManyRequests,
|
||||
Description: "The client made too many requests within a time interval.",
|
||||
Headers: []ParameterDescriptor{
|
||||
{
|
||||
Name: "Content-Length",
|
||||
Type: "integer",
|
||||
Description: "Length of the JSON response body.",
|
||||
Format: "<length>",
|
||||
},
|
||||
},
|
||||
Body: BodyDescriptor{
|
||||
ContentType: "application/json; charset=utf-8",
|
||||
Format: errorsBody,
|
||||
},
|
||||
ErrorCodes: []errcode.ErrorCode{
|
||||
errcode.ErrorCodeTooManyRequests,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -202,17 +223,6 @@ const (
|
||||
...
|
||||
]
|
||||
}`
|
||||
|
||||
unauthorizedErrorsBody = `{
|
||||
"errors:" [
|
||||
{
|
||||
"code": "UNAUTHORIZED",
|
||||
"message": "access to the requested resource is not authorized",
|
||||
"detail": ...
|
||||
},
|
||||
...
|
||||
]
|
||||
}`
|
||||
)
|
||||
|
||||
// APIDescriptor exports descriptions of the layout of the v2 registry API.
|
||||
@@ -391,6 +401,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
StatusCode: http.StatusNotFound,
|
||||
},
|
||||
unauthorizedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -445,6 +456,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -481,6 +493,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -535,6 +548,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -592,6 +606,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
{
|
||||
Name: "Missing Layer(s)",
|
||||
Description: "One or more layers may be missing during a manifest upload. If so, the missing layers will be enumerated in the error response.",
|
||||
@@ -661,6 +676,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
{
|
||||
Name: "Unknown Manifest",
|
||||
Description: "The specified `name` or `reference` are unknown to the registry and the delete was unable to proceed. Clients can assume the manifest was already deleted if this response is returned.",
|
||||
@@ -769,6 +785,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -843,6 +860,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -909,6 +927,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -993,6 +1012,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1039,6 +1059,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1103,6 +1124,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1175,6 +1197,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1249,6 +1272,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1334,6 +1358,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1424,6 +1449,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1480,6 +1506,7 @@ var routeDescriptors = []RouteDescriptor{
|
||||
unauthorizedResponseDescriptor,
|
||||
repositoryNotFoundResponseDescriptor,
|
||||
deniedResponseDescriptor,
|
||||
tooManyRequestsDescriptor,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
161
vendor/github.com/docker/distribution/registry/api/v2/headerparser.go
generated
vendored
Normal file
161
vendor/github.com/docker/distribution/registry/api/v2/headerparser.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var (
|
||||
// according to rfc7230
|
||||
reToken = regexp.MustCompile(`^[^"(),/:;<=>?@[\]{}[:space:][:cntrl:]]+`)
|
||||
reQuotedValue = regexp.MustCompile(`^[^\\"]+`)
|
||||
reEscapedCharacter = regexp.MustCompile(`^[[:blank:][:graph:]]`)
|
||||
)
|
||||
|
||||
// parseForwardedHeader is a benevolent parser of Forwarded header defined in rfc7239. The header contains
|
||||
// a comma-separated list of forwarding key-value pairs. Each list element is set by single proxy. The
|
||||
// function parses only the first element of the list, which is set by the very first proxy. It returns a map
|
||||
// of corresponding key-value pairs and an unparsed slice of the input string.
|
||||
//
|
||||
// Examples of Forwarded header values:
|
||||
//
|
||||
// 1. Forwarded: For=192.0.2.43; Proto=https,For="[2001:db8:cafe::17]",For=unknown
|
||||
// 2. Forwarded: for="192.0.2.43:443"; host="registry.example.org", for="10.10.05.40:80"
|
||||
//
|
||||
// The first will be parsed into {"for": "192.0.2.43", "proto": "https"} while the second into
|
||||
// {"for": "192.0.2.43:443", "host": "registry.example.org"}.
|
||||
func parseForwardedHeader(forwarded string) (map[string]string, string, error) {
|
||||
// Following are states of forwarded header parser. Any state could transition to a failure.
|
||||
const (
|
||||
// terminating state; can transition to Parameter
|
||||
stateElement = iota
|
||||
// terminating state; can transition to KeyValueDelimiter
|
||||
stateParameter
|
||||
// can transition to Value
|
||||
stateKeyValueDelimiter
|
||||
// can transition to one of { QuotedValue, PairEnd }
|
||||
stateValue
|
||||
// can transition to one of { EscapedCharacter, PairEnd }
|
||||
stateQuotedValue
|
||||
// can transition to one of { QuotedValue }
|
||||
stateEscapedCharacter
|
||||
// terminating state; can transition to one of { Parameter, Element }
|
||||
statePairEnd
|
||||
)
|
||||
|
||||
var (
|
||||
parameter string
|
||||
value string
|
||||
parse = forwarded[:]
|
||||
res = map[string]string{}
|
||||
state = stateElement
|
||||
)
|
||||
|
||||
Loop:
|
||||
for {
|
||||
// skip spaces unless in quoted value
|
||||
if state != stateQuotedValue && state != stateEscapedCharacter {
|
||||
parse = strings.TrimLeftFunc(parse, unicode.IsSpace)
|
||||
}
|
||||
|
||||
if len(parse) == 0 {
|
||||
if state != stateElement && state != statePairEnd && state != stateParameter {
|
||||
return nil, parse, fmt.Errorf("unexpected end of input")
|
||||
}
|
||||
// terminating
|
||||
break
|
||||
}
|
||||
|
||||
switch state {
|
||||
// terminate at list element delimiter
|
||||
case stateElement:
|
||||
if parse[0] == ',' {
|
||||
parse = parse[1:]
|
||||
break Loop
|
||||
}
|
||||
state = stateParameter
|
||||
|
||||
// parse parameter (the key of key-value pair)
|
||||
case stateParameter:
|
||||
match := reToken.FindString(parse)
|
||||
if len(match) == 0 {
|
||||
return nil, parse, fmt.Errorf("failed to parse token at position %d", len(forwarded)-len(parse))
|
||||
}
|
||||
parameter = strings.ToLower(match)
|
||||
parse = parse[len(match):]
|
||||
state = stateKeyValueDelimiter
|
||||
|
||||
// parse '='
|
||||
case stateKeyValueDelimiter:
|
||||
if parse[0] != '=' {
|
||||
return nil, parse, fmt.Errorf("expected '=', not '%c' at position %d", parse[0], len(forwarded)-len(parse))
|
||||
}
|
||||
parse = parse[1:]
|
||||
state = stateValue
|
||||
|
||||
// parse value or quoted value
|
||||
case stateValue:
|
||||
if parse[0] == '"' {
|
||||
parse = parse[1:]
|
||||
state = stateQuotedValue
|
||||
} else {
|
||||
value = reToken.FindString(parse)
|
||||
if len(value) == 0 {
|
||||
return nil, parse, fmt.Errorf("failed to parse value at position %d", len(forwarded)-len(parse))
|
||||
}
|
||||
if _, exists := res[parameter]; exists {
|
||||
return nil, parse, fmt.Errorf("duplicate parameter %q at position %d", parameter, len(forwarded)-len(parse))
|
||||
}
|
||||
res[parameter] = value
|
||||
parse = parse[len(value):]
|
||||
value = ""
|
||||
state = statePairEnd
|
||||
}
|
||||
|
||||
// parse a part of quoted value until the first backslash
|
||||
case stateQuotedValue:
|
||||
match := reQuotedValue.FindString(parse)
|
||||
value += match
|
||||
parse = parse[len(match):]
|
||||
switch {
|
||||
case len(parse) == 0:
|
||||
return nil, parse, fmt.Errorf("unterminated quoted string")
|
||||
case parse[0] == '"':
|
||||
res[parameter] = value
|
||||
value = ""
|
||||
parse = parse[1:]
|
||||
state = statePairEnd
|
||||
case parse[0] == '\\':
|
||||
parse = parse[1:]
|
||||
state = stateEscapedCharacter
|
||||
}
|
||||
|
||||
// parse escaped character in a quoted string, ignore the backslash
|
||||
// transition back to QuotedValue state
|
||||
case stateEscapedCharacter:
|
||||
c := reEscapedCharacter.FindString(parse)
|
||||
if len(c) == 0 {
|
||||
return nil, parse, fmt.Errorf("invalid escape sequence at position %d", len(forwarded)-len(parse)-1)
|
||||
}
|
||||
value += c
|
||||
parse = parse[1:]
|
||||
state = stateQuotedValue
|
||||
|
||||
// expect either a new key-value pair, new list or end of input
|
||||
case statePairEnd:
|
||||
switch parse[0] {
|
||||
case ';':
|
||||
parse = parse[1:]
|
||||
state = stateParameter
|
||||
case ',':
|
||||
state = stateElement
|
||||
default:
|
||||
return nil, parse, fmt.Errorf("expected ',' or ';', not %c at position %d", parse[0], len(forwarded)-len(parse))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, parse, nil
|
||||
}
|
67
vendor/github.com/docker/distribution/registry/api/v2/urls.go
generated
vendored
67
vendor/github.com/docker/distribution/registry/api/v2/urls.go
generated
vendored
@@ -1,8 +1,10 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
@@ -49,10 +51,14 @@ func NewURLBuilderFromRequest(r *http.Request, relative bool) *URLBuilder {
|
||||
var scheme string
|
||||
|
||||
forwardedProto := r.Header.Get("X-Forwarded-Proto")
|
||||
// TODO: log the error
|
||||
forwardedHeader, _, _ := parseForwardedHeader(r.Header.Get("Forwarded"))
|
||||
|
||||
switch {
|
||||
case len(forwardedProto) > 0:
|
||||
scheme = forwardedProto
|
||||
case len(forwardedHeader["proto"]) > 0:
|
||||
scheme = forwardedHeader["proto"]
|
||||
case r.TLS != nil:
|
||||
scheme = "https"
|
||||
case len(r.URL.Scheme) > 0:
|
||||
@@ -62,14 +68,46 @@ func NewURLBuilderFromRequest(r *http.Request, relative bool) *URLBuilder {
|
||||
}
|
||||
|
||||
host := r.Host
|
||||
forwardedHost := r.Header.Get("X-Forwarded-Host")
|
||||
if len(forwardedHost) > 0 {
|
||||
|
||||
if forwardedHost := r.Header.Get("X-Forwarded-Host"); len(forwardedHost) > 0 {
|
||||
// According to the Apache mod_proxy docs, X-Forwarded-Host can be a
|
||||
// comma-separated list of hosts, to which each proxy appends the
|
||||
// requested host. We want to grab the first from this comma-separated
|
||||
// list.
|
||||
hosts := strings.SplitN(forwardedHost, ",", 2)
|
||||
host = strings.TrimSpace(hosts[0])
|
||||
} else if addr, exists := forwardedHeader["for"]; exists {
|
||||
host = addr
|
||||
} else if h, exists := forwardedHeader["host"]; exists {
|
||||
host = h
|
||||
}
|
||||
|
||||
portLessHost, port := host, ""
|
||||
if !isIPv6Address(portLessHost) {
|
||||
// with go 1.6, this would treat the last part of IPv6 address as a port
|
||||
portLessHost, port, _ = net.SplitHostPort(host)
|
||||
}
|
||||
if forwardedPort := r.Header.Get("X-Forwarded-Port"); len(port) == 0 && len(forwardedPort) > 0 {
|
||||
ports := strings.SplitN(forwardedPort, ",", 2)
|
||||
forwardedPort = strings.TrimSpace(ports[0])
|
||||
if _, err := strconv.ParseInt(forwardedPort, 10, 32); err == nil {
|
||||
port = forwardedPort
|
||||
}
|
||||
}
|
||||
|
||||
if len(portLessHost) > 0 {
|
||||
host = portLessHost
|
||||
}
|
||||
if len(port) > 0 {
|
||||
// remove enclosing brackets of ipv6 address otherwise they will be duplicated
|
||||
if len(host) > 1 && host[0] == '[' && host[len(host)-1] == ']' {
|
||||
host = host[1 : len(host)-1]
|
||||
}
|
||||
// JoinHostPort properly encloses ipv6 addresses in square brackets
|
||||
host = net.JoinHostPort(host, port)
|
||||
} else if isIPv6Address(host) && host[0] != '[' {
|
||||
// ipv6 needs to be enclosed in square brackets in urls
|
||||
host = "[" + host + "]"
|
||||
}
|
||||
|
||||
basePath := routeDescriptorsMap[RouteNameBase].Path
|
||||
@@ -249,3 +287,28 @@ func appendValues(u string, values ...url.Values) string {
|
||||
|
||||
return appendValuesURL(up, values...).String()
|
||||
}
|
||||
|
||||
// isIPv6Address returns true if given string is a valid IPv6 address. No port is allowed. The address may be
|
||||
// enclosed in square brackets.
|
||||
func isIPv6Address(host string) bool {
|
||||
if len(host) > 1 && host[0] == '[' && host[len(host)-1] == ']' {
|
||||
host = host[1 : len(host)-1]
|
||||
}
|
||||
// The IPv6 scoped addressing zone identifier starts after the last percent sign.
|
||||
if i := strings.LastIndexByte(host, '%'); i > 0 {
|
||||
host = host[:i]
|
||||
}
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
if ip.To16() == nil {
|
||||
return false
|
||||
}
|
||||
if ip.To4() == nil {
|
||||
return true
|
||||
}
|
||||
// dot can be present in ipv4-mapped address, it needs to come after a colon though
|
||||
i := strings.IndexAny(host, ":.")
|
||||
return i >= 0 && host[i] == ':'
|
||||
}
|
||||
|
Reference in New Issue
Block a user