replace zxq.co/ripple/hanayo
This commit is contained in:
496
vendor/github.com/valyala/fasthttp/uri.go
generated
vendored
Normal file
496
vendor/github.com/valyala/fasthttp/uri.go
generated
vendored
Normal file
@@ -0,0 +1,496 @@
|
||||
package fasthttp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// AcquireURI returns an empty URI instance from the pool.
|
||||
//
|
||||
// Release the URI with ReleaseURI after the URI is no longer needed.
|
||||
// This allows reducing GC load.
|
||||
func AcquireURI() *URI {
|
||||
return uriPool.Get().(*URI)
|
||||
}
|
||||
|
||||
// ReleaseURI releases the URI acquired via AcquireURI.
|
||||
//
|
||||
// The released URI mustn't be used after releasing it, otherwise data races
|
||||
// may occur.
|
||||
func ReleaseURI(u *URI) {
|
||||
u.Reset()
|
||||
uriPool.Put(u)
|
||||
}
|
||||
|
||||
var uriPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &URI{}
|
||||
},
|
||||
}
|
||||
|
||||
// URI represents URI :) .
|
||||
//
|
||||
// It is forbidden copying URI instances. Create new instance and use CopyTo
|
||||
// instead.
|
||||
//
|
||||
// URI instance MUST NOT be used from concurrently running goroutines.
|
||||
type URI struct {
|
||||
noCopy noCopy
|
||||
|
||||
pathOriginal []byte
|
||||
scheme []byte
|
||||
path []byte
|
||||
queryString []byte
|
||||
hash []byte
|
||||
host []byte
|
||||
|
||||
queryArgs Args
|
||||
parsedQueryArgs bool
|
||||
|
||||
fullURI []byte
|
||||
requestURI []byte
|
||||
|
||||
h *RequestHeader
|
||||
}
|
||||
|
||||
// CopyTo copies uri contents to dst.
|
||||
func (u *URI) CopyTo(dst *URI) {
|
||||
dst.Reset()
|
||||
dst.pathOriginal = append(dst.pathOriginal[:0], u.pathOriginal...)
|
||||
dst.scheme = append(dst.scheme[:0], u.scheme...)
|
||||
dst.path = append(dst.path[:0], u.path...)
|
||||
dst.queryString = append(dst.queryString[:0], u.queryString...)
|
||||
dst.hash = append(dst.hash[:0], u.hash...)
|
||||
dst.host = append(dst.host[:0], u.host...)
|
||||
|
||||
u.queryArgs.CopyTo(&dst.queryArgs)
|
||||
dst.parsedQueryArgs = u.parsedQueryArgs
|
||||
|
||||
// fullURI and requestURI shouldn't be copied, since they are created
|
||||
// from scratch on each FullURI() and RequestURI() call.
|
||||
dst.h = u.h
|
||||
}
|
||||
|
||||
// Hash returns URI hash, i.e. qwe of http://aaa.com/foo/bar?baz=123#qwe .
|
||||
//
|
||||
// The returned value is valid until the next URI method call.
|
||||
func (u *URI) Hash() []byte {
|
||||
return u.hash
|
||||
}
|
||||
|
||||
// SetHash sets URI hash.
|
||||
func (u *URI) SetHash(hash string) {
|
||||
u.hash = append(u.hash[:0], hash...)
|
||||
}
|
||||
|
||||
// SetHashBytes sets URI hash.
|
||||
func (u *URI) SetHashBytes(hash []byte) {
|
||||
u.hash = append(u.hash[:0], hash...)
|
||||
}
|
||||
|
||||
// QueryString returns URI query string,
|
||||
// i.e. baz=123 of http://aaa.com/foo/bar?baz=123#qwe .
|
||||
//
|
||||
// The returned value is valid until the next URI method call.
|
||||
func (u *URI) QueryString() []byte {
|
||||
return u.queryString
|
||||
}
|
||||
|
||||
// SetQueryString sets URI query string.
|
||||
func (u *URI) SetQueryString(queryString string) {
|
||||
u.queryString = append(u.queryString[:0], queryString...)
|
||||
u.parsedQueryArgs = false
|
||||
}
|
||||
|
||||
// SetQueryStringBytes sets URI query string.
|
||||
func (u *URI) SetQueryStringBytes(queryString []byte) {
|
||||
u.queryString = append(u.queryString[:0], queryString...)
|
||||
u.parsedQueryArgs = false
|
||||
}
|
||||
|
||||
// Path returns URI path, i.e. /foo/bar of http://aaa.com/foo/bar?baz=123#qwe .
|
||||
//
|
||||
// The returned path is always urldecoded and normalized,
|
||||
// i.e. '//f%20obar/baz/../zzz' becomes '/f obar/zzz'.
|
||||
//
|
||||
// The returned value is valid until the next URI method call.
|
||||
func (u *URI) Path() []byte {
|
||||
path := u.path
|
||||
if len(path) == 0 {
|
||||
path = strSlash
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// SetPath sets URI path.
|
||||
func (u *URI) SetPath(path string) {
|
||||
u.pathOriginal = append(u.pathOriginal[:0], path...)
|
||||
u.path = normalizePath(u.path, u.pathOriginal)
|
||||
}
|
||||
|
||||
// SetPathBytes sets URI path.
|
||||
func (u *URI) SetPathBytes(path []byte) {
|
||||
u.pathOriginal = append(u.pathOriginal[:0], path...)
|
||||
u.path = normalizePath(u.path, u.pathOriginal)
|
||||
}
|
||||
|
||||
// PathOriginal returns the original path from requestURI passed to URI.Parse().
|
||||
//
|
||||
// The returned value is valid until the next URI method call.
|
||||
func (u *URI) PathOriginal() []byte {
|
||||
return u.pathOriginal
|
||||
}
|
||||
|
||||
// Scheme returns URI scheme, i.e. http of http://aaa.com/foo/bar?baz=123#qwe .
|
||||
//
|
||||
// Returned scheme is always lowercased.
|
||||
//
|
||||
// The returned value is valid until the next URI method call.
|
||||
func (u *URI) Scheme() []byte {
|
||||
scheme := u.scheme
|
||||
if len(scheme) == 0 {
|
||||
scheme = strHTTP
|
||||
}
|
||||
return scheme
|
||||
}
|
||||
|
||||
// SetScheme sets URI scheme, i.e. http, https, ftp, etc.
|
||||
func (u *URI) SetScheme(scheme string) {
|
||||
u.scheme = append(u.scheme[:0], scheme...)
|
||||
lowercaseBytes(u.scheme)
|
||||
}
|
||||
|
||||
// SetSchemeBytes sets URI scheme, i.e. http, https, ftp, etc.
|
||||
func (u *URI) SetSchemeBytes(scheme []byte) {
|
||||
u.scheme = append(u.scheme[:0], scheme...)
|
||||
lowercaseBytes(u.scheme)
|
||||
}
|
||||
|
||||
// Reset clears uri.
|
||||
func (u *URI) Reset() {
|
||||
u.pathOriginal = u.pathOriginal[:0]
|
||||
u.scheme = u.scheme[:0]
|
||||
u.path = u.path[:0]
|
||||
u.queryString = u.queryString[:0]
|
||||
u.hash = u.hash[:0]
|
||||
|
||||
u.host = u.host[:0]
|
||||
u.queryArgs.Reset()
|
||||
u.parsedQueryArgs = false
|
||||
|
||||
// There is no need in u.fullURI = u.fullURI[:0], since full uri
|
||||
// is calucalted on each call to FullURI().
|
||||
|
||||
// There is no need in u.requestURI = u.requestURI[:0], since requestURI
|
||||
// is calculated on each call to RequestURI().
|
||||
|
||||
u.h = nil
|
||||
}
|
||||
|
||||
// Host returns host part, i.e. aaa.com of http://aaa.com/foo/bar?baz=123#qwe .
|
||||
//
|
||||
// Host is always lowercased.
|
||||
func (u *URI) Host() []byte {
|
||||
if len(u.host) == 0 && u.h != nil {
|
||||
u.host = append(u.host[:0], u.h.Host()...)
|
||||
lowercaseBytes(u.host)
|
||||
u.h = nil
|
||||
}
|
||||
return u.host
|
||||
}
|
||||
|
||||
// SetHost sets host for the uri.
|
||||
func (u *URI) SetHost(host string) {
|
||||
u.host = append(u.host[:0], host...)
|
||||
lowercaseBytes(u.host)
|
||||
}
|
||||
|
||||
// SetHostBytes sets host for the uri.
|
||||
func (u *URI) SetHostBytes(host []byte) {
|
||||
u.host = append(u.host[:0], host...)
|
||||
lowercaseBytes(u.host)
|
||||
}
|
||||
|
||||
// Parse initializes URI from the given host and uri.
|
||||
func (u *URI) Parse(host, uri []byte) {
|
||||
u.parse(host, uri, nil)
|
||||
}
|
||||
|
||||
func (u *URI) parseQuick(uri []byte, h *RequestHeader) {
|
||||
u.parse(nil, uri, h)
|
||||
}
|
||||
|
||||
func (u *URI) parse(host, uri []byte, h *RequestHeader) {
|
||||
u.Reset()
|
||||
u.h = h
|
||||
|
||||
scheme, host, uri := splitHostURI(host, uri)
|
||||
u.scheme = append(u.scheme, scheme...)
|
||||
lowercaseBytes(u.scheme)
|
||||
u.host = append(u.host, host...)
|
||||
lowercaseBytes(u.host)
|
||||
|
||||
b := uri
|
||||
queryIndex := bytes.IndexByte(b, '?')
|
||||
fragmentIndex := bytes.IndexByte(b, '#')
|
||||
// Ignore query in fragment part
|
||||
if fragmentIndex >= 0 && queryIndex > fragmentIndex {
|
||||
queryIndex = -1
|
||||
}
|
||||
|
||||
if queryIndex < 0 && fragmentIndex < 0 {
|
||||
u.pathOriginal = append(u.pathOriginal, b...)
|
||||
u.path = normalizePath(u.path, u.pathOriginal)
|
||||
return
|
||||
}
|
||||
|
||||
if queryIndex >= 0 {
|
||||
// Path is everything up to the start of the query
|
||||
u.pathOriginal = append(u.pathOriginal, b[:queryIndex]...)
|
||||
u.path = normalizePath(u.path, u.pathOriginal)
|
||||
|
||||
if fragmentIndex < 0 {
|
||||
u.queryString = append(u.queryString, b[queryIndex+1:]...)
|
||||
} else {
|
||||
u.queryString = append(u.queryString, b[queryIndex+1:fragmentIndex]...)
|
||||
u.hash = append(u.hash, b[fragmentIndex+1:]...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// fragmentIndex >= 0 && queryIndex < 0
|
||||
// Path is up to the start of fragment
|
||||
u.pathOriginal = append(u.pathOriginal, b[:fragmentIndex]...)
|
||||
u.path = normalizePath(u.path, u.pathOriginal)
|
||||
u.hash = append(u.hash, b[fragmentIndex+1:]...)
|
||||
}
|
||||
|
||||
func normalizePath(dst, src []byte) []byte {
|
||||
dst = dst[:0]
|
||||
dst = addLeadingSlash(dst, src)
|
||||
dst = decodeArgAppend(dst, src, false)
|
||||
|
||||
// remove duplicate slashes
|
||||
b := dst
|
||||
bSize := len(b)
|
||||
for {
|
||||
n := bytes.Index(b, strSlashSlash)
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
b = b[n:]
|
||||
copy(b, b[1:])
|
||||
b = b[:len(b)-1]
|
||||
bSize--
|
||||
}
|
||||
dst = dst[:bSize]
|
||||
|
||||
// remove /./ parts
|
||||
b = dst
|
||||
for {
|
||||
n := bytes.Index(b, strSlashDotSlash)
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
nn := n + len(strSlashDotSlash) - 1
|
||||
copy(b[n:], b[nn:])
|
||||
b = b[:len(b)-nn+n]
|
||||
}
|
||||
|
||||
// remove /foo/../ parts
|
||||
for {
|
||||
n := bytes.Index(b, strSlashDotDotSlash)
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
nn := bytes.LastIndexByte(b[:n], '/')
|
||||
if nn < 0 {
|
||||
nn = 0
|
||||
}
|
||||
n += len(strSlashDotDotSlash) - 1
|
||||
copy(b[nn:], b[n:])
|
||||
b = b[:len(b)-n+nn]
|
||||
}
|
||||
|
||||
// remove trailing /foo/..
|
||||
n := bytes.LastIndex(b, strSlashDotDot)
|
||||
if n >= 0 && n+len(strSlashDotDot) == len(b) {
|
||||
nn := bytes.LastIndexByte(b[:n], '/')
|
||||
if nn < 0 {
|
||||
return strSlash
|
||||
}
|
||||
b = b[:nn+1]
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// RequestURI returns RequestURI - i.e. URI without Scheme and Host.
|
||||
func (u *URI) RequestURI() []byte {
|
||||
dst := appendQuotedPath(u.requestURI[:0], u.Path())
|
||||
if u.queryArgs.Len() > 0 {
|
||||
dst = append(dst, '?')
|
||||
dst = u.queryArgs.AppendBytes(dst)
|
||||
} else if len(u.queryString) > 0 {
|
||||
dst = append(dst, '?')
|
||||
dst = append(dst, u.queryString...)
|
||||
}
|
||||
if len(u.hash) > 0 {
|
||||
dst = append(dst, '#')
|
||||
dst = append(dst, u.hash...)
|
||||
}
|
||||
u.requestURI = dst
|
||||
return u.requestURI
|
||||
}
|
||||
|
||||
// LastPathSegment returns the last part of uri path after '/'.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// * For /foo/bar/baz.html path returns baz.html.
|
||||
// * For /foo/bar/ returns empty byte slice.
|
||||
// * For /foobar.js returns foobar.js.
|
||||
func (u *URI) LastPathSegment() []byte {
|
||||
path := u.Path()
|
||||
n := bytes.LastIndexByte(path, '/')
|
||||
if n < 0 {
|
||||
return path
|
||||
}
|
||||
return path[n+1:]
|
||||
}
|
||||
|
||||
// Update updates uri.
|
||||
//
|
||||
// The following newURI types are accepted:
|
||||
//
|
||||
// * Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
|
||||
// uri is replaced by newURI.
|
||||
// * Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
|
||||
// of the original uri is replaced.
|
||||
// * Relative path, i.e. xx?yy=abc . In this case the original RequestURI
|
||||
// is updated according to the new relative path.
|
||||
func (u *URI) Update(newURI string) {
|
||||
u.UpdateBytes(s2b(newURI))
|
||||
}
|
||||
|
||||
// UpdateBytes updates uri.
|
||||
//
|
||||
// The following newURI types are accepted:
|
||||
//
|
||||
// * Absolute, i.e. http://foobar.com/aaa/bb?cc . In this case the original
|
||||
// uri is replaced by newURI.
|
||||
// * Missing host, i.e. /aaa/bb?cc . In this case only RequestURI part
|
||||
// of the original uri is replaced.
|
||||
// * Relative path, i.e. xx?yy=abc . In this case the original RequestURI
|
||||
// is updated according to the new relative path.
|
||||
func (u *URI) UpdateBytes(newURI []byte) {
|
||||
u.requestURI = u.updateBytes(newURI, u.requestURI)
|
||||
}
|
||||
|
||||
func (u *URI) updateBytes(newURI, buf []byte) []byte {
|
||||
if len(newURI) == 0 {
|
||||
return buf
|
||||
}
|
||||
if newURI[0] == '/' {
|
||||
// uri without host
|
||||
buf = u.appendSchemeHost(buf[:0])
|
||||
buf = append(buf, newURI...)
|
||||
u.Parse(nil, buf)
|
||||
return buf
|
||||
}
|
||||
|
||||
n := bytes.Index(newURI, strColonSlashSlash)
|
||||
if n >= 0 {
|
||||
// absolute uri
|
||||
u.Parse(nil, newURI)
|
||||
return buf
|
||||
}
|
||||
|
||||
// relative path
|
||||
switch newURI[0] {
|
||||
case '?':
|
||||
// query string only update
|
||||
u.SetQueryStringBytes(newURI[1:])
|
||||
return append(buf[:0], u.FullURI()...)
|
||||
case '#':
|
||||
// update only hash
|
||||
u.SetHashBytes(newURI[1:])
|
||||
return append(buf[:0], u.FullURI()...)
|
||||
default:
|
||||
// update the last path part after the slash
|
||||
path := u.Path()
|
||||
n = bytes.LastIndexByte(path, '/')
|
||||
if n < 0 {
|
||||
panic("BUG: path must contain at least one slash")
|
||||
}
|
||||
buf = u.appendSchemeHost(buf[:0])
|
||||
buf = appendQuotedPath(buf, path[:n+1])
|
||||
buf = append(buf, newURI...)
|
||||
u.Parse(nil, buf)
|
||||
return buf
|
||||
}
|
||||
}
|
||||
|
||||
// FullURI returns full uri in the form {Scheme}://{Host}{RequestURI}#{Hash}.
|
||||
func (u *URI) FullURI() []byte {
|
||||
u.fullURI = u.AppendBytes(u.fullURI[:0])
|
||||
return u.fullURI
|
||||
}
|
||||
|
||||
// AppendBytes appends full uri to dst and returns the extended dst.
|
||||
func (u *URI) AppendBytes(dst []byte) []byte {
|
||||
dst = u.appendSchemeHost(dst)
|
||||
return append(dst, u.RequestURI()...)
|
||||
}
|
||||
|
||||
func (u *URI) appendSchemeHost(dst []byte) []byte {
|
||||
dst = append(dst, u.Scheme()...)
|
||||
dst = append(dst, strColonSlashSlash...)
|
||||
return append(dst, u.Host()...)
|
||||
}
|
||||
|
||||
// WriteTo writes full uri to w.
|
||||
//
|
||||
// WriteTo implements io.WriterTo interface.
|
||||
func (u *URI) WriteTo(w io.Writer) (int64, error) {
|
||||
n, err := w.Write(u.FullURI())
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
// String returns full uri.
|
||||
func (u *URI) String() string {
|
||||
return string(u.FullURI())
|
||||
}
|
||||
|
||||
func splitHostURI(host, uri []byte) ([]byte, []byte, []byte) {
|
||||
n := bytes.Index(uri, strColonSlashSlash)
|
||||
if n < 0 {
|
||||
return strHTTP, host, uri
|
||||
}
|
||||
scheme := uri[:n]
|
||||
if bytes.IndexByte(scheme, '/') >= 0 {
|
||||
return strHTTP, host, uri
|
||||
}
|
||||
n += len(strColonSlashSlash)
|
||||
uri = uri[n:]
|
||||
n = bytes.IndexByte(uri, '/')
|
||||
if n < 0 {
|
||||
return scheme, uri, strSlash
|
||||
}
|
||||
return scheme, uri[:n], uri[n:]
|
||||
}
|
||||
|
||||
// QueryArgs returns query args.
|
||||
func (u *URI) QueryArgs() *Args {
|
||||
u.parseQueryArgs()
|
||||
return &u.queryArgs
|
||||
}
|
||||
|
||||
func (u *URI) parseQueryArgs() {
|
||||
if u.parsedQueryArgs {
|
||||
return
|
||||
}
|
||||
u.queryArgs.ParseBytes(u.queryString)
|
||||
u.parsedQueryArgs = true
|
||||
}
|
Reference in New Issue
Block a user