mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	
				
					committed by
					
						
						Lunny Xiao
					
				
			
			
				
	
			
			
			
						parent
						
							b209531959
						
					
				
				
					commit
					33ad554800
				
			
							
								
								
									
										5
									
								
								vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,18 +2,15 @@
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// +build go1.7
 | 
			
		||||
 | 
			
		||||
// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
 | 
			
		||||
package ctxhttp // import "golang.org/x/net/context/ctxhttp"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Do sends an HTTP request with the provided http.Client and returns
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										147
									
								
								vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										147
									
								
								vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,147 +0,0 @@
 | 
			
		||||
// Copyright 2015 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// +build !go1.7
 | 
			
		||||
 | 
			
		||||
package ctxhttp // import "golang.org/x/net/context/ctxhttp"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func nop() {}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	testHookContextDoneBeforeHeaders = nop
 | 
			
		||||
	testHookDoReturned               = nop
 | 
			
		||||
	testHookDidBodyClose             = nop
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
 | 
			
		||||
// If the client is nil, http.DefaultClient is used.
 | 
			
		||||
// If the context is canceled or times out, ctx.Err() will be returned.
 | 
			
		||||
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
 | 
			
		||||
	if client == nil {
 | 
			
		||||
		client = http.DefaultClient
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO(djd): Respect any existing value of req.Cancel.
 | 
			
		||||
	cancel := make(chan struct{})
 | 
			
		||||
	req.Cancel = cancel
 | 
			
		||||
 | 
			
		||||
	type responseAndError struct {
 | 
			
		||||
		resp *http.Response
 | 
			
		||||
		err  error
 | 
			
		||||
	}
 | 
			
		||||
	result := make(chan responseAndError, 1)
 | 
			
		||||
 | 
			
		||||
	// Make local copies of test hooks closed over by goroutines below.
 | 
			
		||||
	// Prevents data races in tests.
 | 
			
		||||
	testHookDoReturned := testHookDoReturned
 | 
			
		||||
	testHookDidBodyClose := testHookDidBodyClose
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		resp, err := client.Do(req)
 | 
			
		||||
		testHookDoReturned()
 | 
			
		||||
		result <- responseAndError{resp, err}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	var resp *http.Response
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
		testHookContextDoneBeforeHeaders()
 | 
			
		||||
		close(cancel)
 | 
			
		||||
		// Clean up after the goroutine calling client.Do:
 | 
			
		||||
		go func() {
 | 
			
		||||
			if r := <-result; r.resp != nil {
 | 
			
		||||
				testHookDidBodyClose()
 | 
			
		||||
				r.resp.Body.Close()
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
		return nil, ctx.Err()
 | 
			
		||||
	case r := <-result:
 | 
			
		||||
		var err error
 | 
			
		||||
		resp, err = r.resp, r.err
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return resp, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c := make(chan struct{})
 | 
			
		||||
	go func() {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			close(cancel)
 | 
			
		||||
		case <-c:
 | 
			
		||||
			// The response's Body is closed.
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	resp.Body = ¬ifyingReader{resp.Body, c}
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get issues a GET request via the Do function.
 | 
			
		||||
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
 | 
			
		||||
	req, err := http.NewRequest("GET", url, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return Do(ctx, client, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Head issues a HEAD request via the Do function.
 | 
			
		||||
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
 | 
			
		||||
	req, err := http.NewRequest("HEAD", url, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return Do(ctx, client, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Post issues a POST request via the Do function.
 | 
			
		||||
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
 | 
			
		||||
	req, err := http.NewRequest("POST", url, body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("Content-Type", bodyType)
 | 
			
		||||
	return Do(ctx, client, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PostForm issues a POST request via the Do function.
 | 
			
		||||
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
 | 
			
		||||
	return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// notifyingReader is an io.ReadCloser that closes the notify channel after
 | 
			
		||||
// Close is called or a Read fails on the underlying ReadCloser.
 | 
			
		||||
type notifyingReader struct {
 | 
			
		||||
	io.ReadCloser
 | 
			
		||||
	notify chan<- struct{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *notifyingReader) Read(p []byte) (int, error) {
 | 
			
		||||
	n, err := r.ReadCloser.Read(p)
 | 
			
		||||
	if err != nil && r.notify != nil {
 | 
			
		||||
		close(r.notify)
 | 
			
		||||
		r.notify = nil
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *notifyingReader) Close() error {
 | 
			
		||||
	err := r.ReadCloser.Close()
 | 
			
		||||
	if r.notify != nil {
 | 
			
		||||
		close(r.notify)
 | 
			
		||||
		r.notify = nil
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/golang.org/x/net/html/node.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/golang.org/x/net/html/node.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -177,7 +177,7 @@ func (s *nodeStack) index(n *Node) int {
 | 
			
		||||
// contains returns whether a is within s.
 | 
			
		||||
func (s *nodeStack) contains(a atom.Atom) bool {
 | 
			
		||||
	for _, n := range *s {
 | 
			
		||||
		if n.DataAtom == a {
 | 
			
		||||
		if n.DataAtom == a && n.Namespace == "" {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										158
									
								
								vendor/golang.org/x/net/html/parse.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										158
									
								
								vendor/golang.org/x/net/html/parse.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -439,9 +439,6 @@ func (p *parser) resetInsertionMode() {
 | 
			
		||||
		case a.Select:
 | 
			
		||||
			if !last {
 | 
			
		||||
				for ancestor, first := n, p.oe[0]; ancestor != first; {
 | 
			
		||||
					if ancestor == first {
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
					ancestor = p.oe[p.oe.index(ancestor)-1]
 | 
			
		||||
					switch ancestor.DataAtom {
 | 
			
		||||
					case a.Template:
 | 
			
		||||
@@ -633,7 +630,16 @@ func inHeadIM(p *parser) bool {
 | 
			
		||||
			p.oe.pop()
 | 
			
		||||
			p.acknowledgeSelfClosingTag()
 | 
			
		||||
			return true
 | 
			
		||||
		case a.Script, a.Title, a.Noscript, a.Noframes, a.Style:
 | 
			
		||||
		case a.Noscript:
 | 
			
		||||
			p.addElement()
 | 
			
		||||
			if p.scripting {
 | 
			
		||||
				p.setOriginalIM()
 | 
			
		||||
				p.im = textIM
 | 
			
		||||
			} else {
 | 
			
		||||
				p.im = inHeadNoscriptIM
 | 
			
		||||
			}
 | 
			
		||||
			return true
 | 
			
		||||
		case a.Script, a.Title, a.Noframes, a.Style:
 | 
			
		||||
			p.addElement()
 | 
			
		||||
			p.setOriginalIM()
 | 
			
		||||
			p.im = textIM
 | 
			
		||||
@@ -695,6 +701,49 @@ func inHeadIM(p *parser) bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 12.2.6.4.5.
 | 
			
		||||
func inHeadNoscriptIM(p *parser) bool {
 | 
			
		||||
	switch p.tok.Type {
 | 
			
		||||
	case DoctypeToken:
 | 
			
		||||
		// Ignore the token.
 | 
			
		||||
		return true
 | 
			
		||||
	case StartTagToken:
 | 
			
		||||
		switch p.tok.DataAtom {
 | 
			
		||||
		case a.Html:
 | 
			
		||||
			return inBodyIM(p)
 | 
			
		||||
		case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style:
 | 
			
		||||
			return inHeadIM(p)
 | 
			
		||||
		case a.Head, a.Noscript:
 | 
			
		||||
			// Ignore the token.
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	case EndTagToken:
 | 
			
		||||
		switch p.tok.DataAtom {
 | 
			
		||||
		case a.Noscript, a.Br:
 | 
			
		||||
		default:
 | 
			
		||||
			// Ignore the token.
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	case TextToken:
 | 
			
		||||
		s := strings.TrimLeft(p.tok.Data, whitespace)
 | 
			
		||||
		if len(s) == 0 {
 | 
			
		||||
			// It was all whitespace.
 | 
			
		||||
			return inHeadIM(p)
 | 
			
		||||
		}
 | 
			
		||||
	case CommentToken:
 | 
			
		||||
		return inHeadIM(p)
 | 
			
		||||
	}
 | 
			
		||||
	p.oe.pop()
 | 
			
		||||
	if p.top().DataAtom != a.Head {
 | 
			
		||||
		panic("html: the new current node will be a head element.")
 | 
			
		||||
	}
 | 
			
		||||
	p.im = inHeadIM
 | 
			
		||||
	if p.tok.DataAtom == a.Noscript {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Section 12.2.6.4.6.
 | 
			
		||||
func afterHeadIM(p *parser) bool {
 | 
			
		||||
	switch p.tok.Type {
 | 
			
		||||
@@ -904,7 +953,7 @@ func inBodyIM(p *parser) bool {
 | 
			
		||||
		case a.A:
 | 
			
		||||
			for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
 | 
			
		||||
				if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
 | 
			
		||||
					p.inBodyEndTagFormatting(a.A)
 | 
			
		||||
					p.inBodyEndTagFormatting(a.A, "a")
 | 
			
		||||
					p.oe.remove(n)
 | 
			
		||||
					p.afe.remove(n)
 | 
			
		||||
					break
 | 
			
		||||
@@ -918,7 +967,7 @@ func inBodyIM(p *parser) bool {
 | 
			
		||||
		case a.Nobr:
 | 
			
		||||
			p.reconstructActiveFormattingElements()
 | 
			
		||||
			if p.elementInScope(defaultScope, a.Nobr) {
 | 
			
		||||
				p.inBodyEndTagFormatting(a.Nobr)
 | 
			
		||||
				p.inBodyEndTagFormatting(a.Nobr, "nobr")
 | 
			
		||||
				p.reconstructActiveFormattingElements()
 | 
			
		||||
			}
 | 
			
		||||
			p.addFormattingElement()
 | 
			
		||||
@@ -1126,7 +1175,7 @@ func inBodyIM(p *parser) bool {
 | 
			
		||||
		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
 | 
			
		||||
			p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
 | 
			
		||||
		case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
 | 
			
		||||
			p.inBodyEndTagFormatting(p.tok.DataAtom)
 | 
			
		||||
			p.inBodyEndTagFormatting(p.tok.DataAtom, p.tok.Data)
 | 
			
		||||
		case a.Applet, a.Marquee, a.Object:
 | 
			
		||||
			if p.popUntil(defaultScope, p.tok.DataAtom) {
 | 
			
		||||
				p.clearActiveFormattingElements()
 | 
			
		||||
@@ -1137,7 +1186,7 @@ func inBodyIM(p *parser) bool {
 | 
			
		||||
		case a.Template:
 | 
			
		||||
			return inHeadIM(p)
 | 
			
		||||
		default:
 | 
			
		||||
			p.inBodyEndTagOther(p.tok.DataAtom)
 | 
			
		||||
			p.inBodyEndTagOther(p.tok.DataAtom, p.tok.Data)
 | 
			
		||||
		}
 | 
			
		||||
	case CommentToken:
 | 
			
		||||
		p.addChild(&Node{
 | 
			
		||||
@@ -1164,7 +1213,7 @@ func inBodyIM(p *parser) bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
 | 
			
		||||
func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom, tagName string) {
 | 
			
		||||
	// This is the "adoption agency" algorithm, described at
 | 
			
		||||
	// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
 | 
			
		||||
 | 
			
		||||
@@ -1186,7 +1235,7 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if formattingElement == nil {
 | 
			
		||||
			p.inBodyEndTagOther(tagAtom)
 | 
			
		||||
			p.inBodyEndTagOther(tagAtom, tagName)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		feIndex := p.oe.index(formattingElement)
 | 
			
		||||
@@ -1291,9 +1340,17 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
 | 
			
		||||
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
 | 
			
		||||
// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
 | 
			
		||||
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
 | 
			
		||||
func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
 | 
			
		||||
func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) {
 | 
			
		||||
	for i := len(p.oe) - 1; i >= 0; i-- {
 | 
			
		||||
		if p.oe[i].DataAtom == tagAtom {
 | 
			
		||||
		// Two element nodes have the same tag if they have the same Data (a
 | 
			
		||||
		// string-typed field). As an optimization, for common HTML tags, each
 | 
			
		||||
		// Data string is assigned a unique, non-zero DataAtom (a uint32-typed
 | 
			
		||||
		// field), since integer comparison is faster than string comparison.
 | 
			
		||||
		// Uncommon (custom) tags get a zero DataAtom.
 | 
			
		||||
		//
 | 
			
		||||
		// The if condition here is equivalent to (p.oe[i].Data == tagName).
 | 
			
		||||
		if (p.oe[i].DataAtom == tagAtom) &&
 | 
			
		||||
			((tagAtom != 0) || (p.oe[i].Data == tagName)) {
 | 
			
		||||
			p.oe = p.oe[:i]
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
@@ -1687,8 +1744,9 @@ func inCellIM(p *parser) bool {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
			// Close the cell and reprocess.
 | 
			
		||||
			p.popUntil(tableScope, a.Td, a.Th)
 | 
			
		||||
			p.clearActiveFormattingElements()
 | 
			
		||||
			if p.popUntil(tableScope, a.Td, a.Th) {
 | 
			
		||||
				p.clearActiveFormattingElements()
 | 
			
		||||
			}
 | 
			
		||||
			p.im = inRowIM
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
@@ -1719,8 +1777,12 @@ func inSelectIM(p *parser) bool {
 | 
			
		||||
			}
 | 
			
		||||
			p.addElement()
 | 
			
		||||
		case a.Select:
 | 
			
		||||
			p.tok.Type = EndTagToken
 | 
			
		||||
			return false
 | 
			
		||||
			if p.popUntil(selectScope, a.Select) {
 | 
			
		||||
				p.resetInsertionMode()
 | 
			
		||||
			} else {
 | 
			
		||||
				// Ignore the token.
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		case a.Input, a.Keygen, a.Textarea:
 | 
			
		||||
			if p.elementInScope(selectScope, a.Select) {
 | 
			
		||||
				p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
 | 
			
		||||
@@ -1750,6 +1812,9 @@ func inSelectIM(p *parser) bool {
 | 
			
		||||
		case a.Select:
 | 
			
		||||
			if p.popUntil(selectScope, a.Select) {
 | 
			
		||||
				p.resetInsertionMode()
 | 
			
		||||
			} else {
 | 
			
		||||
				// Ignore the token.
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		case a.Template:
 | 
			
		||||
			return inHeadIM(p)
 | 
			
		||||
@@ -1775,13 +1840,22 @@ func inSelectInTableIM(p *parser) bool {
 | 
			
		||||
	case StartTagToken, EndTagToken:
 | 
			
		||||
		switch p.tok.DataAtom {
 | 
			
		||||
		case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th:
 | 
			
		||||
			if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.DataAtom) {
 | 
			
		||||
				p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
 | 
			
		||||
				return false
 | 
			
		||||
			} else {
 | 
			
		||||
			if p.tok.Type == EndTagToken && !p.elementInScope(tableScope, p.tok.DataAtom) {
 | 
			
		||||
				// Ignore the token.
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
			// This is like p.popUntil(selectScope, a.Select), but it also
 | 
			
		||||
			// matches <math select>, not just <select>. Matching the MathML
 | 
			
		||||
			// tag is arguably incorrect (conceptually), but it mimics what
 | 
			
		||||
			// Chromium does.
 | 
			
		||||
			for i := len(p.oe) - 1; i >= 0; i-- {
 | 
			
		||||
				if n := p.oe[i]; n.DataAtom == a.Select {
 | 
			
		||||
					p.oe = p.oe[:i]
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			p.resetInsertionMode()
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return inSelectIM(p)
 | 
			
		||||
@@ -2226,6 +2300,33 @@ func (p *parser) parse() error {
 | 
			
		||||
//
 | 
			
		||||
// The input is assumed to be UTF-8 encoded.
 | 
			
		||||
func Parse(r io.Reader) (*Node, error) {
 | 
			
		||||
	return ParseWithOptions(r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseFragment parses a fragment of HTML and returns the nodes that were
 | 
			
		||||
// found. If the fragment is the InnerHTML for an existing element, pass that
 | 
			
		||||
// element in context.
 | 
			
		||||
//
 | 
			
		||||
// It has the same intricacies as Parse.
 | 
			
		||||
func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
 | 
			
		||||
	return ParseFragmentWithOptions(r, context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseOption configures a parser.
 | 
			
		||||
type ParseOption func(p *parser)
 | 
			
		||||
 | 
			
		||||
// ParseOptionEnableScripting configures the scripting flag.
 | 
			
		||||
// https://html.spec.whatwg.org/multipage/webappapis.html#enabling-and-disabling-scripting
 | 
			
		||||
//
 | 
			
		||||
// By default, scripting is enabled.
 | 
			
		||||
func ParseOptionEnableScripting(enable bool) ParseOption {
 | 
			
		||||
	return func(p *parser) {
 | 
			
		||||
		p.scripting = enable
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseWithOptions is like Parse, with options.
 | 
			
		||||
func ParseWithOptions(r io.Reader, opts ...ParseOption) (*Node, error) {
 | 
			
		||||
	p := &parser{
 | 
			
		||||
		tokenizer: NewTokenizer(r),
 | 
			
		||||
		doc: &Node{
 | 
			
		||||
@@ -2235,6 +2336,11 @@ func Parse(r io.Reader) (*Node, error) {
 | 
			
		||||
		framesetOK: true,
 | 
			
		||||
		im:         initialIM,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, f := range opts {
 | 
			
		||||
		f(p)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := p.parse()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
@@ -2242,12 +2348,8 @@ func Parse(r io.Reader) (*Node, error) {
 | 
			
		||||
	return p.doc, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseFragment parses a fragment of HTML and returns the nodes that were
 | 
			
		||||
// found. If the fragment is the InnerHTML for an existing element, pass that
 | 
			
		||||
// element in context.
 | 
			
		||||
//
 | 
			
		||||
// It has the same intricacies as Parse.
 | 
			
		||||
func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
 | 
			
		||||
// ParseFragmentWithOptions is like ParseFragment, with options.
 | 
			
		||||
func ParseFragmentWithOptions(r io.Reader, context *Node, opts ...ParseOption) ([]*Node, error) {
 | 
			
		||||
	contextTag := ""
 | 
			
		||||
	if context != nil {
 | 
			
		||||
		if context.Type != ElementNode {
 | 
			
		||||
@@ -2271,6 +2373,10 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
 | 
			
		||||
		context:   context,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, f := range opts {
 | 
			
		||||
		f(p)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	root := &Node{
 | 
			
		||||
		Type:     ElementNode,
 | 
			
		||||
		DataAtom: a.Html,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										734
									
								
								vendor/golang.org/x/net/idna/idna10.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										734
									
								
								vendor/golang.org/x/net/idna/idna10.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,734 @@
 | 
			
		||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
// Copyright 2016 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// +build go1.10
 | 
			
		||||
 | 
			
		||||
// Package idna implements IDNA2008 using the compatibility processing
 | 
			
		||||
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to
 | 
			
		||||
// deal with the transition from IDNA2003.
 | 
			
		||||
//
 | 
			
		||||
// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC
 | 
			
		||||
// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894.
 | 
			
		||||
// UTS #46 is defined in https://www.unicode.org/reports/tr46.
 | 
			
		||||
// See https://unicode.org/cldr/utility/idna.jsp for a visualization of the
 | 
			
		||||
// differences between these two standards.
 | 
			
		||||
package idna // import "golang.org/x/net/idna"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/text/secure/bidirule"
 | 
			
		||||
	"golang.org/x/text/unicode/bidi"
 | 
			
		||||
	"golang.org/x/text/unicode/norm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NOTE: Unlike common practice in Go APIs, the functions will return a
 | 
			
		||||
// sanitized domain name in case of errors. Browsers sometimes use a partially
 | 
			
		||||
// evaluated string as lookup.
 | 
			
		||||
// TODO: the current error handling is, in my opinion, the least opinionated.
 | 
			
		||||
// Other strategies are also viable, though:
 | 
			
		||||
// Option 1) Return an empty string in case of error, but allow the user to
 | 
			
		||||
//    specify explicitly which errors to ignore.
 | 
			
		||||
// Option 2) Return the partially evaluated string if it is itself a valid
 | 
			
		||||
//    string, otherwise return the empty string in case of error.
 | 
			
		||||
// Option 3) Option 1 and 2.
 | 
			
		||||
// Option 4) Always return an empty string for now and implement Option 1 as
 | 
			
		||||
//    needed, and document that the return string may not be empty in case of
 | 
			
		||||
//    error in the future.
 | 
			
		||||
// I think Option 1 is best, but it is quite opinionated.
 | 
			
		||||
 | 
			
		||||
// ToASCII is a wrapper for Punycode.ToASCII.
 | 
			
		||||
func ToASCII(s string) (string, error) {
 | 
			
		||||
	return Punycode.process(s, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToUnicode is a wrapper for Punycode.ToUnicode.
 | 
			
		||||
func ToUnicode(s string) (string, error) {
 | 
			
		||||
	return Punycode.process(s, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An Option configures a Profile at creation time.
 | 
			
		||||
type Option func(*options)
 | 
			
		||||
 | 
			
		||||
// Transitional sets a Profile to use the Transitional mapping as defined in UTS
 | 
			
		||||
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the
 | 
			
		||||
// transitional mapping provides a compromise between IDNA2003 and IDNA2008
 | 
			
		||||
// compatibility. It is used by most browsers when resolving domain names. This
 | 
			
		||||
// option is only meaningful if combined with MapForLookup.
 | 
			
		||||
func Transitional(transitional bool) Option {
 | 
			
		||||
	return func(o *options) { o.transitional = true }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
 | 
			
		||||
// are longer than allowed by the RFC.
 | 
			
		||||
func VerifyDNSLength(verify bool) Option {
 | 
			
		||||
	return func(o *options) { o.verifyDNSLength = verify }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveLeadingDots removes leading label separators. Leading runes that map to
 | 
			
		||||
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well.
 | 
			
		||||
//
 | 
			
		||||
// This is the behavior suggested by the UTS #46 and is adopted by some
 | 
			
		||||
// browsers.
 | 
			
		||||
func RemoveLeadingDots(remove bool) Option {
 | 
			
		||||
	return func(o *options) { o.removeLeadingDots = remove }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateLabels sets whether to check the mandatory label validation criteria
 | 
			
		||||
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
 | 
			
		||||
// of hyphens ('-'), normalization, validity of runes, and the context rules.
 | 
			
		||||
func ValidateLabels(enable bool) Option {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		// Don't override existing mappings, but set one that at least checks
 | 
			
		||||
		// normalization if it is not set.
 | 
			
		||||
		if o.mapping == nil && enable {
 | 
			
		||||
			o.mapping = normalize
 | 
			
		||||
		}
 | 
			
		||||
		o.trie = trie
 | 
			
		||||
		o.validateLabels = enable
 | 
			
		||||
		o.fromPuny = validateFromPunycode
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StrictDomainName limits the set of permissible ASCII characters to those
 | 
			
		||||
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
 | 
			
		||||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration.
 | 
			
		||||
//
 | 
			
		||||
// This option is useful, for instance, for browsers that allow characters
 | 
			
		||||
// outside this range, for example a '_' (U+005F LOW LINE). See
 | 
			
		||||
// http://www.rfc-editor.org/std/std3.txt for more details This option
 | 
			
		||||
// corresponds to the UseSTD3ASCIIRules option in UTS #46.
 | 
			
		||||
func StrictDomainName(use bool) Option {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		o.trie = trie
 | 
			
		||||
		o.useSTD3Rules = use
 | 
			
		||||
		o.fromPuny = validateFromPunycode
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NOTE: the following options pull in tables. The tables should not be linked
 | 
			
		||||
// in as long as the options are not used.
 | 
			
		||||
 | 
			
		||||
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application
 | 
			
		||||
// that relies on proper validation of labels should include this rule.
 | 
			
		||||
func BidiRule() Option {
 | 
			
		||||
	return func(o *options) { o.bidirule = bidirule.ValidString }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateForRegistration sets validation options to verify that a given IDN is
 | 
			
		||||
// properly formatted for registration as defined by Section 4 of RFC 5891.
 | 
			
		||||
func ValidateForRegistration() Option {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		o.mapping = validateRegistration
 | 
			
		||||
		StrictDomainName(true)(o)
 | 
			
		||||
		ValidateLabels(true)(o)
 | 
			
		||||
		VerifyDNSLength(true)(o)
 | 
			
		||||
		BidiRule()(o)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapForLookup sets validation and mapping options such that a given IDN is
 | 
			
		||||
// transformed for domain name lookup according to the requirements set out in
 | 
			
		||||
// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894,
 | 
			
		||||
// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option
 | 
			
		||||
// to add this check.
 | 
			
		||||
//
 | 
			
		||||
// The mappings include normalization and mapping case, width and other
 | 
			
		||||
// compatibility mappings.
 | 
			
		||||
func MapForLookup() Option {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		o.mapping = validateAndMap
 | 
			
		||||
		StrictDomainName(true)(o)
 | 
			
		||||
		ValidateLabels(true)(o)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type options struct {
 | 
			
		||||
	transitional      bool
 | 
			
		||||
	useSTD3Rules      bool
 | 
			
		||||
	validateLabels    bool
 | 
			
		||||
	verifyDNSLength   bool
 | 
			
		||||
	removeLeadingDots bool
 | 
			
		||||
 | 
			
		||||
	trie *idnaTrie
 | 
			
		||||
 | 
			
		||||
	// fromPuny calls validation rules when converting A-labels to U-labels.
 | 
			
		||||
	fromPuny func(p *Profile, s string) error
 | 
			
		||||
 | 
			
		||||
	// mapping implements a validation and mapping step as defined in RFC 5895
 | 
			
		||||
	// or UTS 46, tailored to, for example, domain registration or lookup.
 | 
			
		||||
	mapping func(p *Profile, s string) (mapped string, isBidi bool, err error)
 | 
			
		||||
 | 
			
		||||
	// bidirule, if specified, checks whether s conforms to the Bidi Rule
 | 
			
		||||
	// defined in RFC 5893.
 | 
			
		||||
	bidirule func(s string) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Profile defines the configuration of an IDNA mapper.
 | 
			
		||||
type Profile struct {
 | 
			
		||||
	options
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func apply(o *options, opts []Option) {
 | 
			
		||||
	for _, f := range opts {
 | 
			
		||||
		f(o)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new Profile.
 | 
			
		||||
//
 | 
			
		||||
// With no options, the returned Profile is the most permissive and equals the
 | 
			
		||||
// Punycode Profile. Options can be passed to further restrict the Profile. The
 | 
			
		||||
// MapForLookup and ValidateForRegistration options set a collection of options,
 | 
			
		||||
// for lookup and registration purposes respectively, which can be tailored by
 | 
			
		||||
// adding more fine-grained options, where later options override earlier
 | 
			
		||||
// options.
 | 
			
		||||
func New(o ...Option) *Profile {
 | 
			
		||||
	p := &Profile{}
 | 
			
		||||
	apply(&p.options, o)
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToASCII converts a domain or domain label to its ASCII form. For example,
 | 
			
		||||
// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
 | 
			
		||||
// ToASCII("golang") is "golang". If an error is encountered it will return
 | 
			
		||||
// an error and a (partially) processed result.
 | 
			
		||||
func (p *Profile) ToASCII(s string) (string, error) {
 | 
			
		||||
	return p.process(s, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToUnicode converts a domain or domain label to its Unicode form. For example,
 | 
			
		||||
// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and
 | 
			
		||||
// ToUnicode("golang") is "golang". If an error is encountered it will return
 | 
			
		||||
// an error and a (partially) processed result.
 | 
			
		||||
func (p *Profile) ToUnicode(s string) (string, error) {
 | 
			
		||||
	pp := *p
 | 
			
		||||
	pp.transitional = false
 | 
			
		||||
	return pp.process(s, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String reports a string with a description of the profile for debugging
 | 
			
		||||
// purposes. The string format may change with different versions.
 | 
			
		||||
func (p *Profile) String() string {
 | 
			
		||||
	s := ""
 | 
			
		||||
	if p.transitional {
 | 
			
		||||
		s = "Transitional"
 | 
			
		||||
	} else {
 | 
			
		||||
		s = "NonTransitional"
 | 
			
		||||
	}
 | 
			
		||||
	if p.useSTD3Rules {
 | 
			
		||||
		s += ":UseSTD3Rules"
 | 
			
		||||
	}
 | 
			
		||||
	if p.validateLabels {
 | 
			
		||||
		s += ":ValidateLabels"
 | 
			
		||||
	}
 | 
			
		||||
	if p.verifyDNSLength {
 | 
			
		||||
		s += ":VerifyDNSLength"
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// Punycode is a Profile that does raw punycode processing with a minimum
 | 
			
		||||
	// of validation.
 | 
			
		||||
	Punycode *Profile = punycode
 | 
			
		||||
 | 
			
		||||
	// Lookup is the recommended profile for looking up domain names, according
 | 
			
		||||
	// to Section 5 of RFC 5891. The exact configuration of this profile may
 | 
			
		||||
	// change over time.
 | 
			
		||||
	Lookup *Profile = lookup
 | 
			
		||||
 | 
			
		||||
	// Display is the recommended profile for displaying domain names.
 | 
			
		||||
	// The configuration of this profile may change over time.
 | 
			
		||||
	Display *Profile = display
 | 
			
		||||
 | 
			
		||||
	// Registration is the recommended profile for checking whether a given
 | 
			
		||||
	// IDN is valid for registration, according to Section 4 of RFC 5891.
 | 
			
		||||
	Registration *Profile = registration
 | 
			
		||||
 | 
			
		||||
	punycode = &Profile{}
 | 
			
		||||
	lookup   = &Profile{options{
 | 
			
		||||
		transitional:   true,
 | 
			
		||||
		useSTD3Rules:   true,
 | 
			
		||||
		validateLabels: true,
 | 
			
		||||
		trie:           trie,
 | 
			
		||||
		fromPuny:       validateFromPunycode,
 | 
			
		||||
		mapping:        validateAndMap,
 | 
			
		||||
		bidirule:       bidirule.ValidString,
 | 
			
		||||
	}}
 | 
			
		||||
	display = &Profile{options{
 | 
			
		||||
		useSTD3Rules:   true,
 | 
			
		||||
		validateLabels: true,
 | 
			
		||||
		trie:           trie,
 | 
			
		||||
		fromPuny:       validateFromPunycode,
 | 
			
		||||
		mapping:        validateAndMap,
 | 
			
		||||
		bidirule:       bidirule.ValidString,
 | 
			
		||||
	}}
 | 
			
		||||
	registration = &Profile{options{
 | 
			
		||||
		useSTD3Rules:    true,
 | 
			
		||||
		validateLabels:  true,
 | 
			
		||||
		verifyDNSLength: true,
 | 
			
		||||
		trie:            trie,
 | 
			
		||||
		fromPuny:        validateFromPunycode,
 | 
			
		||||
		mapping:         validateRegistration,
 | 
			
		||||
		bidirule:        bidirule.ValidString,
 | 
			
		||||
	}}
 | 
			
		||||
 | 
			
		||||
	// TODO: profiles
 | 
			
		||||
	// Register: recommended for approving domain names: don't do any mappings
 | 
			
		||||
	// but rather reject on invalid input. Bundle or block deviation characters.
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type labelError struct{ label, code_ string }
 | 
			
		||||
 | 
			
		||||
func (e labelError) code() string { return e.code_ }
 | 
			
		||||
func (e labelError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("idna: invalid label %q", e.label)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type runeError rune
 | 
			
		||||
 | 
			
		||||
func (e runeError) code() string { return "P1" }
 | 
			
		||||
func (e runeError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("idna: disallowed rune %U", e)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// process implements the algorithm described in section 4 of UTS #46,
 | 
			
		||||
// see https://www.unicode.org/reports/tr46.
 | 
			
		||||
func (p *Profile) process(s string, toASCII bool) (string, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var isBidi bool
 | 
			
		||||
	if p.mapping != nil {
 | 
			
		||||
		s, isBidi, err = p.mapping(p, s)
 | 
			
		||||
	}
 | 
			
		||||
	// Remove leading empty labels.
 | 
			
		||||
	if p.removeLeadingDots {
 | 
			
		||||
		for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: allow for a quick check of the tables data.
 | 
			
		||||
	// It seems like we should only create this error on ToASCII, but the
 | 
			
		||||
	// UTS 46 conformance tests suggests we should always check this.
 | 
			
		||||
	if err == nil && p.verifyDNSLength && s == "" {
 | 
			
		||||
		err = &labelError{s, "A4"}
 | 
			
		||||
	}
 | 
			
		||||
	labels := labelIter{orig: s}
 | 
			
		||||
	for ; !labels.done(); labels.next() {
 | 
			
		||||
		label := labels.label()
 | 
			
		||||
		if label == "" {
 | 
			
		||||
			// Empty labels are not okay. The label iterator skips the last
 | 
			
		||||
			// label if it is empty.
 | 
			
		||||
			if err == nil && p.verifyDNSLength {
 | 
			
		||||
				err = &labelError{s, "A4"}
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasPrefix(label, acePrefix) {
 | 
			
		||||
			u, err2 := decode(label[len(acePrefix):])
 | 
			
		||||
			if err2 != nil {
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					err = err2
 | 
			
		||||
				}
 | 
			
		||||
				// Spec says keep the old label.
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight
 | 
			
		||||
			labels.set(u)
 | 
			
		||||
			if err == nil && p.validateLabels {
 | 
			
		||||
				err = p.fromPuny(p, u)
 | 
			
		||||
			}
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				// This should be called on NonTransitional, according to the
 | 
			
		||||
				// spec, but that currently does not have any effect. Use the
 | 
			
		||||
				// original profile to preserve options.
 | 
			
		||||
				err = p.validateLabel(u)
 | 
			
		||||
			}
 | 
			
		||||
		} else if err == nil {
 | 
			
		||||
			err = p.validateLabel(label)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if isBidi && p.bidirule != nil && err == nil {
 | 
			
		||||
		for labels.reset(); !labels.done(); labels.next() {
 | 
			
		||||
			if !p.bidirule(labels.label()) {
 | 
			
		||||
				err = &labelError{s, "B"}
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if toASCII {
 | 
			
		||||
		for labels.reset(); !labels.done(); labels.next() {
 | 
			
		||||
			label := labels.label()
 | 
			
		||||
			if !ascii(label) {
 | 
			
		||||
				a, err2 := encode(acePrefix, label)
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					err = err2
 | 
			
		||||
				}
 | 
			
		||||
				label = a
 | 
			
		||||
				labels.set(a)
 | 
			
		||||
			}
 | 
			
		||||
			n := len(label)
 | 
			
		||||
			if p.verifyDNSLength && err == nil && (n == 0 || n > 63) {
 | 
			
		||||
				err = &labelError{label, "A4"}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	s = labels.result()
 | 
			
		||||
	if toASCII && p.verifyDNSLength && err == nil {
 | 
			
		||||
		// Compute the length of the domain name minus the root label and its dot.
 | 
			
		||||
		n := len(s)
 | 
			
		||||
		if n > 0 && s[n-1] == '.' {
 | 
			
		||||
			n--
 | 
			
		||||
		}
 | 
			
		||||
		if len(s) < 1 || n > 253 {
 | 
			
		||||
			err = &labelError{s, "A4"}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return s, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func normalize(p *Profile, s string) (mapped string, isBidi bool, err error) {
 | 
			
		||||
	// TODO: consider first doing a quick check to see if any of these checks
 | 
			
		||||
	// need to be done. This will make it slower in the general case, but
 | 
			
		||||
	// faster in the common case.
 | 
			
		||||
	mapped = norm.NFC.String(s)
 | 
			
		||||
	isBidi = bidirule.DirectionString(mapped) == bidi.RightToLeft
 | 
			
		||||
	return mapped, isBidi, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateRegistration(p *Profile, s string) (idem string, bidi bool, err error) {
 | 
			
		||||
	// TODO: filter need for normalization in loop below.
 | 
			
		||||
	if !norm.NFC.IsNormalString(s) {
 | 
			
		||||
		return s, false, &labelError{s, "V1"}
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < len(s); {
 | 
			
		||||
		v, sz := trie.lookupString(s[i:])
 | 
			
		||||
		if sz == 0 {
 | 
			
		||||
			return s, bidi, runeError(utf8.RuneError)
 | 
			
		||||
		}
 | 
			
		||||
		bidi = bidi || info(v).isBidi(s[i:])
 | 
			
		||||
		// Copy bytes not copied so far.
 | 
			
		||||
		switch p.simplify(info(v).category()) {
 | 
			
		||||
		// TODO: handle the NV8 defined in the Unicode idna data set to allow
 | 
			
		||||
		// for strict conformance to IDNA2008.
 | 
			
		||||
		case valid, deviation:
 | 
			
		||||
		case disallowed, mapped, unknown, ignored:
 | 
			
		||||
			r, _ := utf8.DecodeRuneInString(s[i:])
 | 
			
		||||
			return s, bidi, runeError(r)
 | 
			
		||||
		}
 | 
			
		||||
		i += sz
 | 
			
		||||
	}
 | 
			
		||||
	return s, bidi, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c info) isBidi(s string) bool {
 | 
			
		||||
	if !c.isMapped() {
 | 
			
		||||
		return c&attributesMask == rtl
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: also store bidi info for mapped data. This is possible, but a bit
 | 
			
		||||
	// cumbersome and not for the common case.
 | 
			
		||||
	p, _ := bidi.LookupString(s)
 | 
			
		||||
	switch p.Class() {
 | 
			
		||||
	case bidi.R, bidi.AL, bidi.AN:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) {
 | 
			
		||||
	var (
 | 
			
		||||
		b []byte
 | 
			
		||||
		k int
 | 
			
		||||
	)
 | 
			
		||||
	// combinedInfoBits contains the or-ed bits of all runes. We use this
 | 
			
		||||
	// to derive the mayNeedNorm bit later. This may trigger normalization
 | 
			
		||||
	// overeagerly, but it will not do so in the common case. The end result
 | 
			
		||||
	// is another 10% saving on BenchmarkProfile for the common case.
 | 
			
		||||
	var combinedInfoBits info
 | 
			
		||||
	for i := 0; i < len(s); {
 | 
			
		||||
		v, sz := trie.lookupString(s[i:])
 | 
			
		||||
		if sz == 0 {
 | 
			
		||||
			b = append(b, s[k:i]...)
 | 
			
		||||
			b = append(b, "\ufffd"...)
 | 
			
		||||
			k = len(s)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				err = runeError(utf8.RuneError)
 | 
			
		||||
			}
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		combinedInfoBits |= info(v)
 | 
			
		||||
		bidi = bidi || info(v).isBidi(s[i:])
 | 
			
		||||
		start := i
 | 
			
		||||
		i += sz
 | 
			
		||||
		// Copy bytes not copied so far.
 | 
			
		||||
		switch p.simplify(info(v).category()) {
 | 
			
		||||
		case valid:
 | 
			
		||||
			continue
 | 
			
		||||
		case disallowed:
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				r, _ := utf8.DecodeRuneInString(s[start:])
 | 
			
		||||
				err = runeError(r)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		case mapped, deviation:
 | 
			
		||||
			b = append(b, s[k:start]...)
 | 
			
		||||
			b = info(v).appendMapping(b, s[start:i])
 | 
			
		||||
		case ignored:
 | 
			
		||||
			b = append(b, s[k:start]...)
 | 
			
		||||
			// drop the rune
 | 
			
		||||
		case unknown:
 | 
			
		||||
			b = append(b, s[k:start]...)
 | 
			
		||||
			b = append(b, "\ufffd"...)
 | 
			
		||||
		}
 | 
			
		||||
		k = i
 | 
			
		||||
	}
 | 
			
		||||
	if k == 0 {
 | 
			
		||||
		// No changes so far.
 | 
			
		||||
		if combinedInfoBits&mayNeedNorm != 0 {
 | 
			
		||||
			s = norm.NFC.String(s)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		b = append(b, s[k:]...)
 | 
			
		||||
		if norm.NFC.QuickSpan(b) != len(b) {
 | 
			
		||||
			b = norm.NFC.Bytes(b)
 | 
			
		||||
		}
 | 
			
		||||
		// TODO: the punycode converters require strings as input.
 | 
			
		||||
		s = string(b)
 | 
			
		||||
	}
 | 
			
		||||
	return s, bidi, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A labelIter allows iterating over domain name labels.
 | 
			
		||||
type labelIter struct {
 | 
			
		||||
	orig     string
 | 
			
		||||
	slice    []string
 | 
			
		||||
	curStart int
 | 
			
		||||
	curEnd   int
 | 
			
		||||
	i        int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) reset() {
 | 
			
		||||
	l.curStart = 0
 | 
			
		||||
	l.curEnd = 0
 | 
			
		||||
	l.i = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) done() bool {
 | 
			
		||||
	return l.curStart >= len(l.orig)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) result() string {
 | 
			
		||||
	if l.slice != nil {
 | 
			
		||||
		return strings.Join(l.slice, ".")
 | 
			
		||||
	}
 | 
			
		||||
	return l.orig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) label() string {
 | 
			
		||||
	if l.slice != nil {
 | 
			
		||||
		return l.slice[l.i]
 | 
			
		||||
	}
 | 
			
		||||
	p := strings.IndexByte(l.orig[l.curStart:], '.')
 | 
			
		||||
	l.curEnd = l.curStart + p
 | 
			
		||||
	if p == -1 {
 | 
			
		||||
		l.curEnd = len(l.orig)
 | 
			
		||||
	}
 | 
			
		||||
	return l.orig[l.curStart:l.curEnd]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// next sets the value to the next label. It skips the last label if it is empty.
 | 
			
		||||
func (l *labelIter) next() {
 | 
			
		||||
	l.i++
 | 
			
		||||
	if l.slice != nil {
 | 
			
		||||
		if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" {
 | 
			
		||||
			l.curStart = len(l.orig)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		l.curStart = l.curEnd + 1
 | 
			
		||||
		if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' {
 | 
			
		||||
			l.curStart = len(l.orig)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) set(s string) {
 | 
			
		||||
	if l.slice == nil {
 | 
			
		||||
		l.slice = strings.Split(l.orig, ".")
 | 
			
		||||
	}
 | 
			
		||||
	l.slice[l.i] = s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// acePrefix is the ASCII Compatible Encoding prefix.
 | 
			
		||||
const acePrefix = "xn--"
 | 
			
		||||
 | 
			
		||||
func (p *Profile) simplify(cat category) category {
 | 
			
		||||
	switch cat {
 | 
			
		||||
	case disallowedSTD3Mapped:
 | 
			
		||||
		if p.useSTD3Rules {
 | 
			
		||||
			cat = disallowed
 | 
			
		||||
		} else {
 | 
			
		||||
			cat = mapped
 | 
			
		||||
		}
 | 
			
		||||
	case disallowedSTD3Valid:
 | 
			
		||||
		if p.useSTD3Rules {
 | 
			
		||||
			cat = disallowed
 | 
			
		||||
		} else {
 | 
			
		||||
			cat = valid
 | 
			
		||||
		}
 | 
			
		||||
	case deviation:
 | 
			
		||||
		if !p.transitional {
 | 
			
		||||
			cat = valid
 | 
			
		||||
		}
 | 
			
		||||
	case validNV8, validXV8:
 | 
			
		||||
		// TODO: handle V2008
 | 
			
		||||
		cat = valid
 | 
			
		||||
	}
 | 
			
		||||
	return cat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateFromPunycode(p *Profile, s string) error {
 | 
			
		||||
	if !norm.NFC.IsNormalString(s) {
 | 
			
		||||
		return &labelError{s, "V1"}
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: detect whether string may have to be normalized in the following
 | 
			
		||||
	// loop.
 | 
			
		||||
	for i := 0; i < len(s); {
 | 
			
		||||
		v, sz := trie.lookupString(s[i:])
 | 
			
		||||
		if sz == 0 {
 | 
			
		||||
			return runeError(utf8.RuneError)
 | 
			
		||||
		}
 | 
			
		||||
		if c := p.simplify(info(v).category()); c != valid && c != deviation {
 | 
			
		||||
			return &labelError{s, "V6"}
 | 
			
		||||
		}
 | 
			
		||||
		i += sz
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	zwnj = "\u200c"
 | 
			
		||||
	zwj  = "\u200d"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type joinState int8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	stateStart joinState = iota
 | 
			
		||||
	stateVirama
 | 
			
		||||
	stateBefore
 | 
			
		||||
	stateBeforeVirama
 | 
			
		||||
	stateAfter
 | 
			
		||||
	stateFAIL
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var joinStates = [][numJoinTypes]joinState{
 | 
			
		||||
	stateStart: {
 | 
			
		||||
		joiningL:   stateBefore,
 | 
			
		||||
		joiningD:   stateBefore,
 | 
			
		||||
		joinZWNJ:   stateFAIL,
 | 
			
		||||
		joinZWJ:    stateFAIL,
 | 
			
		||||
		joinVirama: stateVirama,
 | 
			
		||||
	},
 | 
			
		||||
	stateVirama: {
 | 
			
		||||
		joiningL: stateBefore,
 | 
			
		||||
		joiningD: stateBefore,
 | 
			
		||||
	},
 | 
			
		||||
	stateBefore: {
 | 
			
		||||
		joiningL:   stateBefore,
 | 
			
		||||
		joiningD:   stateBefore,
 | 
			
		||||
		joiningT:   stateBefore,
 | 
			
		||||
		joinZWNJ:   stateAfter,
 | 
			
		||||
		joinZWJ:    stateFAIL,
 | 
			
		||||
		joinVirama: stateBeforeVirama,
 | 
			
		||||
	},
 | 
			
		||||
	stateBeforeVirama: {
 | 
			
		||||
		joiningL: stateBefore,
 | 
			
		||||
		joiningD: stateBefore,
 | 
			
		||||
		joiningT: stateBefore,
 | 
			
		||||
	},
 | 
			
		||||
	stateAfter: {
 | 
			
		||||
		joiningL:   stateFAIL,
 | 
			
		||||
		joiningD:   stateBefore,
 | 
			
		||||
		joiningT:   stateAfter,
 | 
			
		||||
		joiningR:   stateStart,
 | 
			
		||||
		joinZWNJ:   stateFAIL,
 | 
			
		||||
		joinZWJ:    stateFAIL,
 | 
			
		||||
		joinVirama: stateAfter, // no-op as we can't accept joiners here
 | 
			
		||||
	},
 | 
			
		||||
	stateFAIL: {
 | 
			
		||||
		0:          stateFAIL,
 | 
			
		||||
		joiningL:   stateFAIL,
 | 
			
		||||
		joiningD:   stateFAIL,
 | 
			
		||||
		joiningT:   stateFAIL,
 | 
			
		||||
		joiningR:   stateFAIL,
 | 
			
		||||
		joinZWNJ:   stateFAIL,
 | 
			
		||||
		joinZWJ:    stateFAIL,
 | 
			
		||||
		joinVirama: stateFAIL,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are
 | 
			
		||||
// already implicitly satisfied by the overall implementation.
 | 
			
		||||
func (p *Profile) validateLabel(s string) (err error) {
 | 
			
		||||
	if s == "" {
 | 
			
		||||
		if p.verifyDNSLength {
 | 
			
		||||
			return &labelError{s, "A4"}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if !p.validateLabels {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	trie := p.trie // p.validateLabels is only set if trie is set.
 | 
			
		||||
	if len(s) > 4 && s[2] == '-' && s[3] == '-' {
 | 
			
		||||
		return &labelError{s, "V2"}
 | 
			
		||||
	}
 | 
			
		||||
	if s[0] == '-' || s[len(s)-1] == '-' {
 | 
			
		||||
		return &labelError{s, "V3"}
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: merge the use of this in the trie.
 | 
			
		||||
	v, sz := trie.lookupString(s)
 | 
			
		||||
	x := info(v)
 | 
			
		||||
	if x.isModifier() {
 | 
			
		||||
		return &labelError{s, "V5"}
 | 
			
		||||
	}
 | 
			
		||||
	// Quickly return in the absence of zero-width (non) joiners.
 | 
			
		||||
	if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	st := stateStart
 | 
			
		||||
	for i := 0; ; {
 | 
			
		||||
		jt := x.joinType()
 | 
			
		||||
		if s[i:i+sz] == zwj {
 | 
			
		||||
			jt = joinZWJ
 | 
			
		||||
		} else if s[i:i+sz] == zwnj {
 | 
			
		||||
			jt = joinZWNJ
 | 
			
		||||
		}
 | 
			
		||||
		st = joinStates[st][jt]
 | 
			
		||||
		if x.isViramaModifier() {
 | 
			
		||||
			st = joinStates[st][joinVirama]
 | 
			
		||||
		}
 | 
			
		||||
		if i += sz; i == len(s) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		v, sz = trie.lookupString(s[i:])
 | 
			
		||||
		x = info(v)
 | 
			
		||||
	}
 | 
			
		||||
	if st == stateFAIL || st == stateAfter {
 | 
			
		||||
		return &labelError{s, "C"}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ascii(s string) bool {
 | 
			
		||||
	for i := 0; i < len(s); i++ {
 | 
			
		||||
		if s[i] >= utf8.RuneSelf {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										682
									
								
								vendor/golang.org/x/net/idna/idna9.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										682
									
								
								vendor/golang.org/x/net/idna/idna9.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,682 @@
 | 
			
		||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
// Copyright 2016 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// +build !go1.10
 | 
			
		||||
 | 
			
		||||
// Package idna implements IDNA2008 using the compatibility processing
 | 
			
		||||
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to
 | 
			
		||||
// deal with the transition from IDNA2003.
 | 
			
		||||
//
 | 
			
		||||
// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC
 | 
			
		||||
// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894.
 | 
			
		||||
// UTS #46 is defined in https://www.unicode.org/reports/tr46.
 | 
			
		||||
// See https://unicode.org/cldr/utility/idna.jsp for a visualization of the
 | 
			
		||||
// differences between these two standards.
 | 
			
		||||
package idna // import "golang.org/x/net/idna"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/text/secure/bidirule"
 | 
			
		||||
	"golang.org/x/text/unicode/norm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NOTE: Unlike common practice in Go APIs, the functions will return a
 | 
			
		||||
// sanitized domain name in case of errors. Browsers sometimes use a partially
 | 
			
		||||
// evaluated string as lookup.
 | 
			
		||||
// TODO: the current error handling is, in my opinion, the least opinionated.
 | 
			
		||||
// Other strategies are also viable, though:
 | 
			
		||||
// Option 1) Return an empty string in case of error, but allow the user to
 | 
			
		||||
//    specify explicitly which errors to ignore.
 | 
			
		||||
// Option 2) Return the partially evaluated string if it is itself a valid
 | 
			
		||||
//    string, otherwise return the empty string in case of error.
 | 
			
		||||
// Option 3) Option 1 and 2.
 | 
			
		||||
// Option 4) Always return an empty string for now and implement Option 1 as
 | 
			
		||||
//    needed, and document that the return string may not be empty in case of
 | 
			
		||||
//    error in the future.
 | 
			
		||||
// I think Option 1 is best, but it is quite opinionated.
 | 
			
		||||
 | 
			
		||||
// ToASCII is a wrapper for Punycode.ToASCII.
 | 
			
		||||
func ToASCII(s string) (string, error) {
 | 
			
		||||
	return Punycode.process(s, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToUnicode is a wrapper for Punycode.ToUnicode.
 | 
			
		||||
func ToUnicode(s string) (string, error) {
 | 
			
		||||
	return Punycode.process(s, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An Option configures a Profile at creation time.
 | 
			
		||||
type Option func(*options)
 | 
			
		||||
 | 
			
		||||
// Transitional sets a Profile to use the Transitional mapping as defined in UTS
 | 
			
		||||
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the
 | 
			
		||||
// transitional mapping provides a compromise between IDNA2003 and IDNA2008
 | 
			
		||||
// compatibility. It is used by most browsers when resolving domain names. This
 | 
			
		||||
// option is only meaningful if combined with MapForLookup.
 | 
			
		||||
func Transitional(transitional bool) Option {
 | 
			
		||||
	return func(o *options) { o.transitional = true }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
 | 
			
		||||
// are longer than allowed by the RFC.
 | 
			
		||||
func VerifyDNSLength(verify bool) Option {
 | 
			
		||||
	return func(o *options) { o.verifyDNSLength = verify }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveLeadingDots removes leading label separators. Leading runes that map to
 | 
			
		||||
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well.
 | 
			
		||||
//
 | 
			
		||||
// This is the behavior suggested by the UTS #46 and is adopted by some
 | 
			
		||||
// browsers.
 | 
			
		||||
func RemoveLeadingDots(remove bool) Option {
 | 
			
		||||
	return func(o *options) { o.removeLeadingDots = remove }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateLabels sets whether to check the mandatory label validation criteria
 | 
			
		||||
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
 | 
			
		||||
// of hyphens ('-'), normalization, validity of runes, and the context rules.
 | 
			
		||||
func ValidateLabels(enable bool) Option {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		// Don't override existing mappings, but set one that at least checks
 | 
			
		||||
		// normalization if it is not set.
 | 
			
		||||
		if o.mapping == nil && enable {
 | 
			
		||||
			o.mapping = normalize
 | 
			
		||||
		}
 | 
			
		||||
		o.trie = trie
 | 
			
		||||
		o.validateLabels = enable
 | 
			
		||||
		o.fromPuny = validateFromPunycode
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StrictDomainName limits the set of permissable ASCII characters to those
 | 
			
		||||
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
 | 
			
		||||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration.
 | 
			
		||||
//
 | 
			
		||||
// This option is useful, for instance, for browsers that allow characters
 | 
			
		||||
// outside this range, for example a '_' (U+005F LOW LINE). See
 | 
			
		||||
// http://www.rfc-editor.org/std/std3.txt for more details This option
 | 
			
		||||
// corresponds to the UseSTD3ASCIIRules option in UTS #46.
 | 
			
		||||
func StrictDomainName(use bool) Option {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		o.trie = trie
 | 
			
		||||
		o.useSTD3Rules = use
 | 
			
		||||
		o.fromPuny = validateFromPunycode
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NOTE: the following options pull in tables. The tables should not be linked
 | 
			
		||||
// in as long as the options are not used.
 | 
			
		||||
 | 
			
		||||
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application
 | 
			
		||||
// that relies on proper validation of labels should include this rule.
 | 
			
		||||
func BidiRule() Option {
 | 
			
		||||
	return func(o *options) { o.bidirule = bidirule.ValidString }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateForRegistration sets validation options to verify that a given IDN is
 | 
			
		||||
// properly formatted for registration as defined by Section 4 of RFC 5891.
 | 
			
		||||
func ValidateForRegistration() Option {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		o.mapping = validateRegistration
 | 
			
		||||
		StrictDomainName(true)(o)
 | 
			
		||||
		ValidateLabels(true)(o)
 | 
			
		||||
		VerifyDNSLength(true)(o)
 | 
			
		||||
		BidiRule()(o)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapForLookup sets validation and mapping options such that a given IDN is
 | 
			
		||||
// transformed for domain name lookup according to the requirements set out in
 | 
			
		||||
// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894,
 | 
			
		||||
// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option
 | 
			
		||||
// to add this check.
 | 
			
		||||
//
 | 
			
		||||
// The mappings include normalization and mapping case, width and other
 | 
			
		||||
// compatibility mappings.
 | 
			
		||||
func MapForLookup() Option {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		o.mapping = validateAndMap
 | 
			
		||||
		StrictDomainName(true)(o)
 | 
			
		||||
		ValidateLabels(true)(o)
 | 
			
		||||
		RemoveLeadingDots(true)(o)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type options struct {
 | 
			
		||||
	transitional      bool
 | 
			
		||||
	useSTD3Rules      bool
 | 
			
		||||
	validateLabels    bool
 | 
			
		||||
	verifyDNSLength   bool
 | 
			
		||||
	removeLeadingDots bool
 | 
			
		||||
 | 
			
		||||
	trie *idnaTrie
 | 
			
		||||
 | 
			
		||||
	// fromPuny calls validation rules when converting A-labels to U-labels.
 | 
			
		||||
	fromPuny func(p *Profile, s string) error
 | 
			
		||||
 | 
			
		||||
	// mapping implements a validation and mapping step as defined in RFC 5895
 | 
			
		||||
	// or UTS 46, tailored to, for example, domain registration or lookup.
 | 
			
		||||
	mapping func(p *Profile, s string) (string, error)
 | 
			
		||||
 | 
			
		||||
	// bidirule, if specified, checks whether s conforms to the Bidi Rule
 | 
			
		||||
	// defined in RFC 5893.
 | 
			
		||||
	bidirule func(s string) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Profile defines the configuration of a IDNA mapper.
 | 
			
		||||
type Profile struct {
 | 
			
		||||
	options
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func apply(o *options, opts []Option) {
 | 
			
		||||
	for _, f := range opts {
 | 
			
		||||
		f(o)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new Profile.
 | 
			
		||||
//
 | 
			
		||||
// With no options, the returned Profile is the most permissive and equals the
 | 
			
		||||
// Punycode Profile. Options can be passed to further restrict the Profile. The
 | 
			
		||||
// MapForLookup and ValidateForRegistration options set a collection of options,
 | 
			
		||||
// for lookup and registration purposes respectively, which can be tailored by
 | 
			
		||||
// adding more fine-grained options, where later options override earlier
 | 
			
		||||
// options.
 | 
			
		||||
func New(o ...Option) *Profile {
 | 
			
		||||
	p := &Profile{}
 | 
			
		||||
	apply(&p.options, o)
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToASCII converts a domain or domain label to its ASCII form. For example,
 | 
			
		||||
// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
 | 
			
		||||
// ToASCII("golang") is "golang". If an error is encountered it will return
 | 
			
		||||
// an error and a (partially) processed result.
 | 
			
		||||
func (p *Profile) ToASCII(s string) (string, error) {
 | 
			
		||||
	return p.process(s, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToUnicode converts a domain or domain label to its Unicode form. For example,
 | 
			
		||||
// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and
 | 
			
		||||
// ToUnicode("golang") is "golang". If an error is encountered it will return
 | 
			
		||||
// an error and a (partially) processed result.
 | 
			
		||||
func (p *Profile) ToUnicode(s string) (string, error) {
 | 
			
		||||
	pp := *p
 | 
			
		||||
	pp.transitional = false
 | 
			
		||||
	return pp.process(s, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String reports a string with a description of the profile for debugging
 | 
			
		||||
// purposes. The string format may change with different versions.
 | 
			
		||||
func (p *Profile) String() string {
 | 
			
		||||
	s := ""
 | 
			
		||||
	if p.transitional {
 | 
			
		||||
		s = "Transitional"
 | 
			
		||||
	} else {
 | 
			
		||||
		s = "NonTransitional"
 | 
			
		||||
	}
 | 
			
		||||
	if p.useSTD3Rules {
 | 
			
		||||
		s += ":UseSTD3Rules"
 | 
			
		||||
	}
 | 
			
		||||
	if p.validateLabels {
 | 
			
		||||
		s += ":ValidateLabels"
 | 
			
		||||
	}
 | 
			
		||||
	if p.verifyDNSLength {
 | 
			
		||||
		s += ":VerifyDNSLength"
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// Punycode is a Profile that does raw punycode processing with a minimum
 | 
			
		||||
	// of validation.
 | 
			
		||||
	Punycode *Profile = punycode
 | 
			
		||||
 | 
			
		||||
	// Lookup is the recommended profile for looking up domain names, according
 | 
			
		||||
	// to Section 5 of RFC 5891. The exact configuration of this profile may
 | 
			
		||||
	// change over time.
 | 
			
		||||
	Lookup *Profile = lookup
 | 
			
		||||
 | 
			
		||||
	// Display is the recommended profile for displaying domain names.
 | 
			
		||||
	// The configuration of this profile may change over time.
 | 
			
		||||
	Display *Profile = display
 | 
			
		||||
 | 
			
		||||
	// Registration is the recommended profile for checking whether a given
 | 
			
		||||
	// IDN is valid for registration, according to Section 4 of RFC 5891.
 | 
			
		||||
	Registration *Profile = registration
 | 
			
		||||
 | 
			
		||||
	punycode = &Profile{}
 | 
			
		||||
	lookup   = &Profile{options{
 | 
			
		||||
		transitional:      true,
 | 
			
		||||
		useSTD3Rules:      true,
 | 
			
		||||
		validateLabels:    true,
 | 
			
		||||
		removeLeadingDots: true,
 | 
			
		||||
		trie:              trie,
 | 
			
		||||
		fromPuny:          validateFromPunycode,
 | 
			
		||||
		mapping:           validateAndMap,
 | 
			
		||||
		bidirule:          bidirule.ValidString,
 | 
			
		||||
	}}
 | 
			
		||||
	display = &Profile{options{
 | 
			
		||||
		useSTD3Rules:      true,
 | 
			
		||||
		validateLabels:    true,
 | 
			
		||||
		removeLeadingDots: true,
 | 
			
		||||
		trie:              trie,
 | 
			
		||||
		fromPuny:          validateFromPunycode,
 | 
			
		||||
		mapping:           validateAndMap,
 | 
			
		||||
		bidirule:          bidirule.ValidString,
 | 
			
		||||
	}}
 | 
			
		||||
	registration = &Profile{options{
 | 
			
		||||
		useSTD3Rules:    true,
 | 
			
		||||
		validateLabels:  true,
 | 
			
		||||
		verifyDNSLength: true,
 | 
			
		||||
		trie:            trie,
 | 
			
		||||
		fromPuny:        validateFromPunycode,
 | 
			
		||||
		mapping:         validateRegistration,
 | 
			
		||||
		bidirule:        bidirule.ValidString,
 | 
			
		||||
	}}
 | 
			
		||||
 | 
			
		||||
	// TODO: profiles
 | 
			
		||||
	// Register: recommended for approving domain names: don't do any mappings
 | 
			
		||||
	// but rather reject on invalid input. Bundle or block deviation characters.
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type labelError struct{ label, code_ string }
 | 
			
		||||
 | 
			
		||||
func (e labelError) code() string { return e.code_ }
 | 
			
		||||
func (e labelError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("idna: invalid label %q", e.label)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type runeError rune
 | 
			
		||||
 | 
			
		||||
func (e runeError) code() string { return "P1" }
 | 
			
		||||
func (e runeError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("idna: disallowed rune %U", e)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// process implements the algorithm described in section 4 of UTS #46,
 | 
			
		||||
// see https://www.unicode.org/reports/tr46.
 | 
			
		||||
func (p *Profile) process(s string, toASCII bool) (string, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	if p.mapping != nil {
 | 
			
		||||
		s, err = p.mapping(p, s)
 | 
			
		||||
	}
 | 
			
		||||
	// Remove leading empty labels.
 | 
			
		||||
	if p.removeLeadingDots {
 | 
			
		||||
		for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// It seems like we should only create this error on ToASCII, but the
 | 
			
		||||
	// UTS 46 conformance tests suggests we should always check this.
 | 
			
		||||
	if err == nil && p.verifyDNSLength && s == "" {
 | 
			
		||||
		err = &labelError{s, "A4"}
 | 
			
		||||
	}
 | 
			
		||||
	labels := labelIter{orig: s}
 | 
			
		||||
	for ; !labels.done(); labels.next() {
 | 
			
		||||
		label := labels.label()
 | 
			
		||||
		if label == "" {
 | 
			
		||||
			// Empty labels are not okay. The label iterator skips the last
 | 
			
		||||
			// label if it is empty.
 | 
			
		||||
			if err == nil && p.verifyDNSLength {
 | 
			
		||||
				err = &labelError{s, "A4"}
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasPrefix(label, acePrefix) {
 | 
			
		||||
			u, err2 := decode(label[len(acePrefix):])
 | 
			
		||||
			if err2 != nil {
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					err = err2
 | 
			
		||||
				}
 | 
			
		||||
				// Spec says keep the old label.
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			labels.set(u)
 | 
			
		||||
			if err == nil && p.validateLabels {
 | 
			
		||||
				err = p.fromPuny(p, u)
 | 
			
		||||
			}
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				// This should be called on NonTransitional, according to the
 | 
			
		||||
				// spec, but that currently does not have any effect. Use the
 | 
			
		||||
				// original profile to preserve options.
 | 
			
		||||
				err = p.validateLabel(u)
 | 
			
		||||
			}
 | 
			
		||||
		} else if err == nil {
 | 
			
		||||
			err = p.validateLabel(label)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if toASCII {
 | 
			
		||||
		for labels.reset(); !labels.done(); labels.next() {
 | 
			
		||||
			label := labels.label()
 | 
			
		||||
			if !ascii(label) {
 | 
			
		||||
				a, err2 := encode(acePrefix, label)
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					err = err2
 | 
			
		||||
				}
 | 
			
		||||
				label = a
 | 
			
		||||
				labels.set(a)
 | 
			
		||||
			}
 | 
			
		||||
			n := len(label)
 | 
			
		||||
			if p.verifyDNSLength && err == nil && (n == 0 || n > 63) {
 | 
			
		||||
				err = &labelError{label, "A4"}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	s = labels.result()
 | 
			
		||||
	if toASCII && p.verifyDNSLength && err == nil {
 | 
			
		||||
		// Compute the length of the domain name minus the root label and its dot.
 | 
			
		||||
		n := len(s)
 | 
			
		||||
		if n > 0 && s[n-1] == '.' {
 | 
			
		||||
			n--
 | 
			
		||||
		}
 | 
			
		||||
		if len(s) < 1 || n > 253 {
 | 
			
		||||
			err = &labelError{s, "A4"}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return s, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func normalize(p *Profile, s string) (string, error) {
 | 
			
		||||
	return norm.NFC.String(s), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateRegistration(p *Profile, s string) (string, error) {
 | 
			
		||||
	if !norm.NFC.IsNormalString(s) {
 | 
			
		||||
		return s, &labelError{s, "V1"}
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < len(s); {
 | 
			
		||||
		v, sz := trie.lookupString(s[i:])
 | 
			
		||||
		// Copy bytes not copied so far.
 | 
			
		||||
		switch p.simplify(info(v).category()) {
 | 
			
		||||
		// TODO: handle the NV8 defined in the Unicode idna data set to allow
 | 
			
		||||
		// for strict conformance to IDNA2008.
 | 
			
		||||
		case valid, deviation:
 | 
			
		||||
		case disallowed, mapped, unknown, ignored:
 | 
			
		||||
			r, _ := utf8.DecodeRuneInString(s[i:])
 | 
			
		||||
			return s, runeError(r)
 | 
			
		||||
		}
 | 
			
		||||
		i += sz
 | 
			
		||||
	}
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateAndMap(p *Profile, s string) (string, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err error
 | 
			
		||||
		b   []byte
 | 
			
		||||
		k   int
 | 
			
		||||
	)
 | 
			
		||||
	for i := 0; i < len(s); {
 | 
			
		||||
		v, sz := trie.lookupString(s[i:])
 | 
			
		||||
		start := i
 | 
			
		||||
		i += sz
 | 
			
		||||
		// Copy bytes not copied so far.
 | 
			
		||||
		switch p.simplify(info(v).category()) {
 | 
			
		||||
		case valid:
 | 
			
		||||
			continue
 | 
			
		||||
		case disallowed:
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				r, _ := utf8.DecodeRuneInString(s[start:])
 | 
			
		||||
				err = runeError(r)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		case mapped, deviation:
 | 
			
		||||
			b = append(b, s[k:start]...)
 | 
			
		||||
			b = info(v).appendMapping(b, s[start:i])
 | 
			
		||||
		case ignored:
 | 
			
		||||
			b = append(b, s[k:start]...)
 | 
			
		||||
			// drop the rune
 | 
			
		||||
		case unknown:
 | 
			
		||||
			b = append(b, s[k:start]...)
 | 
			
		||||
			b = append(b, "\ufffd"...)
 | 
			
		||||
		}
 | 
			
		||||
		k = i
 | 
			
		||||
	}
 | 
			
		||||
	if k == 0 {
 | 
			
		||||
		// No changes so far.
 | 
			
		||||
		s = norm.NFC.String(s)
 | 
			
		||||
	} else {
 | 
			
		||||
		b = append(b, s[k:]...)
 | 
			
		||||
		if norm.NFC.QuickSpan(b) != len(b) {
 | 
			
		||||
			b = norm.NFC.Bytes(b)
 | 
			
		||||
		}
 | 
			
		||||
		// TODO: the punycode converters require strings as input.
 | 
			
		||||
		s = string(b)
 | 
			
		||||
	}
 | 
			
		||||
	return s, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A labelIter allows iterating over domain name labels.
 | 
			
		||||
type labelIter struct {
 | 
			
		||||
	orig     string
 | 
			
		||||
	slice    []string
 | 
			
		||||
	curStart int
 | 
			
		||||
	curEnd   int
 | 
			
		||||
	i        int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) reset() {
 | 
			
		||||
	l.curStart = 0
 | 
			
		||||
	l.curEnd = 0
 | 
			
		||||
	l.i = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) done() bool {
 | 
			
		||||
	return l.curStart >= len(l.orig)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) result() string {
 | 
			
		||||
	if l.slice != nil {
 | 
			
		||||
		return strings.Join(l.slice, ".")
 | 
			
		||||
	}
 | 
			
		||||
	return l.orig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) label() string {
 | 
			
		||||
	if l.slice != nil {
 | 
			
		||||
		return l.slice[l.i]
 | 
			
		||||
	}
 | 
			
		||||
	p := strings.IndexByte(l.orig[l.curStart:], '.')
 | 
			
		||||
	l.curEnd = l.curStart + p
 | 
			
		||||
	if p == -1 {
 | 
			
		||||
		l.curEnd = len(l.orig)
 | 
			
		||||
	}
 | 
			
		||||
	return l.orig[l.curStart:l.curEnd]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// next sets the value to the next label. It skips the last label if it is empty.
 | 
			
		||||
func (l *labelIter) next() {
 | 
			
		||||
	l.i++
 | 
			
		||||
	if l.slice != nil {
 | 
			
		||||
		if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" {
 | 
			
		||||
			l.curStart = len(l.orig)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		l.curStart = l.curEnd + 1
 | 
			
		||||
		if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' {
 | 
			
		||||
			l.curStart = len(l.orig)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *labelIter) set(s string) {
 | 
			
		||||
	if l.slice == nil {
 | 
			
		||||
		l.slice = strings.Split(l.orig, ".")
 | 
			
		||||
	}
 | 
			
		||||
	l.slice[l.i] = s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// acePrefix is the ASCII Compatible Encoding prefix.
 | 
			
		||||
const acePrefix = "xn--"
 | 
			
		||||
 | 
			
		||||
func (p *Profile) simplify(cat category) category {
 | 
			
		||||
	switch cat {
 | 
			
		||||
	case disallowedSTD3Mapped:
 | 
			
		||||
		if p.useSTD3Rules {
 | 
			
		||||
			cat = disallowed
 | 
			
		||||
		} else {
 | 
			
		||||
			cat = mapped
 | 
			
		||||
		}
 | 
			
		||||
	case disallowedSTD3Valid:
 | 
			
		||||
		if p.useSTD3Rules {
 | 
			
		||||
			cat = disallowed
 | 
			
		||||
		} else {
 | 
			
		||||
			cat = valid
 | 
			
		||||
		}
 | 
			
		||||
	case deviation:
 | 
			
		||||
		if !p.transitional {
 | 
			
		||||
			cat = valid
 | 
			
		||||
		}
 | 
			
		||||
	case validNV8, validXV8:
 | 
			
		||||
		// TODO: handle V2008
 | 
			
		||||
		cat = valid
 | 
			
		||||
	}
 | 
			
		||||
	return cat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateFromPunycode(p *Profile, s string) error {
 | 
			
		||||
	if !norm.NFC.IsNormalString(s) {
 | 
			
		||||
		return &labelError{s, "V1"}
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < len(s); {
 | 
			
		||||
		v, sz := trie.lookupString(s[i:])
 | 
			
		||||
		if c := p.simplify(info(v).category()); c != valid && c != deviation {
 | 
			
		||||
			return &labelError{s, "V6"}
 | 
			
		||||
		}
 | 
			
		||||
		i += sz
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	zwnj = "\u200c"
 | 
			
		||||
	zwj  = "\u200d"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type joinState int8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	stateStart joinState = iota
 | 
			
		||||
	stateVirama
 | 
			
		||||
	stateBefore
 | 
			
		||||
	stateBeforeVirama
 | 
			
		||||
	stateAfter
 | 
			
		||||
	stateFAIL
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var joinStates = [][numJoinTypes]joinState{
 | 
			
		||||
	stateStart: {
 | 
			
		||||
		joiningL:   stateBefore,
 | 
			
		||||
		joiningD:   stateBefore,
 | 
			
		||||
		joinZWNJ:   stateFAIL,
 | 
			
		||||
		joinZWJ:    stateFAIL,
 | 
			
		||||
		joinVirama: stateVirama,
 | 
			
		||||
	},
 | 
			
		||||
	stateVirama: {
 | 
			
		||||
		joiningL: stateBefore,
 | 
			
		||||
		joiningD: stateBefore,
 | 
			
		||||
	},
 | 
			
		||||
	stateBefore: {
 | 
			
		||||
		joiningL:   stateBefore,
 | 
			
		||||
		joiningD:   stateBefore,
 | 
			
		||||
		joiningT:   stateBefore,
 | 
			
		||||
		joinZWNJ:   stateAfter,
 | 
			
		||||
		joinZWJ:    stateFAIL,
 | 
			
		||||
		joinVirama: stateBeforeVirama,
 | 
			
		||||
	},
 | 
			
		||||
	stateBeforeVirama: {
 | 
			
		||||
		joiningL: stateBefore,
 | 
			
		||||
		joiningD: stateBefore,
 | 
			
		||||
		joiningT: stateBefore,
 | 
			
		||||
	},
 | 
			
		||||
	stateAfter: {
 | 
			
		||||
		joiningL:   stateFAIL,
 | 
			
		||||
		joiningD:   stateBefore,
 | 
			
		||||
		joiningT:   stateAfter,
 | 
			
		||||
		joiningR:   stateStart,
 | 
			
		||||
		joinZWNJ:   stateFAIL,
 | 
			
		||||
		joinZWJ:    stateFAIL,
 | 
			
		||||
		joinVirama: stateAfter, // no-op as we can't accept joiners here
 | 
			
		||||
	},
 | 
			
		||||
	stateFAIL: {
 | 
			
		||||
		0:          stateFAIL,
 | 
			
		||||
		joiningL:   stateFAIL,
 | 
			
		||||
		joiningD:   stateFAIL,
 | 
			
		||||
		joiningT:   stateFAIL,
 | 
			
		||||
		joiningR:   stateFAIL,
 | 
			
		||||
		joinZWNJ:   stateFAIL,
 | 
			
		||||
		joinZWJ:    stateFAIL,
 | 
			
		||||
		joinVirama: stateFAIL,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are
 | 
			
		||||
// already implicitly satisfied by the overall implementation.
 | 
			
		||||
func (p *Profile) validateLabel(s string) error {
 | 
			
		||||
	if s == "" {
 | 
			
		||||
		if p.verifyDNSLength {
 | 
			
		||||
			return &labelError{s, "A4"}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if p.bidirule != nil && !p.bidirule(s) {
 | 
			
		||||
		return &labelError{s, "B"}
 | 
			
		||||
	}
 | 
			
		||||
	if !p.validateLabels {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	trie := p.trie // p.validateLabels is only set if trie is set.
 | 
			
		||||
	if len(s) > 4 && s[2] == '-' && s[3] == '-' {
 | 
			
		||||
		return &labelError{s, "V2"}
 | 
			
		||||
	}
 | 
			
		||||
	if s[0] == '-' || s[len(s)-1] == '-' {
 | 
			
		||||
		return &labelError{s, "V3"}
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: merge the use of this in the trie.
 | 
			
		||||
	v, sz := trie.lookupString(s)
 | 
			
		||||
	x := info(v)
 | 
			
		||||
	if x.isModifier() {
 | 
			
		||||
		return &labelError{s, "V5"}
 | 
			
		||||
	}
 | 
			
		||||
	// Quickly return in the absence of zero-width (non) joiners.
 | 
			
		||||
	if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	st := stateStart
 | 
			
		||||
	for i := 0; ; {
 | 
			
		||||
		jt := x.joinType()
 | 
			
		||||
		if s[i:i+sz] == zwj {
 | 
			
		||||
			jt = joinZWJ
 | 
			
		||||
		} else if s[i:i+sz] == zwnj {
 | 
			
		||||
			jt = joinZWNJ
 | 
			
		||||
		}
 | 
			
		||||
		st = joinStates[st][jt]
 | 
			
		||||
		if x.isViramaModifier() {
 | 
			
		||||
			st = joinStates[st][joinVirama]
 | 
			
		||||
		}
 | 
			
		||||
		if i += sz; i == len(s) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		v, sz = trie.lookupString(s[i:])
 | 
			
		||||
		x = info(v)
 | 
			
		||||
	}
 | 
			
		||||
	if st == stateFAIL || st == stateAfter {
 | 
			
		||||
		return &labelError{s, "C"}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ascii(s string) bool {
 | 
			
		||||
	for i := 0; i < len(s); i++ {
 | 
			
		||||
		if s[i] >= utf8.RuneSelf {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										203
									
								
								vendor/golang.org/x/net/idna/punycode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								vendor/golang.org/x/net/idna/punycode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
			
		||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
// Copyright 2016 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package idna
 | 
			
		||||
 | 
			
		||||
// This file implements the Punycode algorithm from RFC 3492.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"math"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// These parameter values are specified in section 5.
 | 
			
		||||
//
 | 
			
		||||
// All computation is done with int32s, so that overflow behavior is identical
 | 
			
		||||
// regardless of whether int is 32-bit or 64-bit.
 | 
			
		||||
const (
 | 
			
		||||
	base        int32 = 36
 | 
			
		||||
	damp        int32 = 700
 | 
			
		||||
	initialBias int32 = 72
 | 
			
		||||
	initialN    int32 = 128
 | 
			
		||||
	skew        int32 = 38
 | 
			
		||||
	tmax        int32 = 26
 | 
			
		||||
	tmin        int32 = 1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func punyError(s string) error { return &labelError{s, "A3"} }
 | 
			
		||||
 | 
			
		||||
// decode decodes a string as specified in section 6.2.
 | 
			
		||||
func decode(encoded string) (string, error) {
 | 
			
		||||
	if encoded == "" {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	pos := 1 + strings.LastIndex(encoded, "-")
 | 
			
		||||
	if pos == 1 {
 | 
			
		||||
		return "", punyError(encoded)
 | 
			
		||||
	}
 | 
			
		||||
	if pos == len(encoded) {
 | 
			
		||||
		return encoded[:len(encoded)-1], nil
 | 
			
		||||
	}
 | 
			
		||||
	output := make([]rune, 0, len(encoded))
 | 
			
		||||
	if pos != 0 {
 | 
			
		||||
		for _, r := range encoded[:pos-1] {
 | 
			
		||||
			output = append(output, r)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	i, n, bias := int32(0), initialN, initialBias
 | 
			
		||||
	for pos < len(encoded) {
 | 
			
		||||
		oldI, w := i, int32(1)
 | 
			
		||||
		for k := base; ; k += base {
 | 
			
		||||
			if pos == len(encoded) {
 | 
			
		||||
				return "", punyError(encoded)
 | 
			
		||||
			}
 | 
			
		||||
			digit, ok := decodeDigit(encoded[pos])
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return "", punyError(encoded)
 | 
			
		||||
			}
 | 
			
		||||
			pos++
 | 
			
		||||
			i += digit * w
 | 
			
		||||
			if i < 0 {
 | 
			
		||||
				return "", punyError(encoded)
 | 
			
		||||
			}
 | 
			
		||||
			t := k - bias
 | 
			
		||||
			if t < tmin {
 | 
			
		||||
				t = tmin
 | 
			
		||||
			} else if t > tmax {
 | 
			
		||||
				t = tmax
 | 
			
		||||
			}
 | 
			
		||||
			if digit < t {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			w *= base - t
 | 
			
		||||
			if w >= math.MaxInt32/base {
 | 
			
		||||
				return "", punyError(encoded)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		x := int32(len(output) + 1)
 | 
			
		||||
		bias = adapt(i-oldI, x, oldI == 0)
 | 
			
		||||
		n += i / x
 | 
			
		||||
		i %= x
 | 
			
		||||
		if n > utf8.MaxRune || len(output) >= 1024 {
 | 
			
		||||
			return "", punyError(encoded)
 | 
			
		||||
		}
 | 
			
		||||
		output = append(output, 0)
 | 
			
		||||
		copy(output[i+1:], output[i:])
 | 
			
		||||
		output[i] = n
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return string(output), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// encode encodes a string as specified in section 6.3 and prepends prefix to
 | 
			
		||||
// the result.
 | 
			
		||||
//
 | 
			
		||||
// The "while h < length(input)" line in the specification becomes "for
 | 
			
		||||
// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
 | 
			
		||||
func encode(prefix, s string) (string, error) {
 | 
			
		||||
	output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
 | 
			
		||||
	copy(output, prefix)
 | 
			
		||||
	delta, n, bias := int32(0), initialN, initialBias
 | 
			
		||||
	b, remaining := int32(0), int32(0)
 | 
			
		||||
	for _, r := range s {
 | 
			
		||||
		if r < 0x80 {
 | 
			
		||||
			b++
 | 
			
		||||
			output = append(output, byte(r))
 | 
			
		||||
		} else {
 | 
			
		||||
			remaining++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	h := b
 | 
			
		||||
	if b > 0 {
 | 
			
		||||
		output = append(output, '-')
 | 
			
		||||
	}
 | 
			
		||||
	for remaining != 0 {
 | 
			
		||||
		m := int32(0x7fffffff)
 | 
			
		||||
		for _, r := range s {
 | 
			
		||||
			if m > r && r >= n {
 | 
			
		||||
				m = r
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		delta += (m - n) * (h + 1)
 | 
			
		||||
		if delta < 0 {
 | 
			
		||||
			return "", punyError(s)
 | 
			
		||||
		}
 | 
			
		||||
		n = m
 | 
			
		||||
		for _, r := range s {
 | 
			
		||||
			if r < n {
 | 
			
		||||
				delta++
 | 
			
		||||
				if delta < 0 {
 | 
			
		||||
					return "", punyError(s)
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if r > n {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			q := delta
 | 
			
		||||
			for k := base; ; k += base {
 | 
			
		||||
				t := k - bias
 | 
			
		||||
				if t < tmin {
 | 
			
		||||
					t = tmin
 | 
			
		||||
				} else if t > tmax {
 | 
			
		||||
					t = tmax
 | 
			
		||||
				}
 | 
			
		||||
				if q < t {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
				output = append(output, encodeDigit(t+(q-t)%(base-t)))
 | 
			
		||||
				q = (q - t) / (base - t)
 | 
			
		||||
			}
 | 
			
		||||
			output = append(output, encodeDigit(q))
 | 
			
		||||
			bias = adapt(delta, h+1, h == b)
 | 
			
		||||
			delta = 0
 | 
			
		||||
			h++
 | 
			
		||||
			remaining--
 | 
			
		||||
		}
 | 
			
		||||
		delta++
 | 
			
		||||
		n++
 | 
			
		||||
	}
 | 
			
		||||
	return string(output), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func decodeDigit(x byte) (digit int32, ok bool) {
 | 
			
		||||
	switch {
 | 
			
		||||
	case '0' <= x && x <= '9':
 | 
			
		||||
		return int32(x - ('0' - 26)), true
 | 
			
		||||
	case 'A' <= x && x <= 'Z':
 | 
			
		||||
		return int32(x - 'A'), true
 | 
			
		||||
	case 'a' <= x && x <= 'z':
 | 
			
		||||
		return int32(x - 'a'), true
 | 
			
		||||
	}
 | 
			
		||||
	return 0, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func encodeDigit(digit int32) byte {
 | 
			
		||||
	switch {
 | 
			
		||||
	case 0 <= digit && digit < 26:
 | 
			
		||||
		return byte(digit + 'a')
 | 
			
		||||
	case 26 <= digit && digit < 36:
 | 
			
		||||
		return byte(digit + ('0' - 26))
 | 
			
		||||
	}
 | 
			
		||||
	panic("idna: internal error in punycode encoding")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// adapt is the bias adaptation function specified in section 6.1.
 | 
			
		||||
func adapt(delta, numPoints int32, firstTime bool) int32 {
 | 
			
		||||
	if firstTime {
 | 
			
		||||
		delta /= damp
 | 
			
		||||
	} else {
 | 
			
		||||
		delta /= 2
 | 
			
		||||
	}
 | 
			
		||||
	delta += delta / numPoints
 | 
			
		||||
	k := int32(0)
 | 
			
		||||
	for delta > ((base-tmin)*tmax)/2 {
 | 
			
		||||
		delta /= base - tmin
 | 
			
		||||
		k += base
 | 
			
		||||
	}
 | 
			
		||||
	return k + (base-tmin+1)*delta/(delta+skew)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4559
									
								
								vendor/golang.org/x/net/idna/tables10.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4559
									
								
								vendor/golang.org/x/net/idna/tables10.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4653
									
								
								vendor/golang.org/x/net/idna/tables11.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4653
									
								
								vendor/golang.org/x/net/idna/tables11.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4486
									
								
								vendor/golang.org/x/net/idna/tables9.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4486
									
								
								vendor/golang.org/x/net/idna/tables9.0.0.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										72
									
								
								vendor/golang.org/x/net/idna/trie.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								vendor/golang.org/x/net/idna/trie.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
// Copyright 2016 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package idna
 | 
			
		||||
 | 
			
		||||
// appendMapping appends the mapping for the respective rune. isMapped must be
 | 
			
		||||
// true. A mapping is a categorization of a rune as defined in UTS #46.
 | 
			
		||||
func (c info) appendMapping(b []byte, s string) []byte {
 | 
			
		||||
	index := int(c >> indexShift)
 | 
			
		||||
	if c&xorBit == 0 {
 | 
			
		||||
		s := mappings[index:]
 | 
			
		||||
		return append(b, s[1:s[0]+1]...)
 | 
			
		||||
	}
 | 
			
		||||
	b = append(b, s...)
 | 
			
		||||
	if c&inlineXOR == inlineXOR {
 | 
			
		||||
		// TODO: support and handle two-byte inline masks
 | 
			
		||||
		b[len(b)-1] ^= byte(index)
 | 
			
		||||
	} else {
 | 
			
		||||
		for p := len(b) - int(xorData[index]); p < len(b); p++ {
 | 
			
		||||
			index++
 | 
			
		||||
			b[p] ^= xorData[index]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sparse block handling code.
 | 
			
		||||
 | 
			
		||||
type valueRange struct {
 | 
			
		||||
	value  uint16 // header: value:stride
 | 
			
		||||
	lo, hi byte   // header: lo:n
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type sparseBlocks struct {
 | 
			
		||||
	values []valueRange
 | 
			
		||||
	offset []uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var idnaSparse = sparseBlocks{
 | 
			
		||||
	values: idnaSparseValues[:],
 | 
			
		||||
	offset: idnaSparseOffset[:],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Don't use newIdnaTrie to avoid unconditional linking in of the table.
 | 
			
		||||
var trie = &idnaTrie{}
 | 
			
		||||
 | 
			
		||||
// lookup determines the type of block n and looks up the value for b.
 | 
			
		||||
// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block
 | 
			
		||||
// is a list of ranges with an accompanying value. Given a matching range r,
 | 
			
		||||
// the value for b is by r.value + (b - r.lo) * stride.
 | 
			
		||||
func (t *sparseBlocks) lookup(n uint32, b byte) uint16 {
 | 
			
		||||
	offset := t.offset[n]
 | 
			
		||||
	header := t.values[offset]
 | 
			
		||||
	lo := offset + 1
 | 
			
		||||
	hi := lo + uint16(header.lo)
 | 
			
		||||
	for lo < hi {
 | 
			
		||||
		m := lo + (hi-lo)/2
 | 
			
		||||
		r := t.values[m]
 | 
			
		||||
		if r.lo <= b && b <= r.hi {
 | 
			
		||||
			return r.value + uint16(b-r.lo)*header.value
 | 
			
		||||
		}
 | 
			
		||||
		if b < r.lo {
 | 
			
		||||
			hi = m
 | 
			
		||||
		} else {
 | 
			
		||||
			lo = m + 1
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								vendor/golang.org/x/net/idna/trieval.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								vendor/golang.org/x/net/idna/trieval.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package idna
 | 
			
		||||
 | 
			
		||||
// This file contains definitions for interpreting the trie value of the idna
 | 
			
		||||
// trie generated by "go run gen*.go". It is shared by both the generator
 | 
			
		||||
// program and the resultant package. Sharing is achieved by the generator
 | 
			
		||||
// copying gen_trieval.go to trieval.go and changing what's above this comment.
 | 
			
		||||
 | 
			
		||||
// info holds information from the IDNA mapping table for a single rune. It is
 | 
			
		||||
// the value returned by a trie lookup. In most cases, all information fits in
 | 
			
		||||
// a 16-bit value. For mappings, this value may contain an index into a slice
 | 
			
		||||
// with the mapped string. Such mappings can consist of the actual mapped value
 | 
			
		||||
// or an XOR pattern to be applied to the bytes of the UTF8 encoding of the
 | 
			
		||||
// input rune. This technique is used by the cases packages and reduces the
 | 
			
		||||
// table size significantly.
 | 
			
		||||
//
 | 
			
		||||
// The per-rune values have the following format:
 | 
			
		||||
//
 | 
			
		||||
//   if mapped {
 | 
			
		||||
//     if inlinedXOR {
 | 
			
		||||
//       15..13 inline XOR marker
 | 
			
		||||
//       12..11 unused
 | 
			
		||||
//       10..3  inline XOR mask
 | 
			
		||||
//     } else {
 | 
			
		||||
//       15..3  index into xor or mapping table
 | 
			
		||||
//     }
 | 
			
		||||
//   } else {
 | 
			
		||||
//       15..14 unused
 | 
			
		||||
//       13     mayNeedNorm
 | 
			
		||||
//       12..11 attributes
 | 
			
		||||
//       10..8  joining type
 | 
			
		||||
//        7..3  category type
 | 
			
		||||
//   }
 | 
			
		||||
//      2  use xor pattern
 | 
			
		||||
//   1..0  mapped category
 | 
			
		||||
//
 | 
			
		||||
// See the definitions below for a more detailed description of the various
 | 
			
		||||
// bits.
 | 
			
		||||
type info uint16
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	catSmallMask = 0x3
 | 
			
		||||
	catBigMask   = 0xF8
 | 
			
		||||
	indexShift   = 3
 | 
			
		||||
	xorBit       = 0x4    // interpret the index as an xor pattern
 | 
			
		||||
	inlineXOR    = 0xE000 // These bits are set if the XOR pattern is inlined.
 | 
			
		||||
 | 
			
		||||
	joinShift = 8
 | 
			
		||||
	joinMask  = 0x07
 | 
			
		||||
 | 
			
		||||
	// Attributes
 | 
			
		||||
	attributesMask = 0x1800
 | 
			
		||||
	viramaModifier = 0x1800
 | 
			
		||||
	modifier       = 0x1000
 | 
			
		||||
	rtl            = 0x0800
 | 
			
		||||
 | 
			
		||||
	mayNeedNorm = 0x2000
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A category corresponds to a category defined in the IDNA mapping table.
 | 
			
		||||
type category uint16
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	unknown              category = 0 // not currently defined in unicode.
 | 
			
		||||
	mapped               category = 1
 | 
			
		||||
	disallowedSTD3Mapped category = 2
 | 
			
		||||
	deviation            category = 3
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	valid               category = 0x08
 | 
			
		||||
	validNV8            category = 0x18
 | 
			
		||||
	validXV8            category = 0x28
 | 
			
		||||
	disallowed          category = 0x40
 | 
			
		||||
	disallowedSTD3Valid category = 0x80
 | 
			
		||||
	ignored             category = 0xC0
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// join types and additional rune information
 | 
			
		||||
const (
 | 
			
		||||
	joiningL = (iota + 1)
 | 
			
		||||
	joiningD
 | 
			
		||||
	joiningT
 | 
			
		||||
	joiningR
 | 
			
		||||
 | 
			
		||||
	//the following types are derived during processing
 | 
			
		||||
	joinZWJ
 | 
			
		||||
	joinZWNJ
 | 
			
		||||
	joinVirama
 | 
			
		||||
	numJoinTypes
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (c info) isMapped() bool {
 | 
			
		||||
	return c&0x3 != 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c info) category() category {
 | 
			
		||||
	small := c & catSmallMask
 | 
			
		||||
	if small != 0 {
 | 
			
		||||
		return category(small)
 | 
			
		||||
	}
 | 
			
		||||
	return category(c & catBigMask)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c info) joinType() info {
 | 
			
		||||
	if c.isMapped() {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return (c >> joinShift) & joinMask
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c info) isModifier() bool {
 | 
			
		||||
	return c&(modifier|catSmallMask) == modifier
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c info) isViramaModifier() bool {
 | 
			
		||||
	return c&(attributesMask|catSmallMask) == viramaModifier
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										168
									
								
								vendor/golang.org/x/net/internal/socks/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								vendor/golang.org/x/net/internal/socks/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
// Copyright 2018 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package socks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	noDeadline   = time.Time{}
 | 
			
		||||
	aLongTimeAgo = time.Unix(1, 0)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
 | 
			
		||||
	host, port, err := splitHostPort(address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
 | 
			
		||||
		c.SetDeadline(deadline)
 | 
			
		||||
		defer c.SetDeadline(noDeadline)
 | 
			
		||||
	}
 | 
			
		||||
	if ctx != context.Background() {
 | 
			
		||||
		errCh := make(chan error, 1)
 | 
			
		||||
		done := make(chan struct{})
 | 
			
		||||
		defer func() {
 | 
			
		||||
			close(done)
 | 
			
		||||
			if ctxErr == nil {
 | 
			
		||||
				ctxErr = <-errCh
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
		go func() {
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ctx.Done():
 | 
			
		||||
				c.SetDeadline(aLongTimeAgo)
 | 
			
		||||
				errCh <- ctx.Err()
 | 
			
		||||
			case <-done:
 | 
			
		||||
				errCh <- nil
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
 | 
			
		||||
	b = append(b, Version5)
 | 
			
		||||
	if len(d.AuthMethods) == 0 || d.Authenticate == nil {
 | 
			
		||||
		b = append(b, 1, byte(AuthMethodNotRequired))
 | 
			
		||||
	} else {
 | 
			
		||||
		ams := d.AuthMethods
 | 
			
		||||
		if len(ams) > 255 {
 | 
			
		||||
			return nil, errors.New("too many authentication methods")
 | 
			
		||||
		}
 | 
			
		||||
		b = append(b, byte(len(ams)))
 | 
			
		||||
		for _, am := range ams {
 | 
			
		||||
			b = append(b, byte(am))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if _, ctxErr = c.Write(b); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if b[0] != Version5 {
 | 
			
		||||
		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
 | 
			
		||||
	}
 | 
			
		||||
	am := AuthMethod(b[1])
 | 
			
		||||
	if am == AuthMethodNoAcceptableMethods {
 | 
			
		||||
		return nil, errors.New("no acceptable authentication methods")
 | 
			
		||||
	}
 | 
			
		||||
	if d.Authenticate != nil {
 | 
			
		||||
		if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b = b[:0]
 | 
			
		||||
	b = append(b, Version5, byte(d.cmd), 0)
 | 
			
		||||
	if ip := net.ParseIP(host); ip != nil {
 | 
			
		||||
		if ip4 := ip.To4(); ip4 != nil {
 | 
			
		||||
			b = append(b, AddrTypeIPv4)
 | 
			
		||||
			b = append(b, ip4...)
 | 
			
		||||
		} else if ip6 := ip.To16(); ip6 != nil {
 | 
			
		||||
			b = append(b, AddrTypeIPv6)
 | 
			
		||||
			b = append(b, ip6...)
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, errors.New("unknown address type")
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if len(host) > 255 {
 | 
			
		||||
			return nil, errors.New("FQDN too long")
 | 
			
		||||
		}
 | 
			
		||||
		b = append(b, AddrTypeFQDN)
 | 
			
		||||
		b = append(b, byte(len(host)))
 | 
			
		||||
		b = append(b, host...)
 | 
			
		||||
	}
 | 
			
		||||
	b = append(b, byte(port>>8), byte(port))
 | 
			
		||||
	if _, ctxErr = c.Write(b); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if b[0] != Version5 {
 | 
			
		||||
		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
 | 
			
		||||
	}
 | 
			
		||||
	if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded {
 | 
			
		||||
		return nil, errors.New("unknown error " + cmdErr.String())
 | 
			
		||||
	}
 | 
			
		||||
	if b[2] != 0 {
 | 
			
		||||
		return nil, errors.New("non-zero reserved field")
 | 
			
		||||
	}
 | 
			
		||||
	l := 2
 | 
			
		||||
	var a Addr
 | 
			
		||||
	switch b[3] {
 | 
			
		||||
	case AddrTypeIPv4:
 | 
			
		||||
		l += net.IPv4len
 | 
			
		||||
		a.IP = make(net.IP, net.IPv4len)
 | 
			
		||||
	case AddrTypeIPv6:
 | 
			
		||||
		l += net.IPv6len
 | 
			
		||||
		a.IP = make(net.IP, net.IPv6len)
 | 
			
		||||
	case AddrTypeFQDN:
 | 
			
		||||
		if _, err := io.ReadFull(c, b[:1]); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		l += int(b[0])
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
 | 
			
		||||
	}
 | 
			
		||||
	if cap(b) < l {
 | 
			
		||||
		b = make([]byte, l)
 | 
			
		||||
	} else {
 | 
			
		||||
		b = b[:l]
 | 
			
		||||
	}
 | 
			
		||||
	if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if a.IP != nil {
 | 
			
		||||
		copy(a.IP, b)
 | 
			
		||||
	} else {
 | 
			
		||||
		a.Name = string(b[:len(b)-2])
 | 
			
		||||
	}
 | 
			
		||||
	a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
 | 
			
		||||
	return &a, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func splitHostPort(address string) (string, int, error) {
 | 
			
		||||
	host, port, err := net.SplitHostPort(address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", 0, err
 | 
			
		||||
	}
 | 
			
		||||
	portnum, err := strconv.Atoi(port)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if 1 > portnum || portnum > 0xffff {
 | 
			
		||||
		return "", 0, errors.New("port number out of range " + port)
 | 
			
		||||
	}
 | 
			
		||||
	return host, portnum, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										317
									
								
								vendor/golang.org/x/net/internal/socks/socks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										317
									
								
								vendor/golang.org/x/net/internal/socks/socks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,317 @@
 | 
			
		||||
// Copyright 2018 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package socks provides a SOCKS version 5 client implementation.
 | 
			
		||||
//
 | 
			
		||||
// SOCKS protocol version 5 is defined in RFC 1928.
 | 
			
		||||
// Username/Password authentication for SOCKS version 5 is defined in
 | 
			
		||||
// RFC 1929.
 | 
			
		||||
package socks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Command represents a SOCKS command.
 | 
			
		||||
type Command int
 | 
			
		||||
 | 
			
		||||
func (cmd Command) String() string {
 | 
			
		||||
	switch cmd {
 | 
			
		||||
	case CmdConnect:
 | 
			
		||||
		return "socks connect"
 | 
			
		||||
	case cmdBind:
 | 
			
		||||
		return "socks bind"
 | 
			
		||||
	default:
 | 
			
		||||
		return "socks " + strconv.Itoa(int(cmd))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An AuthMethod represents a SOCKS authentication method.
 | 
			
		||||
type AuthMethod int
 | 
			
		||||
 | 
			
		||||
// A Reply represents a SOCKS command reply code.
 | 
			
		||||
type Reply int
 | 
			
		||||
 | 
			
		||||
func (code Reply) String() string {
 | 
			
		||||
	switch code {
 | 
			
		||||
	case StatusSucceeded:
 | 
			
		||||
		return "succeeded"
 | 
			
		||||
	case 0x01:
 | 
			
		||||
		return "general SOCKS server failure"
 | 
			
		||||
	case 0x02:
 | 
			
		||||
		return "connection not allowed by ruleset"
 | 
			
		||||
	case 0x03:
 | 
			
		||||
		return "network unreachable"
 | 
			
		||||
	case 0x04:
 | 
			
		||||
		return "host unreachable"
 | 
			
		||||
	case 0x05:
 | 
			
		||||
		return "connection refused"
 | 
			
		||||
	case 0x06:
 | 
			
		||||
		return "TTL expired"
 | 
			
		||||
	case 0x07:
 | 
			
		||||
		return "command not supported"
 | 
			
		||||
	case 0x08:
 | 
			
		||||
		return "address type not supported"
 | 
			
		||||
	default:
 | 
			
		||||
		return "unknown code: " + strconv.Itoa(int(code))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wire protocol constants.
 | 
			
		||||
const (
 | 
			
		||||
	Version5 = 0x05
 | 
			
		||||
 | 
			
		||||
	AddrTypeIPv4 = 0x01
 | 
			
		||||
	AddrTypeFQDN = 0x03
 | 
			
		||||
	AddrTypeIPv6 = 0x04
 | 
			
		||||
 | 
			
		||||
	CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
 | 
			
		||||
	cmdBind    Command = 0x02 // establishes a passive-open forward proxy connection
 | 
			
		||||
 | 
			
		||||
	AuthMethodNotRequired         AuthMethod = 0x00 // no authentication required
 | 
			
		||||
	AuthMethodUsernamePassword    AuthMethod = 0x02 // use username/password
 | 
			
		||||
	AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
 | 
			
		||||
 | 
			
		||||
	StatusSucceeded Reply = 0x00
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// An Addr represents a SOCKS-specific address.
 | 
			
		||||
// Either Name or IP is used exclusively.
 | 
			
		||||
type Addr struct {
 | 
			
		||||
	Name string // fully-qualified domain name
 | 
			
		||||
	IP   net.IP
 | 
			
		||||
	Port int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *Addr) Network() string { return "socks" }
 | 
			
		||||
 | 
			
		||||
func (a *Addr) String() string {
 | 
			
		||||
	if a == nil {
 | 
			
		||||
		return "<nil>"
 | 
			
		||||
	}
 | 
			
		||||
	port := strconv.Itoa(a.Port)
 | 
			
		||||
	if a.IP == nil {
 | 
			
		||||
		return net.JoinHostPort(a.Name, port)
 | 
			
		||||
	}
 | 
			
		||||
	return net.JoinHostPort(a.IP.String(), port)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Conn represents a forward proxy connection.
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	net.Conn
 | 
			
		||||
 | 
			
		||||
	boundAddr net.Addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BoundAddr returns the address assigned by the proxy server for
 | 
			
		||||
// connecting to the command target address from the proxy server.
 | 
			
		||||
func (c *Conn) BoundAddr() net.Addr {
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return c.boundAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Dialer holds SOCKS-specific options.
 | 
			
		||||
type Dialer struct {
 | 
			
		||||
	cmd          Command // either CmdConnect or cmdBind
 | 
			
		||||
	proxyNetwork string  // network between a proxy server and a client
 | 
			
		||||
	proxyAddress string  // proxy server address
 | 
			
		||||
 | 
			
		||||
	// ProxyDial specifies the optional dial function for
 | 
			
		||||
	// establishing the transport connection.
 | 
			
		||||
	ProxyDial func(context.Context, string, string) (net.Conn, error)
 | 
			
		||||
 | 
			
		||||
	// AuthMethods specifies the list of request authention
 | 
			
		||||
	// methods.
 | 
			
		||||
	// If empty, SOCKS client requests only AuthMethodNotRequired.
 | 
			
		||||
	AuthMethods []AuthMethod
 | 
			
		||||
 | 
			
		||||
	// Authenticate specifies the optional authentication
 | 
			
		||||
	// function. It must be non-nil when AuthMethods is not empty.
 | 
			
		||||
	// It must return an error when the authentication is failed.
 | 
			
		||||
	Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialContext connects to the provided address on the provided
 | 
			
		||||
// network.
 | 
			
		||||
//
 | 
			
		||||
// The returned error value may be a net.OpError. When the Op field of
 | 
			
		||||
// net.OpError contains "socks", the Source field contains a proxy
 | 
			
		||||
// server address and the Addr field contains a command target
 | 
			
		||||
// address.
 | 
			
		||||
//
 | 
			
		||||
// See func Dial of the net package of standard library for a
 | 
			
		||||
// description of the network and address parameters.
 | 
			
		||||
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
 | 
			
		||||
	if err := d.validateTarget(network, address); err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	if ctx == nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
 | 
			
		||||
	}
 | 
			
		||||
	var err error
 | 
			
		||||
	var c net.Conn
 | 
			
		||||
	if d.ProxyDial != nil {
 | 
			
		||||
		c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
 | 
			
		||||
	} else {
 | 
			
		||||
		var dd net.Dialer
 | 
			
		||||
		c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	a, err := d.connect(ctx, c, address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.Close()
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return &Conn{Conn: c, boundAddr: a}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialWithConn initiates a connection from SOCKS server to the target
 | 
			
		||||
// network and address using the connection c that is already
 | 
			
		||||
// connected to the SOCKS server.
 | 
			
		||||
//
 | 
			
		||||
// It returns the connection's local address assigned by the SOCKS
 | 
			
		||||
// server.
 | 
			
		||||
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
 | 
			
		||||
	if err := d.validateTarget(network, address); err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	if ctx == nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
 | 
			
		||||
	}
 | 
			
		||||
	a, err := d.connect(ctx, c, address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return a, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial connects to the provided address on the provided network.
 | 
			
		||||
//
 | 
			
		||||
// Unlike DialContext, it returns a raw transport connection instead
 | 
			
		||||
// of a forward proxy connection.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: Use DialContext or DialWithConn instead.
 | 
			
		||||
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
 | 
			
		||||
	if err := d.validateTarget(network, address); err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	var err error
 | 
			
		||||
	var c net.Conn
 | 
			
		||||
	if d.ProxyDial != nil {
 | 
			
		||||
		c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
 | 
			
		||||
	} else {
 | 
			
		||||
		c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
 | 
			
		||||
		c.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Dialer) validateTarget(network, address string) error {
 | 
			
		||||
	switch network {
 | 
			
		||||
	case "tcp", "tcp6", "tcp4":
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.New("network not implemented")
 | 
			
		||||
	}
 | 
			
		||||
	switch d.cmd {
 | 
			
		||||
	case CmdConnect, cmdBind:
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.New("command not implemented")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
 | 
			
		||||
	for i, s := range []string{d.proxyAddress, address} {
 | 
			
		||||
		host, port, err := splitHostPort(s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		a := &Addr{Port: port}
 | 
			
		||||
		a.IP = net.ParseIP(host)
 | 
			
		||||
		if a.IP == nil {
 | 
			
		||||
			a.Name = host
 | 
			
		||||
		}
 | 
			
		||||
		if i == 0 {
 | 
			
		||||
			proxy = a
 | 
			
		||||
		} else {
 | 
			
		||||
			dst = a
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewDialer returns a new Dialer that dials through the provided
 | 
			
		||||
// proxy server's network and address.
 | 
			
		||||
func NewDialer(network, address string) *Dialer {
 | 
			
		||||
	return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	authUsernamePasswordVersion = 0x01
 | 
			
		||||
	authStatusSucceeded         = 0x00
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// UsernamePassword are the credentials for the username/password
 | 
			
		||||
// authentication method.
 | 
			
		||||
type UsernamePassword struct {
 | 
			
		||||
	Username string
 | 
			
		||||
	Password string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Authenticate authenticates a pair of username and password with the
 | 
			
		||||
// proxy server.
 | 
			
		||||
func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error {
 | 
			
		||||
	switch auth {
 | 
			
		||||
	case AuthMethodNotRequired:
 | 
			
		||||
		return nil
 | 
			
		||||
	case AuthMethodUsernamePassword:
 | 
			
		||||
		if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 {
 | 
			
		||||
			return errors.New("invalid username/password")
 | 
			
		||||
		}
 | 
			
		||||
		b := []byte{authUsernamePasswordVersion}
 | 
			
		||||
		b = append(b, byte(len(up.Username)))
 | 
			
		||||
		b = append(b, up.Username...)
 | 
			
		||||
		b = append(b, byte(len(up.Password)))
 | 
			
		||||
		b = append(b, up.Password...)
 | 
			
		||||
		// TODO(mikio): handle IO deadlines and cancelation if
 | 
			
		||||
		// necessary
 | 
			
		||||
		if _, err := rw.Write(b); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if _, err := io.ReadFull(rw, b[:2]); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if b[0] != authUsernamePasswordVersion {
 | 
			
		||||
			return errors.New("invalid username/password version")
 | 
			
		||||
		}
 | 
			
		||||
		if b[1] != authStatusSucceeded {
 | 
			
		||||
			return errors.New("username/password authentication failed")
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								vendor/golang.org/x/net/proxy/dial.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/golang.org/x/net/proxy/dial.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
// Copyright 2019 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package proxy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A ContextDialer dials using a context.
 | 
			
		||||
type ContextDialer interface {
 | 
			
		||||
	DialContext(ctx context.Context, network, address string) (net.Conn, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment.
 | 
			
		||||
//
 | 
			
		||||
// The passed ctx is only used for returning the Conn, not the lifetime of the Conn.
 | 
			
		||||
//
 | 
			
		||||
// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer
 | 
			
		||||
// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout.
 | 
			
		||||
//
 | 
			
		||||
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
 | 
			
		||||
func Dial(ctx context.Context, network, address string) (net.Conn, error) {
 | 
			
		||||
	d := FromEnvironment()
 | 
			
		||||
	if xd, ok := d.(ContextDialer); ok {
 | 
			
		||||
		return xd.DialContext(ctx, network, address)
 | 
			
		||||
	}
 | 
			
		||||
	return dialContext(ctx, d, network, address)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout
 | 
			
		||||
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
 | 
			
		||||
func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		conn net.Conn
 | 
			
		||||
		done = make(chan struct{}, 1)
 | 
			
		||||
		err  error
 | 
			
		||||
	)
 | 
			
		||||
	go func() {
 | 
			
		||||
		conn, err = d.Dial(network, address)
 | 
			
		||||
		close(done)
 | 
			
		||||
		if conn != nil && ctx.Err() != nil {
 | 
			
		||||
			conn.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
		err = ctx.Err()
 | 
			
		||||
	case <-done:
 | 
			
		||||
	}
 | 
			
		||||
	return conn, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/golang.org/x/net/proxy/direct.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/golang.org/x/net/proxy/direct.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package proxy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type direct struct{}
 | 
			
		||||
 | 
			
		||||
// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext.
 | 
			
		||||
var Direct = direct{}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	_ Dialer        = Direct
 | 
			
		||||
	_ ContextDialer = Direct
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Dial directly invokes net.Dial with the supplied parameters.
 | 
			
		||||
func (direct) Dial(network, addr string) (net.Conn, error) {
 | 
			
		||||
	return net.Dial(network, addr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters.
 | 
			
		||||
func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
 | 
			
		||||
	var d net.Dialer
 | 
			
		||||
	return d.DialContext(ctx, network, addr)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										155
									
								
								vendor/golang.org/x/net/proxy/per_host.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								vendor/golang.org/x/net/proxy/per_host.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package proxy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A PerHost directs connections to a default Dialer unless the host name
 | 
			
		||||
// requested matches one of a number of exceptions.
 | 
			
		||||
type PerHost struct {
 | 
			
		||||
	def, bypass Dialer
 | 
			
		||||
 | 
			
		||||
	bypassNetworks []*net.IPNet
 | 
			
		||||
	bypassIPs      []net.IP
 | 
			
		||||
	bypassZones    []string
 | 
			
		||||
	bypassHosts    []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewPerHost returns a PerHost Dialer that directs connections to either
 | 
			
		||||
// defaultDialer or bypass, depending on whether the connection matches one of
 | 
			
		||||
// the configured rules.
 | 
			
		||||
func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
 | 
			
		||||
	return &PerHost{
 | 
			
		||||
		def:    defaultDialer,
 | 
			
		||||
		bypass: bypass,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial connects to the address addr on the given network through either
 | 
			
		||||
// defaultDialer or bypass.
 | 
			
		||||
func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
 | 
			
		||||
	host, _, err := net.SplitHostPort(addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return p.dialerForRequest(host).Dial(network, addr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialContext connects to the address addr on the given network through either
 | 
			
		||||
// defaultDialer or bypass.
 | 
			
		||||
func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) {
 | 
			
		||||
	host, _, err := net.SplitHostPort(addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	d := p.dialerForRequest(host)
 | 
			
		||||
	if x, ok := d.(ContextDialer); ok {
 | 
			
		||||
		return x.DialContext(ctx, network, addr)
 | 
			
		||||
	}
 | 
			
		||||
	return dialContext(ctx, d, network, addr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *PerHost) dialerForRequest(host string) Dialer {
 | 
			
		||||
	if ip := net.ParseIP(host); ip != nil {
 | 
			
		||||
		for _, net := range p.bypassNetworks {
 | 
			
		||||
			if net.Contains(ip) {
 | 
			
		||||
				return p.bypass
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for _, bypassIP := range p.bypassIPs {
 | 
			
		||||
			if bypassIP.Equal(ip) {
 | 
			
		||||
				return p.bypass
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return p.def
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, zone := range p.bypassZones {
 | 
			
		||||
		if strings.HasSuffix(host, zone) {
 | 
			
		||||
			return p.bypass
 | 
			
		||||
		}
 | 
			
		||||
		if host == zone[1:] {
 | 
			
		||||
			// For a zone ".example.com", we match "example.com"
 | 
			
		||||
			// too.
 | 
			
		||||
			return p.bypass
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, bypassHost := range p.bypassHosts {
 | 
			
		||||
		if bypassHost == host {
 | 
			
		||||
			return p.bypass
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return p.def
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddFromString parses a string that contains comma-separated values
 | 
			
		||||
// specifying hosts that should use the bypass proxy. Each value is either an
 | 
			
		||||
// IP address, a CIDR range, a zone (*.example.com) or a host name
 | 
			
		||||
// (localhost). A best effort is made to parse the string and errors are
 | 
			
		||||
// ignored.
 | 
			
		||||
func (p *PerHost) AddFromString(s string) {
 | 
			
		||||
	hosts := strings.Split(s, ",")
 | 
			
		||||
	for _, host := range hosts {
 | 
			
		||||
		host = strings.TrimSpace(host)
 | 
			
		||||
		if len(host) == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.Contains(host, "/") {
 | 
			
		||||
			// We assume that it's a CIDR address like 127.0.0.0/8
 | 
			
		||||
			if _, net, err := net.ParseCIDR(host); err == nil {
 | 
			
		||||
				p.AddNetwork(net)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if ip := net.ParseIP(host); ip != nil {
 | 
			
		||||
			p.AddIP(ip)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasPrefix(host, "*.") {
 | 
			
		||||
			p.AddZone(host[1:])
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		p.AddHost(host)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddIP specifies an IP address that will use the bypass proxy. Note that
 | 
			
		||||
// this will only take effect if a literal IP address is dialed. A connection
 | 
			
		||||
// to a named host will never match an IP.
 | 
			
		||||
func (p *PerHost) AddIP(ip net.IP) {
 | 
			
		||||
	p.bypassIPs = append(p.bypassIPs, ip)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddNetwork specifies an IP range that will use the bypass proxy. Note that
 | 
			
		||||
// this will only take effect if a literal IP address is dialed. A connection
 | 
			
		||||
// to a named host will never match.
 | 
			
		||||
func (p *PerHost) AddNetwork(net *net.IPNet) {
 | 
			
		||||
	p.bypassNetworks = append(p.bypassNetworks, net)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
 | 
			
		||||
// "example.com" matches "example.com" and all of its subdomains.
 | 
			
		||||
func (p *PerHost) AddZone(zone string) {
 | 
			
		||||
	if strings.HasSuffix(zone, ".") {
 | 
			
		||||
		zone = zone[:len(zone)-1]
 | 
			
		||||
	}
 | 
			
		||||
	if !strings.HasPrefix(zone, ".") {
 | 
			
		||||
		zone = "." + zone
 | 
			
		||||
	}
 | 
			
		||||
	p.bypassZones = append(p.bypassZones, zone)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddHost specifies a host name that will use the bypass proxy.
 | 
			
		||||
func (p *PerHost) AddHost(host string) {
 | 
			
		||||
	if strings.HasSuffix(host, ".") {
 | 
			
		||||
		host = host[:len(host)-1]
 | 
			
		||||
	}
 | 
			
		||||
	p.bypassHosts = append(p.bypassHosts, host)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										149
									
								
								vendor/golang.org/x/net/proxy/proxy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								vendor/golang.org/x/net/proxy/proxy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package proxy provides support for a variety of protocols to proxy network
 | 
			
		||||
// data.
 | 
			
		||||
package proxy // import "golang.org/x/net/proxy"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Dialer is a means to establish a connection.
 | 
			
		||||
// Custom dialers should also implement ContextDialer.
 | 
			
		||||
type Dialer interface {
 | 
			
		||||
	// Dial connects to the given address via the proxy.
 | 
			
		||||
	Dial(network, addr string) (c net.Conn, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Auth contains authentication parameters that specific Dialers may require.
 | 
			
		||||
type Auth struct {
 | 
			
		||||
	User, Password string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromEnvironment returns the dialer specified by the proxy-related
 | 
			
		||||
// variables in the environment and makes underlying connections
 | 
			
		||||
// directly.
 | 
			
		||||
func FromEnvironment() Dialer {
 | 
			
		||||
	return FromEnvironmentUsing(Direct)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromEnvironmentUsing returns the dialer specify by the proxy-related
 | 
			
		||||
// variables in the environment and makes underlying connections
 | 
			
		||||
// using the provided forwarding Dialer (for instance, a *net.Dialer
 | 
			
		||||
// with desired configuration).
 | 
			
		||||
func FromEnvironmentUsing(forward Dialer) Dialer {
 | 
			
		||||
	allProxy := allProxyEnv.Get()
 | 
			
		||||
	if len(allProxy) == 0 {
 | 
			
		||||
		return forward
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	proxyURL, err := url.Parse(allProxy)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return forward
 | 
			
		||||
	}
 | 
			
		||||
	proxy, err := FromURL(proxyURL, forward)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return forward
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	noProxy := noProxyEnv.Get()
 | 
			
		||||
	if len(noProxy) == 0 {
 | 
			
		||||
		return proxy
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	perHost := NewPerHost(proxy, forward)
 | 
			
		||||
	perHost.AddFromString(noProxy)
 | 
			
		||||
	return perHost
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// proxySchemes is a map from URL schemes to a function that creates a Dialer
 | 
			
		||||
// from a URL with such a scheme.
 | 
			
		||||
var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
 | 
			
		||||
 | 
			
		||||
// RegisterDialerType takes a URL scheme and a function to generate Dialers from
 | 
			
		||||
// a URL with that scheme and a forwarding Dialer. Registered schemes are used
 | 
			
		||||
// by FromURL.
 | 
			
		||||
func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
 | 
			
		||||
	if proxySchemes == nil {
 | 
			
		||||
		proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
 | 
			
		||||
	}
 | 
			
		||||
	proxySchemes[scheme] = f
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromURL returns a Dialer given a URL specification and an underlying
 | 
			
		||||
// Dialer for it to make network requests.
 | 
			
		||||
func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
 | 
			
		||||
	var auth *Auth
 | 
			
		||||
	if u.User != nil {
 | 
			
		||||
		auth = new(Auth)
 | 
			
		||||
		auth.User = u.User.Username()
 | 
			
		||||
		if p, ok := u.User.Password(); ok {
 | 
			
		||||
			auth.Password = p
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch u.Scheme {
 | 
			
		||||
	case "socks5", "socks5h":
 | 
			
		||||
		addr := u.Hostname()
 | 
			
		||||
		port := u.Port()
 | 
			
		||||
		if port == "" {
 | 
			
		||||
			port = "1080"
 | 
			
		||||
		}
 | 
			
		||||
		return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the scheme doesn't match any of the built-in schemes, see if it
 | 
			
		||||
	// was registered by another package.
 | 
			
		||||
	if proxySchemes != nil {
 | 
			
		||||
		if f, ok := proxySchemes[u.Scheme]; ok {
 | 
			
		||||
			return f(u, forward)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	allProxyEnv = &envOnce{
 | 
			
		||||
		names: []string{"ALL_PROXY", "all_proxy"},
 | 
			
		||||
	}
 | 
			
		||||
	noProxyEnv = &envOnce{
 | 
			
		||||
		names: []string{"NO_PROXY", "no_proxy"},
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// envOnce looks up an environment variable (optionally by multiple
 | 
			
		||||
// names) once. It mitigates expensive lookups on some platforms
 | 
			
		||||
// (e.g. Windows).
 | 
			
		||||
// (Borrowed from net/http/transport.go)
 | 
			
		||||
type envOnce struct {
 | 
			
		||||
	names []string
 | 
			
		||||
	once  sync.Once
 | 
			
		||||
	val   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *envOnce) Get() string {
 | 
			
		||||
	e.once.Do(e.init)
 | 
			
		||||
	return e.val
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *envOnce) init() {
 | 
			
		||||
	for _, n := range e.names {
 | 
			
		||||
		e.val = os.Getenv(n)
 | 
			
		||||
		if e.val != "" {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// reset is used by tests
 | 
			
		||||
func (e *envOnce) reset() {
 | 
			
		||||
	e.once = sync.Once{}
 | 
			
		||||
	e.val = ""
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								vendor/golang.org/x/net/proxy/socks5.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/golang.org/x/net/proxy/socks5.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package proxy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/internal/socks"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given
 | 
			
		||||
// address with an optional username and password.
 | 
			
		||||
// See RFC 1928 and RFC 1929.
 | 
			
		||||
func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) {
 | 
			
		||||
	d := socks.NewDialer(network, address)
 | 
			
		||||
	if forward != nil {
 | 
			
		||||
		if f, ok := forward.(ContextDialer); ok {
 | 
			
		||||
			d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
 | 
			
		||||
				return f.DialContext(ctx, network, address)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
 | 
			
		||||
				return dialContext(ctx, forward, network, address)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if auth != nil {
 | 
			
		||||
		up := socks.UsernamePassword{
 | 
			
		||||
			Username: auth.User,
 | 
			
		||||
			Password: auth.Password,
 | 
			
		||||
		}
 | 
			
		||||
		d.AuthMethods = []socks.AuthMethod{
 | 
			
		||||
			socks.AuthMethodNotRequired,
 | 
			
		||||
			socks.AuthMethodUsernamePassword,
 | 
			
		||||
		}
 | 
			
		||||
		d.Authenticate = up.Authenticate
 | 
			
		||||
	}
 | 
			
		||||
	return d, nil
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user