mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 09:24:23 +00:00
change golang.org/x/net to be the same revision as used in kubernetes
This commit is contained in:
15
vendor/golang.org/x/net/CONTRIBUTING.md
generated
vendored
15
vendor/golang.org/x/net/CONTRIBUTING.md
generated
vendored
@@ -4,15 +4,16 @@ Go is an open source project.
|
||||
|
||||
It is the work of hundreds of contributors. We appreciate your help!
|
||||
|
||||
|
||||
## Filing issues
|
||||
|
||||
When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
|
||||
|
||||
1. What version of Go are you using (`go version`)?
|
||||
2. What operating system and processor architecture are you using?
|
||||
3. What did you do?
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
1. What version of Go are you using (`go version`)?
|
||||
2. What operating system and processor architecture are you using?
|
||||
3. What did you do?
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
|
||||
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
|
||||
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||
@@ -22,5 +23,9 @@ The gophers there will answer or ask you to file an issue if you've tripped over
|
||||
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
|
||||
before sending patches.
|
||||
|
||||
**We do not accept GitHub pull requests**
|
||||
(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed under
|
||||
the BSD-style license found in the LICENSE file.
|
||||
|
||||
|
||||
3
vendor/golang.org/x/net/README
generated
vendored
Normal file
3
vendor/golang.org/x/net/README
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
This repository holds supplementary Go networking libraries.
|
||||
|
||||
To submit changes to this repository, see http://golang.org/doc/contribute.html.
|
||||
16
vendor/golang.org/x/net/README.md
generated
vendored
16
vendor/golang.org/x/net/README.md
generated
vendored
@@ -1,16 +0,0 @@
|
||||
# Go Networking
|
||||
|
||||
This repository holds supplementary Go networking libraries.
|
||||
|
||||
## Download/Install
|
||||
|
||||
The easiest way to install is to run `go get -u golang.org/x/net`. You can
|
||||
also manually git clone the repository to `$GOPATH/src/golang.org/x/net`.
|
||||
|
||||
## Report Issues / Send Patches
|
||||
|
||||
This repository uses Gerrit for code changes. To learn how to submit
|
||||
changes to this repository, see https://golang.org/doc/contribute.html.
|
||||
The main issue tracker for the net repository is located at
|
||||
https://github.com/golang/go/issues. Prefix your issue with "x/net:" in the
|
||||
subject line, so it is easy to find.
|
||||
32
vendor/golang.org/x/net/bpf/instructions.go
generated
vendored
32
vendor/golang.org/x/net/bpf/instructions.go
generated
vendored
@@ -198,7 +198,7 @@ func (a LoadConstant) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a LoadConstant) String() string {
|
||||
switch a.Dst {
|
||||
case RegA:
|
||||
@@ -224,7 +224,7 @@ func (a LoadScratch) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a LoadScratch) String() string {
|
||||
switch a.Dst {
|
||||
case RegA:
|
||||
@@ -248,7 +248,7 @@ func (a LoadAbsolute) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a LoadAbsolute) String() string {
|
||||
switch a.Size {
|
||||
case 1: // byte
|
||||
@@ -277,7 +277,7 @@ func (a LoadIndirect) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a LoadIndirect) String() string {
|
||||
switch a.Size {
|
||||
case 1: // byte
|
||||
@@ -306,7 +306,7 @@ func (a LoadMemShift) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a LoadMemShift) String() string {
|
||||
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
|
||||
}
|
||||
@@ -325,7 +325,7 @@ func (a LoadExtension) Assemble() (RawInstruction, error) {
|
||||
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a LoadExtension) String() string {
|
||||
switch a.Num {
|
||||
case ExtLen:
|
||||
@@ -392,7 +392,7 @@ func (a StoreScratch) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a StoreScratch) String() string {
|
||||
switch a.Src {
|
||||
case RegA:
|
||||
@@ -418,7 +418,7 @@ func (a ALUOpConstant) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a ALUOpConstant) String() string {
|
||||
switch a.Op {
|
||||
case ALUOpAdd:
|
||||
@@ -458,7 +458,7 @@ func (a ALUOpX) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a ALUOpX) String() string {
|
||||
switch a.Op {
|
||||
case ALUOpAdd:
|
||||
@@ -496,7 +496,7 @@ func (a NegateA) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a NegateA) String() string {
|
||||
return fmt.Sprintf("neg")
|
||||
}
|
||||
@@ -514,7 +514,7 @@ func (a Jump) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a Jump) String() string {
|
||||
return fmt.Sprintf("ja %d", a.Skip)
|
||||
}
|
||||
@@ -566,7 +566,7 @@ func (a JumpIf) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a JumpIf) String() string {
|
||||
switch a.Cond {
|
||||
// K == A
|
||||
@@ -621,7 +621,7 @@ func (a RetA) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a RetA) String() string {
|
||||
return fmt.Sprintf("ret a")
|
||||
}
|
||||
@@ -639,7 +639,7 @@ func (a RetConstant) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a RetConstant) String() string {
|
||||
return fmt.Sprintf("ret #%d", a.Val)
|
||||
}
|
||||
@@ -654,7 +654,7 @@ func (a TXA) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a TXA) String() string {
|
||||
return fmt.Sprintf("txa")
|
||||
}
|
||||
@@ -669,7 +669,7 @@ func (a TAX) Assemble() (RawInstruction, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the instruction in assembler notation.
|
||||
// String returns the the instruction in assembler notation.
|
||||
func (a TAX) String() string {
|
||||
return fmt.Sprintf("tax")
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/net/context/context.go
generated
vendored
2
vendor/golang.org/x/net/context/context.go
generated
vendored
@@ -5,8 +5,6 @@
|
||||
// Package context defines the Context type, which carries deadlines,
|
||||
// cancelation signals, and other request-scoped values across API boundaries
|
||||
// and between processes.
|
||||
// As of Go 1.7 this package is available in the standard library under the
|
||||
// name context. https://golang.org/pkg/context.
|
||||
//
|
||||
// Incoming requests to a server should create a Context, and outgoing calls to
|
||||
// servers should accept a Context. The chain of function calls between must
|
||||
|
||||
8
vendor/golang.org/x/net/dns/dnsmessage/example_test.go
generated
vendored
8
vendor/golang.org/x/net/dns/dnsmessage/example_test.go
generated
vendored
@@ -37,20 +37,20 @@ func ExampleParser() {
|
||||
},
|
||||
Answers: []dnsmessage.Resource{
|
||||
{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
dnsmessage.ResourceHeader{
|
||||
Name: mustNewName("foo.bar.example.com."),
|
||||
Type: dnsmessage.TypeA,
|
||||
Class: dnsmessage.ClassINET,
|
||||
},
|
||||
Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}},
|
||||
&dnsmessage.AResource{[4]byte{127, 0, 0, 1}},
|
||||
},
|
||||
{
|
||||
Header: dnsmessage.ResourceHeader{
|
||||
dnsmessage.ResourceHeader{
|
||||
Name: mustNewName("bar.example.com."),
|
||||
Type: dnsmessage.TypeA,
|
||||
Class: dnsmessage.ClassINET,
|
||||
},
|
||||
Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 2}},
|
||||
&dnsmessage.AResource{[4]byte{127, 0, 0, 2}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
454
vendor/golang.org/x/net/dns/dnsmessage/message.go
generated
vendored
454
vendor/golang.org/x/net/dns/dnsmessage/message.go
generated
vendored
@@ -5,9 +5,6 @@
|
||||
// Package dnsmessage provides a mostly RFC 1035 compliant implementation of
|
||||
// DNS message packing and unpacking.
|
||||
//
|
||||
// The package also supports messages with Extension Mechanisms for DNS
|
||||
// (EDNS(0)) as defined in RFC 6891.
|
||||
//
|
||||
// This implementation is designed to minimize heap allocations and avoid
|
||||
// unnecessary packing and unpacking as much as possible.
|
||||
package dnsmessage
|
||||
@@ -16,7 +13,7 @@ import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Message formats
|
||||
// Packet formats
|
||||
|
||||
// A Type is a type of DNS request and response.
|
||||
type Type uint16
|
||||
@@ -42,7 +39,6 @@ const (
|
||||
TypeTXT Type = 16
|
||||
TypeAAAA Type = 28
|
||||
TypeSRV Type = 33
|
||||
TypeOPT Type = 41
|
||||
|
||||
// Question.Type
|
||||
TypeWKS Type = 11
|
||||
@@ -94,8 +90,6 @@ var (
|
||||
errTooManyAuthorities = errors.New("too many Authorities to pack (>65535)")
|
||||
errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)")
|
||||
errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)")
|
||||
errStringTooLong = errors.New("character string exceeds maximum length (255)")
|
||||
errCompressedSRV = errors.New("compressed name in SRV resource data")
|
||||
)
|
||||
|
||||
// Internal constants.
|
||||
@@ -224,7 +218,6 @@ func (h *header) count(sec section) uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// pack appends the wire format of the header to msg.
|
||||
func (h *header) pack(msg []byte) []byte {
|
||||
msg = packUint16(msg, h.id)
|
||||
msg = packUint16(msg, h.bits)
|
||||
@@ -280,26 +273,25 @@ type Resource struct {
|
||||
// A ResourceBody is a DNS resource record minus the header.
|
||||
type ResourceBody interface {
|
||||
// pack packs a Resource except for its header.
|
||||
pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error)
|
||||
pack(msg []byte, compression map[string]int) ([]byte, error)
|
||||
|
||||
// realType returns the actual type of the Resource. This is used to
|
||||
// fill in the header Type field.
|
||||
realType() Type
|
||||
}
|
||||
|
||||
// pack appends the wire format of the Resource to msg.
|
||||
func (r *Resource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
func (r *Resource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
if r.Body == nil {
|
||||
return msg, errNilResouceBody
|
||||
}
|
||||
oldMsg := msg
|
||||
r.Header.Type = r.Body.realType()
|
||||
msg, length, err := r.Header.pack(msg, compression, compressionOff)
|
||||
msg, length, err := r.Header.pack(msg, compression)
|
||||
if err != nil {
|
||||
return msg, &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
msg, err = r.Body.pack(msg, compression, compressionOff)
|
||||
msg, err = r.Body.pack(msg, compression)
|
||||
if err != nil {
|
||||
return msg, &nestedError{"content", err}
|
||||
}
|
||||
@@ -444,13 +436,7 @@ func (p *Parser) Question() (Question, error) {
|
||||
|
||||
// AllQuestions parses all Questions.
|
||||
func (p *Parser) AllQuestions() ([]Question, error) {
|
||||
// Multiple questions are valid according to the spec,
|
||||
// but servers don't actually support them. There will
|
||||
// be at most one question here.
|
||||
//
|
||||
// Do not pre-allocate based on info in p.header, since
|
||||
// the data is untrusted.
|
||||
qs := []Question{}
|
||||
qs := make([]Question, 0, p.header.questions)
|
||||
for {
|
||||
q, err := p.Question()
|
||||
if err == ErrSectionDone {
|
||||
@@ -506,16 +492,7 @@ func (p *Parser) Answer() (Resource, error) {
|
||||
|
||||
// AllAnswers parses all Answer Resources.
|
||||
func (p *Parser) AllAnswers() ([]Resource, error) {
|
||||
// The most common query is for A/AAAA, which usually returns
|
||||
// a handful of IPs.
|
||||
//
|
||||
// Pre-allocate up to a certain limit, since p.header is
|
||||
// untrusted data.
|
||||
n := int(p.header.answers)
|
||||
if n > 20 {
|
||||
n = 20
|
||||
}
|
||||
as := make([]Resource, 0, n)
|
||||
as := make([]Resource, 0, p.header.answers)
|
||||
for {
|
||||
a, err := p.Answer()
|
||||
if err == ErrSectionDone {
|
||||
@@ -556,16 +533,7 @@ func (p *Parser) Authority() (Resource, error) {
|
||||
|
||||
// AllAuthorities parses all Authority Resources.
|
||||
func (p *Parser) AllAuthorities() ([]Resource, error) {
|
||||
// Authorities contains SOA in case of NXDOMAIN and friends,
|
||||
// otherwise it is empty.
|
||||
//
|
||||
// Pre-allocate up to a certain limit, since p.header is
|
||||
// untrusted data.
|
||||
n := int(p.header.authorities)
|
||||
if n > 10 {
|
||||
n = 10
|
||||
}
|
||||
as := make([]Resource, 0, n)
|
||||
as := make([]Resource, 0, p.header.authorities)
|
||||
for {
|
||||
a, err := p.Authority()
|
||||
if err == ErrSectionDone {
|
||||
@@ -606,16 +574,7 @@ func (p *Parser) Additional() (Resource, error) {
|
||||
|
||||
// AllAdditionals parses all Additional Resources.
|
||||
func (p *Parser) AllAdditionals() ([]Resource, error) {
|
||||
// Additionals usually contain OPT, and sometimes A/AAAA
|
||||
// glue records.
|
||||
//
|
||||
// Pre-allocate up to a certain limit, since p.header is
|
||||
// untrusted data.
|
||||
n := int(p.header.additionals)
|
||||
if n > 10 {
|
||||
n = 10
|
||||
}
|
||||
as := make([]Resource, 0, n)
|
||||
as := make([]Resource, 0, p.header.additionals)
|
||||
for {
|
||||
a, err := p.Additional()
|
||||
if err == ErrSectionDone {
|
||||
@@ -806,24 +765,6 @@ func (p *Parser) AAAAResource() (AAAAResource, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// OPTResource parses a single OPTResource.
|
||||
//
|
||||
// One of the XXXHeader methods must have been called before calling this
|
||||
// method.
|
||||
func (p *Parser) OPTResource() (OPTResource, error) {
|
||||
if !p.resHeaderValid || p.resHeader.Type != TypeOPT {
|
||||
return OPTResource{}, ErrNotStarted
|
||||
}
|
||||
r, err := unpackOPTResource(p.msg, p.off, p.resHeader.Length)
|
||||
if err != nil {
|
||||
return OPTResource{}, err
|
||||
}
|
||||
p.off += int(p.resHeader.Length)
|
||||
p.resHeaderValid = false
|
||||
p.index++
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Unpack parses a full Message.
|
||||
func (m *Message) Unpack(msg []byte) error {
|
||||
var p Parser
|
||||
@@ -848,12 +789,6 @@ func (m *Message) Unpack(msg []byte) error {
|
||||
|
||||
// Pack packs a full Message.
|
||||
func (m *Message) Pack() ([]byte, error) {
|
||||
return m.AppendPack(make([]byte, 0, packStartingCap))
|
||||
}
|
||||
|
||||
// AppendPack is like Pack but appends the full Message to b and returns the
|
||||
// extended buffer.
|
||||
func (m *Message) AppendPack(b []byte) ([]byte, error) {
|
||||
// Validate the lengths. It is very unlikely that anyone will try to
|
||||
// pack more than 65535 of any particular type, but it is possible and
|
||||
// we should fail gracefully.
|
||||
@@ -878,40 +813,41 @@ func (m *Message) AppendPack(b []byte) ([]byte, error) {
|
||||
h.authorities = uint16(len(m.Authorities))
|
||||
h.additionals = uint16(len(m.Additionals))
|
||||
|
||||
compressionOff := len(b)
|
||||
msg := h.pack(b)
|
||||
msg := make([]byte, 0, packStartingCap)
|
||||
|
||||
msg = h.pack(msg)
|
||||
|
||||
// RFC 1035 allows (but does not require) compression for packing. RFC
|
||||
// 1035 requires unpacking implementations to support compression, so
|
||||
// unconditionally enabling it is fine.
|
||||
//
|
||||
// DNS lookups are typically done over UDP, and RFC 1035 states that UDP
|
||||
// DNS messages can be a maximum of 512 bytes long. Without compression,
|
||||
// many DNS response messages are over this limit, so enabling
|
||||
// DNS packets can be a maximum of 512 bytes long. Without compression,
|
||||
// many DNS response packets are over this limit, so enabling
|
||||
// compression will help ensure compliance.
|
||||
compression := map[string]int{}
|
||||
|
||||
for i := range m.Questions {
|
||||
var err error
|
||||
if msg, err = m.Questions[i].pack(msg, compression, compressionOff); err != nil {
|
||||
if msg, err = m.Questions[i].pack(msg, compression); err != nil {
|
||||
return nil, &nestedError{"packing Question", err}
|
||||
}
|
||||
}
|
||||
for i := range m.Answers {
|
||||
var err error
|
||||
if msg, err = m.Answers[i].pack(msg, compression, compressionOff); err != nil {
|
||||
if msg, err = m.Answers[i].pack(msg, compression); err != nil {
|
||||
return nil, &nestedError{"packing Answer", err}
|
||||
}
|
||||
}
|
||||
for i := range m.Authorities {
|
||||
var err error
|
||||
if msg, err = m.Authorities[i].pack(msg, compression, compressionOff); err != nil {
|
||||
if msg, err = m.Authorities[i].pack(msg, compression); err != nil {
|
||||
return nil, &nestedError{"packing Authority", err}
|
||||
}
|
||||
}
|
||||
for i := range m.Additionals {
|
||||
var err error
|
||||
if msg, err = m.Additionals[i].pack(msg, compression, compressionOff); err != nil {
|
||||
if msg, err = m.Additionals[i].pack(msg, compression); err != nil {
|
||||
return nil, &nestedError{"packing Additional", err}
|
||||
}
|
||||
}
|
||||
@@ -920,69 +856,36 @@ func (m *Message) AppendPack(b []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// A Builder allows incrementally packing a DNS message.
|
||||
//
|
||||
// Example usage:
|
||||
// buf := make([]byte, 2, 514)
|
||||
// b := NewBuilder(buf, Header{...})
|
||||
// b.EnableCompression()
|
||||
// // Optionally start a section and add things to that section.
|
||||
// // Repeat adding sections as necessary.
|
||||
// buf, err := b.Finish()
|
||||
// // If err is nil, buf[2:] will contain the built bytes.
|
||||
type Builder struct {
|
||||
// msg is the storage for the message being built.
|
||||
msg []byte
|
||||
|
||||
// section keeps track of the current section being built.
|
||||
section section
|
||||
|
||||
// header keeps track of what should go in the header when Finish is
|
||||
// called.
|
||||
header header
|
||||
|
||||
// start is the starting index of the bytes allocated in msg for header.
|
||||
start int
|
||||
|
||||
// compression is a mapping from name suffixes to their starting index
|
||||
// in msg.
|
||||
msg []byte
|
||||
header header
|
||||
section section
|
||||
compression map[string]int
|
||||
}
|
||||
|
||||
// NewBuilder creates a new builder with compression disabled.
|
||||
// Start initializes the builder.
|
||||
//
|
||||
// Note: Most users will want to immediately enable compression with the
|
||||
// EnableCompression method. See that method's comment for why you may or may
|
||||
// not want to enable compression.
|
||||
//
|
||||
// The DNS message is appended to the provided initial buffer buf (which may be
|
||||
// nil) as it is built. The final message is returned by the (*Builder).Finish
|
||||
// method, which may return the same underlying array if there was sufficient
|
||||
// capacity in the slice.
|
||||
func NewBuilder(buf []byte, h Header) Builder {
|
||||
if buf == nil {
|
||||
buf = make([]byte, 0, packStartingCap)
|
||||
}
|
||||
b := Builder{msg: buf, start: len(buf)}
|
||||
b.header.id, b.header.bits = h.pack()
|
||||
var hb [headerLen]byte
|
||||
b.msg = append(b.msg, hb[:]...)
|
||||
b.section = sectionHeader
|
||||
return b
|
||||
// buf is optional (nil is fine), but if provided, Start takes ownership of buf.
|
||||
func (b *Builder) Start(buf []byte, h Header) {
|
||||
b.StartWithoutCompression(buf, h)
|
||||
b.compression = map[string]int{}
|
||||
}
|
||||
|
||||
// EnableCompression enables compression in the Builder.
|
||||
// StartWithoutCompression initializes the builder with compression disabled.
|
||||
//
|
||||
// Leaving compression disabled avoids compression related allocations, but can
|
||||
// result in larger message sizes. Be careful with this mode as it can cause
|
||||
// messages to exceed the UDP size limit.
|
||||
// This avoids compression related allocations, but can result in larger message
|
||||
// sizes. Be careful with this mode as it can cause messages to exceed the UDP
|
||||
// size limit.
|
||||
//
|
||||
// According to RFC 1035, section 4.1.4, the use of compression is optional, but
|
||||
// all implementations must accept both compressed and uncompressed DNS
|
||||
// messages.
|
||||
//
|
||||
// Compression should be enabled before any sections are added for best results.
|
||||
func (b *Builder) EnableCompression() {
|
||||
b.compression = map[string]int{}
|
||||
// buf is optional (nil is fine), but if provided, Start takes ownership of buf.
|
||||
func (b *Builder) StartWithoutCompression(buf []byte, h Header) {
|
||||
*b = Builder{msg: buf}
|
||||
b.header.id, b.header.bits = h.pack()
|
||||
if cap(b.msg) < headerLen {
|
||||
b.msg = make([]byte, 0, packStartingCap)
|
||||
}
|
||||
b.msg = b.msg[:headerLen]
|
||||
b.section = sectionHeader
|
||||
}
|
||||
|
||||
func (b *Builder) startCheck(s section) error {
|
||||
@@ -1063,7 +966,7 @@ func (b *Builder) Question(q Question) error {
|
||||
if b.section > sectionQuestions {
|
||||
return ErrSectionDone
|
||||
}
|
||||
msg, err := q.pack(b.msg, b.compression, b.start)
|
||||
msg, err := q.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1090,12 +993,12 @@ func (b *Builder) CNAMEResource(h ResourceHeader, r CNAMEResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"CNAMEResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1114,12 +1017,12 @@ func (b *Builder) MXResource(h ResourceHeader, r MXResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"MXResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1138,12 +1041,12 @@ func (b *Builder) NSResource(h ResourceHeader, r NSResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"NSResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1162,12 +1065,12 @@ func (b *Builder) PTRResource(h ResourceHeader, r PTRResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"PTRResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1186,12 +1089,12 @@ func (b *Builder) SOAResource(h ResourceHeader, r SOAResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"SOAResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1210,12 +1113,12 @@ func (b *Builder) TXTResource(h ResourceHeader, r TXTResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"TXTResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1234,12 +1137,12 @@ func (b *Builder) SRVResource(h ResourceHeader, r SRVResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"SRVResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1258,12 +1161,12 @@ func (b *Builder) AResource(h ResourceHeader, r AResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"AResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1282,12 +1185,12 @@ func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
msg, length, err := h.pack(b.msg, b.compression)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
if msg, err = r.pack(msg, b.compression); err != nil {
|
||||
return &nestedError{"AAAAResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
@@ -1300,38 +1203,13 @@ func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OPTResource adds a single OPTResource.
|
||||
func (b *Builder) OPTResource(h ResourceHeader, r OPTResource) error {
|
||||
if err := b.checkResourceSection(); err != nil {
|
||||
return err
|
||||
}
|
||||
h.Type = r.realType()
|
||||
msg, length, err := h.pack(b.msg, b.compression, b.start)
|
||||
if err != nil {
|
||||
return &nestedError{"ResourceHeader", err}
|
||||
}
|
||||
preLen := len(msg)
|
||||
if msg, err = r.pack(msg, b.compression, b.start); err != nil {
|
||||
return &nestedError{"OPTResource body", err}
|
||||
}
|
||||
if err := h.fixLen(msg, length, preLen); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.incrementSectionCount(); err != nil {
|
||||
return err
|
||||
}
|
||||
b.msg = msg
|
||||
return nil
|
||||
}
|
||||
|
||||
// Finish ends message building and generates a binary message.
|
||||
// Finish ends message building and generates a binary packet.
|
||||
func (b *Builder) Finish() ([]byte, error) {
|
||||
if b.section < sectionHeader {
|
||||
return nil, ErrNotStarted
|
||||
}
|
||||
b.section = sectionDone
|
||||
// Space for the header was allocated in NewBuilder.
|
||||
b.header.pack(b.msg[b.start:b.start])
|
||||
b.header.pack(b.msg[:0])
|
||||
return b.msg, nil
|
||||
}
|
||||
|
||||
@@ -1361,13 +1239,12 @@ type ResourceHeader struct {
|
||||
Length uint16
|
||||
}
|
||||
|
||||
// pack appends the wire format of the ResourceHeader to oldMsg.
|
||||
//
|
||||
// The bytes where length was packed are returned as a slice so they can be
|
||||
// updated after the rest of the Resource has been packed.
|
||||
func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]int, compressionOff int) (msg []byte, length []byte, err error) {
|
||||
// pack packs all of the fields in a ResourceHeader except for the length. The
|
||||
// length bytes are returned as a slice so they can be filled in after the rest
|
||||
// of the Resource has been packed.
|
||||
func (h *ResourceHeader) pack(oldMsg []byte, compression map[string]int) (msg []byte, length []byte, err error) {
|
||||
msg = oldMsg
|
||||
if msg, err = h.Name.pack(msg, compression, compressionOff); err != nil {
|
||||
if msg, err = h.Name.pack(msg, compression); err != nil {
|
||||
return oldMsg, nil, &nestedError{"Name", err}
|
||||
}
|
||||
msg = packType(msg, h.Type)
|
||||
@@ -1412,44 +1289,6 @@ func (h *ResourceHeader) fixLen(msg []byte, length []byte, preLen int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// EDNS(0) wire costants.
|
||||
const (
|
||||
edns0Version = 0
|
||||
|
||||
edns0DNSSECOK = 0x00008000
|
||||
ednsVersionMask = 0x00ff0000
|
||||
edns0DNSSECOKMask = 0x00ff8000
|
||||
)
|
||||
|
||||
// SetEDNS0 configures h for EDNS(0).
|
||||
//
|
||||
// The provided extRCode must be an extedned RCode.
|
||||
func (h *ResourceHeader) SetEDNS0(udpPayloadLen int, extRCode RCode, dnssecOK bool) error {
|
||||
h.Name = Name{Data: [nameLen]byte{'.'}, Length: 1} // RFC 6891 section 6.1.2
|
||||
h.Type = TypeOPT
|
||||
h.Class = Class(udpPayloadLen)
|
||||
h.TTL = uint32(extRCode) >> 4 << 24
|
||||
if dnssecOK {
|
||||
h.TTL |= edns0DNSSECOK
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DNSSECAllowed reports whether the DNSSEC OK bit is set.
|
||||
func (h *ResourceHeader) DNSSECAllowed() bool {
|
||||
return h.TTL&edns0DNSSECOKMask == edns0DNSSECOK // RFC 6891 section 6.1.3
|
||||
}
|
||||
|
||||
// ExtendedRCode returns an extended RCode.
|
||||
//
|
||||
// The provided rcode must be the RCode in DNS message header.
|
||||
func (h *ResourceHeader) ExtendedRCode(rcode RCode) RCode {
|
||||
if h.TTL&ednsVersionMask == edns0Version { // RFC 6891 section 6.1.3
|
||||
return RCode(h.TTL>>24<<4) | rcode
|
||||
}
|
||||
return rcode
|
||||
}
|
||||
|
||||
func skipResource(msg []byte, off int) (int, error) {
|
||||
newOff, err := skipName(msg, off)
|
||||
if err != nil {
|
||||
@@ -1474,7 +1313,6 @@ func skipResource(msg []byte, off int) (int, error) {
|
||||
return newOff, nil
|
||||
}
|
||||
|
||||
// packUint16 appends the wire format of field to msg.
|
||||
func packUint16(msg []byte, field uint16) []byte {
|
||||
return append(msg, byte(field>>8), byte(field))
|
||||
}
|
||||
@@ -1493,7 +1331,6 @@ func skipUint16(msg []byte, off int) (int, error) {
|
||||
return off + uint16Len, nil
|
||||
}
|
||||
|
||||
// packType appends the wire format of field to msg.
|
||||
func packType(msg []byte, field Type) []byte {
|
||||
return packUint16(msg, uint16(field))
|
||||
}
|
||||
@@ -1507,7 +1344,6 @@ func skipType(msg []byte, off int) (int, error) {
|
||||
return skipUint16(msg, off)
|
||||
}
|
||||
|
||||
// packClass appends the wire format of field to msg.
|
||||
func packClass(msg []byte, field Class) []byte {
|
||||
return packUint16(msg, uint16(field))
|
||||
}
|
||||
@@ -1521,7 +1357,6 @@ func skipClass(msg []byte, off int) (int, error) {
|
||||
return skipUint16(msg, off)
|
||||
}
|
||||
|
||||
// packUint32 appends the wire format of field to msg.
|
||||
func packUint32(msg []byte, field uint32) []byte {
|
||||
return append(
|
||||
msg,
|
||||
@@ -1547,16 +1382,17 @@ func skipUint32(msg []byte, off int) (int, error) {
|
||||
return off + uint32Len, nil
|
||||
}
|
||||
|
||||
// packText appends the wire format of field to msg.
|
||||
func packText(msg []byte, field string) ([]byte, error) {
|
||||
l := len(field)
|
||||
if l > 255 {
|
||||
return nil, errStringTooLong
|
||||
func packText(msg []byte, field string) []byte {
|
||||
for len(field) > 0 {
|
||||
l := len(field)
|
||||
if l > 255 {
|
||||
l = 255
|
||||
}
|
||||
msg = append(msg, byte(l))
|
||||
msg = append(msg, field[:l]...)
|
||||
field = field[l:]
|
||||
}
|
||||
msg = append(msg, byte(l))
|
||||
msg = append(msg, field...)
|
||||
|
||||
return msg, nil
|
||||
return msg
|
||||
}
|
||||
|
||||
func unpackText(msg []byte, off int) (string, int, error) {
|
||||
@@ -1582,7 +1418,6 @@ func skipText(msg []byte, off int) (int, error) {
|
||||
return endOff, nil
|
||||
}
|
||||
|
||||
// packBytes appends the wire format of field to msg.
|
||||
func packBytes(msg []byte, field []byte) []byte {
|
||||
return append(msg, field...)
|
||||
}
|
||||
@@ -1627,14 +1462,14 @@ func (n Name) String() string {
|
||||
return string(n.Data[:n.Length])
|
||||
}
|
||||
|
||||
// pack appends the wire format of the Name to msg.
|
||||
// pack packs a domain name.
|
||||
//
|
||||
// Domain names are a sequence of counted strings split at the dots. They end
|
||||
// with a zero-length string. Compression can be used to reuse domain suffixes.
|
||||
//
|
||||
// The compression map will be updated with new domain suffixes. If compression
|
||||
// is nil, compression will not be used.
|
||||
func (n *Name) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
func (n *Name) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
oldMsg := msg
|
||||
|
||||
// Add a trailing dot to canonicalize name.
|
||||
@@ -1686,7 +1521,7 @@ func (n *Name) pack(msg []byte, compression map[string]int, compressionOff int)
|
||||
// Miss. Add the suffix to the compression table if the
|
||||
// offset can be stored in the available 14 bytes.
|
||||
if len(msg) <= int(^uint16(0)>>2) {
|
||||
compression[string(n.Data[i:])] = len(msg) - compressionOff
|
||||
compression[string(n.Data[i:])] = len(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1695,10 +1530,6 @@ func (n *Name) pack(msg []byte, compression map[string]int, compressionOff int)
|
||||
|
||||
// unpack unpacks a domain name.
|
||||
func (n *Name) unpack(msg []byte, off int) (int, error) {
|
||||
return n.unpackCompressed(msg, off, true /* allowCompression */)
|
||||
}
|
||||
|
||||
func (n *Name) unpackCompressed(msg []byte, off int, allowCompression bool) (int, error) {
|
||||
// currOff is the current working offset.
|
||||
currOff := off
|
||||
|
||||
@@ -1734,9 +1565,6 @@ Loop:
|
||||
name = append(name, '.')
|
||||
currOff = endOff
|
||||
case 0xC0: // Pointer
|
||||
if !allowCompression {
|
||||
return off, errCompressedSRV
|
||||
}
|
||||
if currOff >= len(msg) {
|
||||
return off, errInvalidPtr
|
||||
}
|
||||
@@ -1816,9 +1644,8 @@ type Question struct {
|
||||
Class Class
|
||||
}
|
||||
|
||||
// pack appends the wire format of the Question to msg.
|
||||
func (q *Question) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
msg, err := q.Name.pack(msg, compression, compressionOff)
|
||||
func (q *Question) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
msg, err := q.Name.pack(msg, compression)
|
||||
if err != nil {
|
||||
return msg, &nestedError{"Name", err}
|
||||
}
|
||||
@@ -1878,11 +1705,6 @@ func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody,
|
||||
rb, err = unpackSRVResource(msg, off)
|
||||
r = &rb
|
||||
name = "SRV"
|
||||
case TypeOPT:
|
||||
var rb OPTResource
|
||||
rb, err = unpackOPTResource(msg, off, hdr.Length)
|
||||
r = &rb
|
||||
name = "OPT"
|
||||
}
|
||||
if err != nil {
|
||||
return nil, off, &nestedError{name + " record", err}
|
||||
@@ -1902,9 +1724,8 @@ func (r *CNAMEResource) realType() Type {
|
||||
return TypeCNAME
|
||||
}
|
||||
|
||||
// pack appends the wire format of the CNAMEResource to msg.
|
||||
func (r *CNAMEResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
return r.CNAME.pack(msg, compression, compressionOff)
|
||||
func (r *CNAMEResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
return r.CNAME.pack(msg, compression)
|
||||
}
|
||||
|
||||
func unpackCNAMEResource(msg []byte, off int) (CNAMEResource, error) {
|
||||
@@ -1925,11 +1746,10 @@ func (r *MXResource) realType() Type {
|
||||
return TypeMX
|
||||
}
|
||||
|
||||
// pack appends the wire format of the MXResource to msg.
|
||||
func (r *MXResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
func (r *MXResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
oldMsg := msg
|
||||
msg = packUint16(msg, r.Pref)
|
||||
msg, err := r.MX.pack(msg, compression, compressionOff)
|
||||
msg, err := r.MX.pack(msg, compression)
|
||||
if err != nil {
|
||||
return oldMsg, &nestedError{"MXResource.MX", err}
|
||||
}
|
||||
@@ -1957,9 +1777,8 @@ func (r *NSResource) realType() Type {
|
||||
return TypeNS
|
||||
}
|
||||
|
||||
// pack appends the wire format of the NSResource to msg.
|
||||
func (r *NSResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
return r.NS.pack(msg, compression, compressionOff)
|
||||
func (r *NSResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
return r.NS.pack(msg, compression)
|
||||
}
|
||||
|
||||
func unpackNSResource(msg []byte, off int) (NSResource, error) {
|
||||
@@ -1979,9 +1798,8 @@ func (r *PTRResource) realType() Type {
|
||||
return TypePTR
|
||||
}
|
||||
|
||||
// pack appends the wire format of the PTRResource to msg.
|
||||
func (r *PTRResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
return r.PTR.pack(msg, compression, compressionOff)
|
||||
func (r *PTRResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
return r.PTR.pack(msg, compression)
|
||||
}
|
||||
|
||||
func unpackPTRResource(msg []byte, off int) (PTRResource, error) {
|
||||
@@ -2011,14 +1829,13 @@ func (r *SOAResource) realType() Type {
|
||||
return TypeSOA
|
||||
}
|
||||
|
||||
// pack appends the wire format of the SOAResource to msg.
|
||||
func (r *SOAResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
func (r *SOAResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
oldMsg := msg
|
||||
msg, err := r.NS.pack(msg, compression, compressionOff)
|
||||
msg, err := r.NS.pack(msg, compression)
|
||||
if err != nil {
|
||||
return oldMsg, &nestedError{"SOAResource.NS", err}
|
||||
}
|
||||
msg, err = r.MBox.pack(msg, compression, compressionOff)
|
||||
msg, err = r.MBox.pack(msg, compression)
|
||||
if err != nil {
|
||||
return oldMsg, &nestedError{"SOAResource.MBox", err}
|
||||
}
|
||||
@@ -2064,28 +1881,19 @@ func unpackSOAResource(msg []byte, off int) (SOAResource, error) {
|
||||
|
||||
// A TXTResource is a TXT Resource record.
|
||||
type TXTResource struct {
|
||||
TXT []string
|
||||
Txt string // Not a domain name.
|
||||
}
|
||||
|
||||
func (r *TXTResource) realType() Type {
|
||||
return TypeTXT
|
||||
}
|
||||
|
||||
// pack appends the wire format of the TXTResource to msg.
|
||||
func (r *TXTResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
oldMsg := msg
|
||||
for _, s := range r.TXT {
|
||||
var err error
|
||||
msg, err = packText(msg, s)
|
||||
if err != nil {
|
||||
return oldMsg, err
|
||||
}
|
||||
}
|
||||
return msg, nil
|
||||
func (r *TXTResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
return packText(msg, r.Txt), nil
|
||||
}
|
||||
|
||||
func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error) {
|
||||
txts := make([]string, 0, 1)
|
||||
var txt string
|
||||
for n := uint16(0); n < length; {
|
||||
var t string
|
||||
var err error
|
||||
@@ -2097,9 +1905,9 @@ func unpackTXTResource(msg []byte, off int, length uint16) (TXTResource, error)
|
||||
return TXTResource{}, errCalcLen
|
||||
}
|
||||
n += uint16(len(t)) + 1
|
||||
txts = append(txts, t)
|
||||
txt += t
|
||||
}
|
||||
return TXTResource{txts}, nil
|
||||
return TXTResource{txt}, nil
|
||||
}
|
||||
|
||||
// An SRVResource is an SRV Resource record.
|
||||
@@ -2114,13 +1922,12 @@ func (r *SRVResource) realType() Type {
|
||||
return TypeSRV
|
||||
}
|
||||
|
||||
// pack appends the wire format of the SRVResource to msg.
|
||||
func (r *SRVResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
func (r *SRVResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
oldMsg := msg
|
||||
msg = packUint16(msg, r.Priority)
|
||||
msg = packUint16(msg, r.Weight)
|
||||
msg = packUint16(msg, r.Port)
|
||||
msg, err := r.Target.pack(msg, nil, compressionOff)
|
||||
msg, err := r.Target.pack(msg, nil)
|
||||
if err != nil {
|
||||
return oldMsg, &nestedError{"SRVResource.Target", err}
|
||||
}
|
||||
@@ -2141,7 +1948,7 @@ func unpackSRVResource(msg []byte, off int) (SRVResource, error) {
|
||||
return SRVResource{}, &nestedError{"Port", err}
|
||||
}
|
||||
var target Name
|
||||
if _, err := target.unpackCompressed(msg, off, false /* allowCompression */); err != nil {
|
||||
if _, err := target.unpack(msg, off); err != nil {
|
||||
return SRVResource{}, &nestedError{"Target", err}
|
||||
}
|
||||
return SRVResource{priority, weight, port, target}, nil
|
||||
@@ -2156,8 +1963,7 @@ func (r *AResource) realType() Type {
|
||||
return TypeA
|
||||
}
|
||||
|
||||
// pack appends the wire format of the AResource to msg.
|
||||
func (r *AResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
func (r *AResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
return packBytes(msg, r.A[:]), nil
|
||||
}
|
||||
|
||||
@@ -2178,8 +1984,7 @@ func (r *AAAAResource) realType() Type {
|
||||
return TypeAAAA
|
||||
}
|
||||
|
||||
// pack appends the wire format of the AAAAResource to msg.
|
||||
func (r *AAAAResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
func (r *AAAAResource) pack(msg []byte, compression map[string]int) ([]byte, error) {
|
||||
return packBytes(msg, r.AAAA[:]), nil
|
||||
}
|
||||
|
||||
@@ -2190,58 +1995,3 @@ func unpackAAAAResource(msg []byte, off int) (AAAAResource, error) {
|
||||
}
|
||||
return AAAAResource{aaaa}, nil
|
||||
}
|
||||
|
||||
// An OPTResource is an OPT pseudo Resource record.
|
||||
//
|
||||
// The pseudo resource record is part of the extension mechanisms for DNS
|
||||
// as defined in RFC 6891.
|
||||
type OPTResource struct {
|
||||
Options []Option
|
||||
}
|
||||
|
||||
// An Option represents a DNS message option within OPTResource.
|
||||
//
|
||||
// The message option is part of the extension mechanisms for DNS as
|
||||
// defined in RFC 6891.
|
||||
type Option struct {
|
||||
Code uint16 // option code
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (r *OPTResource) realType() Type {
|
||||
return TypeOPT
|
||||
}
|
||||
|
||||
func (r *OPTResource) pack(msg []byte, compression map[string]int, compressionOff int) ([]byte, error) {
|
||||
for _, opt := range r.Options {
|
||||
msg = packUint16(msg, opt.Code)
|
||||
l := uint16(len(opt.Data))
|
||||
msg = packUint16(msg, l)
|
||||
msg = packBytes(msg, opt.Data)
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
func unpackOPTResource(msg []byte, off int, length uint16) (OPTResource, error) {
|
||||
var opts []Option
|
||||
for oldOff := off; off < oldOff+int(length); {
|
||||
var err error
|
||||
var o Option
|
||||
o.Code, off, err = unpackUint16(msg, off)
|
||||
if err != nil {
|
||||
return OPTResource{}, &nestedError{"Code", err}
|
||||
}
|
||||
var l uint16
|
||||
l, off, err = unpackUint16(msg, off)
|
||||
if err != nil {
|
||||
return OPTResource{}, &nestedError{"Data", err}
|
||||
}
|
||||
o.Data = make([]byte, l)
|
||||
if copy(o.Data, msg[off:]) != int(l) {
|
||||
return OPTResource{}, &nestedError{"Data", errCalcLen}
|
||||
}
|
||||
off += int(l)
|
||||
opts = append(opts, o)
|
||||
}
|
||||
return OPTResource{opts}, nil
|
||||
}
|
||||
|
||||
784
vendor/golang.org/x/net/dns/dnsmessage/message_test.go
generated
vendored
784
vendor/golang.org/x/net/dns/dnsmessage/message_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
138
vendor/golang.org/x/net/html/atom/gen.go
generated
vendored
138
vendor/golang.org/x/net/html/atom/gen.go
generated
vendored
@@ -4,17 +4,17 @@
|
||||
|
||||
// +build ignore
|
||||
|
||||
//go:generate go run gen.go
|
||||
//go:generate go run gen.go -test
|
||||
|
||||
package main
|
||||
|
||||
// This program generates table.go and table_test.go.
|
||||
// Invoke as
|
||||
//
|
||||
// go run gen.go |gofmt >table.go
|
||||
// go run gen.go -test |gofmt >table_test.go
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
@@ -42,18 +42,6 @@ func identifier(s string) string {
|
||||
|
||||
var test = flag.Bool("test", false, "generate table_test.go")
|
||||
|
||||
func genFile(name string, buf *bytes.Buffer) {
|
||||
b, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := ioutil.WriteFile(name, b, 0644); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
@@ -64,31 +52,32 @@ func main() {
|
||||
all = append(all, extra...)
|
||||
sort.Strings(all)
|
||||
|
||||
if *test {
|
||||
fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n")
|
||||
fmt.Printf("package atom\n\n")
|
||||
fmt.Printf("var testAtomList = []string{\n")
|
||||
for _, s := range all {
|
||||
fmt.Printf("\t%q,\n", s)
|
||||
}
|
||||
fmt.Printf("}\n")
|
||||
return
|
||||
}
|
||||
|
||||
// uniq - lists have dups
|
||||
// compute max len too
|
||||
maxLen := 0
|
||||
w := 0
|
||||
for _, s := range all {
|
||||
if w == 0 || all[w-1] != s {
|
||||
if maxLen < len(s) {
|
||||
maxLen = len(s)
|
||||
}
|
||||
all[w] = s
|
||||
w++
|
||||
}
|
||||
}
|
||||
all = all[:w]
|
||||
|
||||
if *test {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintln(&buf, "// Code generated by go generate gen.go; DO NOT EDIT.\n")
|
||||
fmt.Fprintln(&buf, "//go:generate go run gen.go -test\n")
|
||||
fmt.Fprintln(&buf, "package atom\n")
|
||||
fmt.Fprintln(&buf, "var testAtomList = []string{")
|
||||
for _, s := range all {
|
||||
fmt.Fprintf(&buf, "\t%q,\n", s)
|
||||
}
|
||||
fmt.Fprintln(&buf, "}")
|
||||
|
||||
genFile("table_test.go", &buf)
|
||||
return
|
||||
}
|
||||
|
||||
// Find hash that minimizes table size.
|
||||
var best *table
|
||||
for i := 0; i < 1000000; i++ {
|
||||
@@ -174,46 +163,36 @@ func main() {
|
||||
atom[s] = uint32(off<<8 | len(s))
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
// Generate the Go code.
|
||||
fmt.Fprintln(&buf, "// Code generated by go generate gen.go; DO NOT EDIT.\n")
|
||||
fmt.Fprintln(&buf, "//go:generate go run gen.go\n")
|
||||
fmt.Fprintln(&buf, "package atom\n\nconst (")
|
||||
|
||||
// compute max len
|
||||
maxLen := 0
|
||||
fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n")
|
||||
fmt.Printf("package atom\n\nconst (\n")
|
||||
for _, s := range all {
|
||||
if maxLen < len(s) {
|
||||
maxLen = len(s)
|
||||
}
|
||||
fmt.Fprintf(&buf, "\t%s Atom = %#x\n", identifier(s), atom[s])
|
||||
fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s])
|
||||
}
|
||||
fmt.Fprintln(&buf, ")\n")
|
||||
fmt.Printf(")\n\n")
|
||||
|
||||
fmt.Fprintf(&buf, "const hash0 = %#x\n\n", best.h0)
|
||||
fmt.Fprintf(&buf, "const maxAtomLen = %d\n\n", maxLen)
|
||||
fmt.Printf("const hash0 = %#x\n\n", best.h0)
|
||||
fmt.Printf("const maxAtomLen = %d\n\n", maxLen)
|
||||
|
||||
fmt.Fprintf(&buf, "var table = [1<<%d]Atom{\n", best.k)
|
||||
fmt.Printf("var table = [1<<%d]Atom{\n", best.k)
|
||||
for i, s := range best.tab {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(&buf, "\t%#x: %#x, // %s\n", i, atom[s], s)
|
||||
fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s)
|
||||
}
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
fmt.Printf("}\n")
|
||||
datasize := (1 << best.k) * 4
|
||||
|
||||
fmt.Fprintln(&buf, "const atomText =")
|
||||
fmt.Printf("const atomText =\n")
|
||||
textsize := len(text)
|
||||
for len(text) > 60 {
|
||||
fmt.Fprintf(&buf, "\t%q +\n", text[:60])
|
||||
fmt.Printf("\t%q +\n", text[:60])
|
||||
text = text[60:]
|
||||
}
|
||||
fmt.Fprintf(&buf, "\t%q\n\n", text)
|
||||
fmt.Printf("\t%q\n\n", text)
|
||||
|
||||
genFile("table.go", &buf)
|
||||
|
||||
fmt.Fprintf(os.Stdout, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize)
|
||||
fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize)
|
||||
}
|
||||
|
||||
type byLen []string
|
||||
@@ -306,10 +285,8 @@ func (t *table) push(i uint32, depth int) bool {
|
||||
|
||||
// The lists of element names and attribute keys were taken from
|
||||
// https://html.spec.whatwg.org/multipage/indices.html#index
|
||||
// as of the "HTML Living Standard - Last Updated 16 April 2018" version.
|
||||
// as of the "HTML Living Standard - Last Updated 21 February 2015" version.
|
||||
|
||||
// "command", "keygen" and "menuitem" have been removed from the spec,
|
||||
// but are kept here for backwards compatibility.
|
||||
var elements = []string{
|
||||
"a",
|
||||
"abbr",
|
||||
@@ -372,7 +349,6 @@ var elements = []string{
|
||||
"legend",
|
||||
"li",
|
||||
"link",
|
||||
"main",
|
||||
"map",
|
||||
"mark",
|
||||
"menu",
|
||||
@@ -388,7 +364,6 @@ var elements = []string{
|
||||
"output",
|
||||
"p",
|
||||
"param",
|
||||
"picture",
|
||||
"pre",
|
||||
"progress",
|
||||
"q",
|
||||
@@ -400,7 +375,6 @@ var elements = []string{
|
||||
"script",
|
||||
"section",
|
||||
"select",
|
||||
"slot",
|
||||
"small",
|
||||
"source",
|
||||
"span",
|
||||
@@ -429,21 +403,14 @@ var elements = []string{
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/indices.html#attributes-3
|
||||
//
|
||||
// "challenge", "command", "contextmenu", "dropzone", "icon", "keytype", "mediagroup",
|
||||
// "radiogroup", "spellcheck", "scoped", "seamless", "sortable" and "sorted" have been removed from the spec,
|
||||
// but are kept here for backwards compatibility.
|
||||
|
||||
var attributes = []string{
|
||||
"abbr",
|
||||
"accept",
|
||||
"accept-charset",
|
||||
"accesskey",
|
||||
"action",
|
||||
"allowfullscreen",
|
||||
"allowpaymentrequest",
|
||||
"allowusermedia",
|
||||
"alt",
|
||||
"as",
|
||||
"async",
|
||||
"autocomplete",
|
||||
"autofocus",
|
||||
@@ -453,7 +420,6 @@ var attributes = []string{
|
||||
"checked",
|
||||
"cite",
|
||||
"class",
|
||||
"color",
|
||||
"cols",
|
||||
"colspan",
|
||||
"command",
|
||||
@@ -491,8 +457,6 @@ var attributes = []string{
|
||||
"icon",
|
||||
"id",
|
||||
"inputmode",
|
||||
"integrity",
|
||||
"is",
|
||||
"ismap",
|
||||
"itemid",
|
||||
"itemprop",
|
||||
@@ -517,20 +481,16 @@ var attributes = []string{
|
||||
"multiple",
|
||||
"muted",
|
||||
"name",
|
||||
"nomodule",
|
||||
"nonce",
|
||||
"novalidate",
|
||||
"open",
|
||||
"optimum",
|
||||
"pattern",
|
||||
"ping",
|
||||
"placeholder",
|
||||
"playsinline",
|
||||
"poster",
|
||||
"preload",
|
||||
"radiogroup",
|
||||
"readonly",
|
||||
"referrerpolicy",
|
||||
"rel",
|
||||
"required",
|
||||
"reversed",
|
||||
@@ -547,13 +507,10 @@ var attributes = []string{
|
||||
"sizes",
|
||||
"sortable",
|
||||
"sorted",
|
||||
"slot",
|
||||
"span",
|
||||
"spellcheck",
|
||||
"src",
|
||||
"srcdoc",
|
||||
"srclang",
|
||||
"srcset",
|
||||
"start",
|
||||
"step",
|
||||
"style",
|
||||
@@ -563,22 +520,16 @@ var attributes = []string{
|
||||
"translate",
|
||||
"type",
|
||||
"typemustmatch",
|
||||
"updateviacache",
|
||||
"usemap",
|
||||
"value",
|
||||
"width",
|
||||
"workertype",
|
||||
"wrap",
|
||||
}
|
||||
|
||||
// "onautocomplete", "onautocompleteerror", "onmousewheel",
|
||||
// "onshow" and "onsort" have been removed from the spec,
|
||||
// but are kept here for backwards compatibility.
|
||||
var eventHandlers = []string{
|
||||
"onabort",
|
||||
"onautocomplete",
|
||||
"onautocompleteerror",
|
||||
"onauxclick",
|
||||
"onafterprint",
|
||||
"onbeforeprint",
|
||||
"onbeforeunload",
|
||||
@@ -590,14 +541,11 @@ var eventHandlers = []string{
|
||||
"onclick",
|
||||
"onclose",
|
||||
"oncontextmenu",
|
||||
"oncopy",
|
||||
"oncuechange",
|
||||
"oncut",
|
||||
"ondblclick",
|
||||
"ondrag",
|
||||
"ondragend",
|
||||
"ondragenter",
|
||||
"ondragexit",
|
||||
"ondragleave",
|
||||
"ondragover",
|
||||
"ondragstart",
|
||||
@@ -617,24 +565,18 @@ var eventHandlers = []string{
|
||||
"onload",
|
||||
"onloadeddata",
|
||||
"onloadedmetadata",
|
||||
"onloadend",
|
||||
"onloadstart",
|
||||
"onmessage",
|
||||
"onmessageerror",
|
||||
"onmousedown",
|
||||
"onmouseenter",
|
||||
"onmouseleave",
|
||||
"onmousemove",
|
||||
"onmouseout",
|
||||
"onmouseover",
|
||||
"onmouseup",
|
||||
"onmousewheel",
|
||||
"onwheel",
|
||||
"onoffline",
|
||||
"ononline",
|
||||
"onpagehide",
|
||||
"onpageshow",
|
||||
"onpaste",
|
||||
"onpause",
|
||||
"onplay",
|
||||
"onplaying",
|
||||
@@ -643,9 +585,7 @@ var eventHandlers = []string{
|
||||
"onratechange",
|
||||
"onreset",
|
||||
"onresize",
|
||||
"onrejectionhandled",
|
||||
"onscroll",
|
||||
"onsecuritypolicyviolation",
|
||||
"onseeked",
|
||||
"onseeking",
|
||||
"onselect",
|
||||
@@ -657,7 +597,6 @@ var eventHandlers = []string{
|
||||
"onsuspend",
|
||||
"ontimeupdate",
|
||||
"ontoggle",
|
||||
"onunhandledrejection",
|
||||
"onunload",
|
||||
"onvolumechange",
|
||||
"onwaiting",
|
||||
@@ -665,7 +604,6 @@ var eventHandlers = []string{
|
||||
|
||||
// extra are ad-hoc values not covered by any of the lists above.
|
||||
var extra = []string{
|
||||
"acronym",
|
||||
"align",
|
||||
"annotation",
|
||||
"annotation-xml",
|
||||
@@ -701,8 +639,6 @@ var extra = []string{
|
||||
"plaintext",
|
||||
"prompt",
|
||||
"public",
|
||||
"rb",
|
||||
"rtc",
|
||||
"spacer",
|
||||
"strike",
|
||||
"svg",
|
||||
|
||||
1474
vendor/golang.org/x/net/html/atom/table.go
generated
vendored
1474
vendor/golang.org/x/net/html/atom/table.go
generated
vendored
File diff suppressed because it is too large
Load Diff
45
vendor/golang.org/x/net/html/atom/table_test.go
generated
vendored
45
vendor/golang.org/x/net/html/atom/table_test.go
generated
vendored
@@ -1,29 +1,23 @@
|
||||
// Code generated by go generate gen.go; DO NOT EDIT.
|
||||
|
||||
//go:generate go run gen.go -test
|
||||
// generated by go run gen.go -test; DO NOT EDIT
|
||||
|
||||
package atom
|
||||
|
||||
var testAtomList = []string{
|
||||
"a",
|
||||
"abbr",
|
||||
"abbr",
|
||||
"accept",
|
||||
"accept-charset",
|
||||
"accesskey",
|
||||
"acronym",
|
||||
"action",
|
||||
"address",
|
||||
"align",
|
||||
"allowfullscreen",
|
||||
"allowpaymentrequest",
|
||||
"allowusermedia",
|
||||
"alt",
|
||||
"annotation",
|
||||
"annotation-xml",
|
||||
"applet",
|
||||
"area",
|
||||
"article",
|
||||
"as",
|
||||
"aside",
|
||||
"async",
|
||||
"audio",
|
||||
@@ -49,6 +43,7 @@ var testAtomList = []string{
|
||||
"charset",
|
||||
"checked",
|
||||
"cite",
|
||||
"cite",
|
||||
"class",
|
||||
"code",
|
||||
"col",
|
||||
@@ -57,6 +52,7 @@ var testAtomList = []string{
|
||||
"cols",
|
||||
"colspan",
|
||||
"command",
|
||||
"command",
|
||||
"content",
|
||||
"contenteditable",
|
||||
"contextmenu",
|
||||
@@ -64,6 +60,7 @@ var testAtomList = []string{
|
||||
"coords",
|
||||
"crossorigin",
|
||||
"data",
|
||||
"data",
|
||||
"datalist",
|
||||
"datetime",
|
||||
"dd",
|
||||
@@ -96,6 +93,7 @@ var testAtomList = []string{
|
||||
"foreignObject",
|
||||
"foreignobject",
|
||||
"form",
|
||||
"form",
|
||||
"formaction",
|
||||
"formenctype",
|
||||
"formmethod",
|
||||
@@ -130,8 +128,6 @@ var testAtomList = []string{
|
||||
"input",
|
||||
"inputmode",
|
||||
"ins",
|
||||
"integrity",
|
||||
"is",
|
||||
"isindex",
|
||||
"ismap",
|
||||
"itemid",
|
||||
@@ -144,6 +140,7 @@ var testAtomList = []string{
|
||||
"keytype",
|
||||
"kind",
|
||||
"label",
|
||||
"label",
|
||||
"lang",
|
||||
"legend",
|
||||
"li",
|
||||
@@ -152,7 +149,6 @@ var testAtomList = []string{
|
||||
"listing",
|
||||
"loop",
|
||||
"low",
|
||||
"main",
|
||||
"malignmark",
|
||||
"manifest",
|
||||
"map",
|
||||
@@ -183,8 +179,6 @@ var testAtomList = []string{
|
||||
"nobr",
|
||||
"noembed",
|
||||
"noframes",
|
||||
"nomodule",
|
||||
"nonce",
|
||||
"noscript",
|
||||
"novalidate",
|
||||
"object",
|
||||
@@ -193,7 +187,6 @@ var testAtomList = []string{
|
||||
"onafterprint",
|
||||
"onautocomplete",
|
||||
"onautocompleteerror",
|
||||
"onauxclick",
|
||||
"onbeforeprint",
|
||||
"onbeforeunload",
|
||||
"onblur",
|
||||
@@ -204,14 +197,11 @@ var testAtomList = []string{
|
||||
"onclick",
|
||||
"onclose",
|
||||
"oncontextmenu",
|
||||
"oncopy",
|
||||
"oncuechange",
|
||||
"oncut",
|
||||
"ondblclick",
|
||||
"ondrag",
|
||||
"ondragend",
|
||||
"ondragenter",
|
||||
"ondragexit",
|
||||
"ondragleave",
|
||||
"ondragover",
|
||||
"ondragstart",
|
||||
@@ -231,13 +221,9 @@ var testAtomList = []string{
|
||||
"onload",
|
||||
"onloadeddata",
|
||||
"onloadedmetadata",
|
||||
"onloadend",
|
||||
"onloadstart",
|
||||
"onmessage",
|
||||
"onmessageerror",
|
||||
"onmousedown",
|
||||
"onmouseenter",
|
||||
"onmouseleave",
|
||||
"onmousemove",
|
||||
"onmouseout",
|
||||
"onmouseover",
|
||||
@@ -247,18 +233,15 @@ var testAtomList = []string{
|
||||
"ononline",
|
||||
"onpagehide",
|
||||
"onpageshow",
|
||||
"onpaste",
|
||||
"onpause",
|
||||
"onplay",
|
||||
"onplaying",
|
||||
"onpopstate",
|
||||
"onprogress",
|
||||
"onratechange",
|
||||
"onrejectionhandled",
|
||||
"onreset",
|
||||
"onresize",
|
||||
"onscroll",
|
||||
"onsecuritypolicyviolation",
|
||||
"onseeked",
|
||||
"onseeking",
|
||||
"onselect",
|
||||
@@ -270,11 +253,9 @@ var testAtomList = []string{
|
||||
"onsuspend",
|
||||
"ontimeupdate",
|
||||
"ontoggle",
|
||||
"onunhandledrejection",
|
||||
"onunload",
|
||||
"onvolumechange",
|
||||
"onwaiting",
|
||||
"onwheel",
|
||||
"open",
|
||||
"optgroup",
|
||||
"optimum",
|
||||
@@ -283,11 +264,9 @@ var testAtomList = []string{
|
||||
"p",
|
||||
"param",
|
||||
"pattern",
|
||||
"picture",
|
||||
"ping",
|
||||
"placeholder",
|
||||
"plaintext",
|
||||
"playsinline",
|
||||
"poster",
|
||||
"pre",
|
||||
"preload",
|
||||
@@ -296,9 +275,7 @@ var testAtomList = []string{
|
||||
"public",
|
||||
"q",
|
||||
"radiogroup",
|
||||
"rb",
|
||||
"readonly",
|
||||
"referrerpolicy",
|
||||
"rel",
|
||||
"required",
|
||||
"reversed",
|
||||
@@ -306,7 +283,6 @@ var testAtomList = []string{
|
||||
"rowspan",
|
||||
"rp",
|
||||
"rt",
|
||||
"rtc",
|
||||
"ruby",
|
||||
"s",
|
||||
"samp",
|
||||
@@ -321,23 +297,23 @@ var testAtomList = []string{
|
||||
"shape",
|
||||
"size",
|
||||
"sizes",
|
||||
"slot",
|
||||
"small",
|
||||
"sortable",
|
||||
"sorted",
|
||||
"source",
|
||||
"spacer",
|
||||
"span",
|
||||
"span",
|
||||
"spellcheck",
|
||||
"src",
|
||||
"srcdoc",
|
||||
"srclang",
|
||||
"srcset",
|
||||
"start",
|
||||
"step",
|
||||
"strike",
|
||||
"strong",
|
||||
"style",
|
||||
"style",
|
||||
"sub",
|
||||
"summary",
|
||||
"sup",
|
||||
@@ -355,6 +331,7 @@ var testAtomList = []string{
|
||||
"thead",
|
||||
"time",
|
||||
"title",
|
||||
"title",
|
||||
"tr",
|
||||
"track",
|
||||
"translate",
|
||||
@@ -363,14 +340,12 @@ var testAtomList = []string{
|
||||
"typemustmatch",
|
||||
"u",
|
||||
"ul",
|
||||
"updateviacache",
|
||||
"usemap",
|
||||
"value",
|
||||
"var",
|
||||
"video",
|
||||
"wbr",
|
||||
"width",
|
||||
"workertype",
|
||||
"wrap",
|
||||
"xmp",
|
||||
}
|
||||
|
||||
6
vendor/golang.org/x/net/html/const.go
generated
vendored
6
vendor/golang.org/x/net/html/const.go
generated
vendored
@@ -4,7 +4,7 @@
|
||||
|
||||
package html
|
||||
|
||||
// Section 12.2.4.2 of the HTML5 specification says "The following elements
|
||||
// Section 12.2.3.2 of the HTML5 specification says "The following elements
|
||||
// have varying levels of special parsing rules".
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
|
||||
var isSpecialElementMap = map[string]bool{
|
||||
@@ -52,12 +52,10 @@ var isSpecialElementMap = map[string]bool{
|
||||
"iframe": true,
|
||||
"img": true,
|
||||
"input": true,
|
||||
"isindex": true, // The 'isindex' element has been removed, but keep it for backwards compatibility.
|
||||
"keygen": true,
|
||||
"isindex": true,
|
||||
"li": true,
|
||||
"link": true,
|
||||
"listing": true,
|
||||
"main": true,
|
||||
"marquee": true,
|
||||
"menu": true,
|
||||
"meta": true,
|
||||
|
||||
8
vendor/golang.org/x/net/html/doc.go
generated
vendored
8
vendor/golang.org/x/net/html/doc.go
generated
vendored
@@ -49,18 +49,18 @@ call to Next. For example, to extract an HTML page's anchor text:
|
||||
for {
|
||||
tt := z.Next()
|
||||
switch tt {
|
||||
case html.ErrorToken:
|
||||
case ErrorToken:
|
||||
return z.Err()
|
||||
case html.TextToken:
|
||||
case TextToken:
|
||||
if depth > 0 {
|
||||
// emitBytes should copy the []byte it receives,
|
||||
// if it doesn't process it immediately.
|
||||
emitBytes(z.Text())
|
||||
}
|
||||
case html.StartTagToken, html.EndTagToken:
|
||||
case StartTagToken, EndTagToken:
|
||||
tn, _ := z.TagName()
|
||||
if len(tn) == 1 && tn[0] == 'a' {
|
||||
if tt == html.StartTagToken {
|
||||
if tt == StartTagToken {
|
||||
depth++
|
||||
} else {
|
||||
depth--
|
||||
|
||||
4154
vendor/golang.org/x/net/html/entity.go
generated
vendored
4154
vendor/golang.org/x/net/html/entity.go
generated
vendored
File diff suppressed because it is too large
Load Diff
6
vendor/golang.org/x/net/html/foreign.go
generated
vendored
6
vendor/golang.org/x/net/html/foreign.go
generated
vendored
@@ -67,7 +67,7 @@ func mathMLTextIntegrationPoint(n *Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.5.
|
||||
// Section 12.2.5.5.
|
||||
var breakout = map[string]bool{
|
||||
"b": true,
|
||||
"big": true,
|
||||
@@ -115,7 +115,7 @@ var breakout = map[string]bool{
|
||||
"var": true,
|
||||
}
|
||||
|
||||
// Section 12.2.6.5.
|
||||
// Section 12.2.5.5.
|
||||
var svgTagNameAdjustments = map[string]string{
|
||||
"altglyph": "altGlyph",
|
||||
"altglyphdef": "altGlyphDef",
|
||||
@@ -155,7 +155,7 @@ var svgTagNameAdjustments = map[string]string{
|
||||
"textpath": "textPath",
|
||||
}
|
||||
|
||||
// Section 12.2.6.1
|
||||
// Section 12.2.5.1
|
||||
var mathMLAttributeAdjustments = map[string]string{
|
||||
"definitionurl": "definitionURL",
|
||||
}
|
||||
|
||||
33
vendor/golang.org/x/net/html/node.go
generated
vendored
33
vendor/golang.org/x/net/html/node.go
generated
vendored
@@ -21,10 +21,9 @@ const (
|
||||
scopeMarkerNode
|
||||
)
|
||||
|
||||
// Section 12.2.4.3 says "The markers are inserted when entering applet,
|
||||
// object, marquee, template, td, th, and caption elements, and are used
|
||||
// to prevent formatting from "leaking" into applet, object, marquee,
|
||||
// template, td, th, and caption elements".
|
||||
// Section 12.2.3.3 says "scope markers are inserted when entering applet
|
||||
// elements, buttons, object elements, marquees, table cells, and table
|
||||
// captions, and are used to prevent formatting from 'leaking'".
|
||||
var scopeMarker = Node{Type: scopeMarkerNode}
|
||||
|
||||
// A Node consists of a NodeType and some Data (tag name for element nodes,
|
||||
@@ -174,16 +173,6 @@ func (s *nodeStack) index(n *Node) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// contains returns whether a is within s.
|
||||
func (s *nodeStack) contains(a atom.Atom) bool {
|
||||
for _, n := range *s {
|
||||
if n.DataAtom == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// insert inserts a node at the given index.
|
||||
func (s *nodeStack) insert(i int, n *Node) {
|
||||
(*s) = append(*s, nil)
|
||||
@@ -202,19 +191,3 @@ func (s *nodeStack) remove(n *Node) {
|
||||
(*s)[j] = nil
|
||||
*s = (*s)[:j]
|
||||
}
|
||||
|
||||
type insertionModeStack []insertionMode
|
||||
|
||||
func (s *insertionModeStack) pop() (im insertionMode) {
|
||||
i := len(*s)
|
||||
im = (*s)[i-1]
|
||||
*s = (*s)[:i-1]
|
||||
return im
|
||||
}
|
||||
|
||||
func (s *insertionModeStack) top() insertionMode {
|
||||
if i := len(*s); i > 0 {
|
||||
return (*s)[i-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
361
vendor/golang.org/x/net/html/parse.go
generated
vendored
361
vendor/golang.org/x/net/html/parse.go
generated
vendored
@@ -25,22 +25,20 @@ type parser struct {
|
||||
hasSelfClosingToken bool
|
||||
// doc is the document root element.
|
||||
doc *Node
|
||||
// The stack of open elements (section 12.2.4.2) and active formatting
|
||||
// elements (section 12.2.4.3).
|
||||
// The stack of open elements (section 12.2.3.2) and active formatting
|
||||
// elements (section 12.2.3.3).
|
||||
oe, afe nodeStack
|
||||
// Element pointers (section 12.2.4.4).
|
||||
// Element pointers (section 12.2.3.4).
|
||||
head, form *Node
|
||||
// Other parsing state flags (section 12.2.4.5).
|
||||
// Other parsing state flags (section 12.2.3.5).
|
||||
scripting, framesetOK bool
|
||||
// The stack of template insertion modes
|
||||
templateStack insertionModeStack
|
||||
// im is the current insertion mode.
|
||||
im insertionMode
|
||||
// originalIM is the insertion mode to go back to after completing a text
|
||||
// or inTableText insertion mode.
|
||||
originalIM insertionMode
|
||||
// fosterParenting is whether new elements should be inserted according to
|
||||
// the foster parenting rules (section 12.2.6.1).
|
||||
// the foster parenting rules (section 12.2.5.3).
|
||||
fosterParenting bool
|
||||
// quirks is whether the parser is operating in "quirks mode."
|
||||
quirks bool
|
||||
@@ -58,7 +56,7 @@ func (p *parser) top() *Node {
|
||||
return p.doc
|
||||
}
|
||||
|
||||
// Stop tags for use in popUntil. These come from section 12.2.4.2.
|
||||
// Stop tags for use in popUntil. These come from section 12.2.3.2.
|
||||
var (
|
||||
defaultScopeStopTags = map[string][]a.Atom{
|
||||
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
|
||||
@@ -81,7 +79,7 @@ const (
|
||||
|
||||
// popUntil pops the stack of open elements at the highest element whose tag
|
||||
// is in matchTags, provided there is no higher element in the scope's stop
|
||||
// tags (as defined in section 12.2.4.2). It returns whether or not there was
|
||||
// tags (as defined in section 12.2.3.2). It returns whether or not there was
|
||||
// such an element. If there was not, popUntil leaves the stack unchanged.
|
||||
//
|
||||
// For example, the set of stop tags for table scope is: "html", "table". If
|
||||
@@ -128,7 +126,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
|
||||
return -1
|
||||
}
|
||||
case tableScope:
|
||||
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
|
||||
if tagAtom == a.Html || tagAtom == a.Table {
|
||||
return -1
|
||||
}
|
||||
case selectScope:
|
||||
@@ -164,17 +162,17 @@ func (p *parser) clearStackToContext(s scope) {
|
||||
tagAtom := p.oe[i].DataAtom
|
||||
switch s {
|
||||
case tableScope:
|
||||
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
|
||||
if tagAtom == a.Html || tagAtom == a.Table {
|
||||
p.oe = p.oe[:i+1]
|
||||
return
|
||||
}
|
||||
case tableRowScope:
|
||||
if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template {
|
||||
if tagAtom == a.Html || tagAtom == a.Tr {
|
||||
p.oe = p.oe[:i+1]
|
||||
return
|
||||
}
|
||||
case tableBodyScope:
|
||||
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template {
|
||||
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead {
|
||||
p.oe = p.oe[:i+1]
|
||||
return
|
||||
}
|
||||
@@ -185,7 +183,7 @@ func (p *parser) clearStackToContext(s scope) {
|
||||
}
|
||||
|
||||
// generateImpliedEndTags pops nodes off the stack of open elements as long as
|
||||
// the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc.
|
||||
// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt.
|
||||
// If exceptions are specified, nodes with that name will not be popped off.
|
||||
func (p *parser) generateImpliedEndTags(exceptions ...string) {
|
||||
var i int
|
||||
@@ -194,7 +192,7 @@ loop:
|
||||
n := p.oe[i]
|
||||
if n.Type == ElementNode {
|
||||
switch n.DataAtom {
|
||||
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc:
|
||||
case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt:
|
||||
for _, except := range exceptions {
|
||||
if n.Data == except {
|
||||
break loop
|
||||
@@ -209,27 +207,6 @@ loop:
|
||||
p.oe = p.oe[:i+1]
|
||||
}
|
||||
|
||||
// generateAllImpliedEndTags pops nodes off the stack of open elements as long as
|
||||
// the top node has a tag name of caption, colgroup, dd, div, dt, li, optgroup, option, p, rb,
|
||||
// rp, rt, rtc, span, tbody, td, tfoot, th, thead or tr.
|
||||
func (p *parser) generateAllImpliedEndTags() {
|
||||
var i int
|
||||
for i = len(p.oe) - 1; i >= 0; i-- {
|
||||
n := p.oe[i]
|
||||
if n.Type == ElementNode {
|
||||
switch n.DataAtom {
|
||||
// TODO: remove this divergence from the HTML5 spec
|
||||
case a.Caption, a.Colgroup, a.Dd, a.Div, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb,
|
||||
a.Rp, a.Rt, a.Rtc, a.Span, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
p.oe = p.oe[:i+1]
|
||||
}
|
||||
|
||||
// addChild adds a child node n to the top element, and pushes n onto the stack
|
||||
// of open elements if it is an element node.
|
||||
func (p *parser) addChild(n *Node) {
|
||||
@@ -257,9 +234,9 @@ func (p *parser) shouldFosterParent() bool {
|
||||
}
|
||||
|
||||
// fosterParent adds a child node according to the foster parenting rules.
|
||||
// Section 12.2.6.1, "foster parenting".
|
||||
// Section 12.2.5.3, "foster parenting".
|
||||
func (p *parser) fosterParent(n *Node) {
|
||||
var table, parent, prev, template *Node
|
||||
var table, parent, prev *Node
|
||||
var i int
|
||||
for i = len(p.oe) - 1; i >= 0; i-- {
|
||||
if p.oe[i].DataAtom == a.Table {
|
||||
@@ -268,19 +245,6 @@ func (p *parser) fosterParent(n *Node) {
|
||||
}
|
||||
}
|
||||
|
||||
var j int
|
||||
for j = len(p.oe) - 1; j >= 0; j-- {
|
||||
if p.oe[j].DataAtom == a.Template {
|
||||
template = p.oe[j]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if template != nil && (table == nil || j < i) {
|
||||
template.AppendChild(n)
|
||||
return
|
||||
}
|
||||
|
||||
if table == nil {
|
||||
// The foster parent is the html element.
|
||||
parent = p.oe[0]
|
||||
@@ -340,7 +304,7 @@ func (p *parser) addElement() {
|
||||
})
|
||||
}
|
||||
|
||||
// Section 12.2.4.3.
|
||||
// Section 12.2.3.3.
|
||||
func (p *parser) addFormattingElement() {
|
||||
tagAtom, attr := p.tok.DataAtom, p.tok.Attr
|
||||
p.addElement()
|
||||
@@ -387,7 +351,7 @@ findIdenticalElements:
|
||||
p.afe = append(p.afe, p.top())
|
||||
}
|
||||
|
||||
// Section 12.2.4.3.
|
||||
// Section 12.2.3.3.
|
||||
func (p *parser) clearActiveFormattingElements() {
|
||||
for {
|
||||
n := p.afe.pop()
|
||||
@@ -397,7 +361,7 @@ func (p *parser) clearActiveFormattingElements() {
|
||||
}
|
||||
}
|
||||
|
||||
// Section 12.2.4.3.
|
||||
// Section 12.2.3.3.
|
||||
func (p *parser) reconstructActiveFormattingElements() {
|
||||
n := p.afe.top()
|
||||
if n == nil {
|
||||
@@ -426,12 +390,12 @@ func (p *parser) reconstructActiveFormattingElements() {
|
||||
}
|
||||
}
|
||||
|
||||
// Section 12.2.5.
|
||||
// Section 12.2.4.
|
||||
func (p *parser) acknowledgeSelfClosingTag() {
|
||||
p.hasSelfClosingToken = false
|
||||
}
|
||||
|
||||
// An insertion mode (section 12.2.4.1) is the state transition function from
|
||||
// An insertion mode (section 12.2.3.1) is the state transition function from
|
||||
// a particular state in the HTML5 parser's state machine. It updates the
|
||||
// parser's fields depending on parser.tok (where ErrorToken means EOF).
|
||||
// It returns whether the token was consumed.
|
||||
@@ -439,7 +403,7 @@ type insertionMode func(*parser) bool
|
||||
|
||||
// setOriginalIM sets the insertion mode to return to after completing a text or
|
||||
// inTableText insertion mode.
|
||||
// Section 12.2.4.1, "using the rules for".
|
||||
// Section 12.2.3.1, "using the rules for".
|
||||
func (p *parser) setOriginalIM() {
|
||||
if p.originalIM != nil {
|
||||
panic("html: bad parser state: originalIM was set twice")
|
||||
@@ -447,38 +411,18 @@ func (p *parser) setOriginalIM() {
|
||||
p.originalIM = p.im
|
||||
}
|
||||
|
||||
// Section 12.2.4.1, "reset the insertion mode".
|
||||
// Section 12.2.3.1, "reset the insertion mode".
|
||||
func (p *parser) resetInsertionMode() {
|
||||
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||
n := p.oe[i]
|
||||
last := i == 0
|
||||
if last && p.context != nil {
|
||||
if i == 0 && p.context != nil {
|
||||
n = p.context
|
||||
}
|
||||
|
||||
switch n.DataAtom {
|
||||
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:
|
||||
p.im = inSelectIM
|
||||
return
|
||||
case a.Table:
|
||||
p.im = inSelectInTableIM
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
p.im = inSelectIM
|
||||
case a.Td, a.Th:
|
||||
// TODO: remove this divergence from the HTML5 spec.
|
||||
//
|
||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||
p.im = inCellIM
|
||||
case a.Tr:
|
||||
p.im = inRowIM
|
||||
@@ -490,37 +434,25 @@ func (p *parser) resetInsertionMode() {
|
||||
p.im = inColumnGroupIM
|
||||
case a.Table:
|
||||
p.im = inTableIM
|
||||
case a.Template:
|
||||
p.im = p.templateStack.top()
|
||||
case a.Head:
|
||||
// TODO: remove this divergence from the HTML5 spec.
|
||||
//
|
||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||
p.im = inHeadIM
|
||||
p.im = inBodyIM
|
||||
case a.Body:
|
||||
p.im = inBodyIM
|
||||
case a.Frameset:
|
||||
p.im = inFramesetIM
|
||||
case a.Html:
|
||||
if p.head == nil {
|
||||
p.im = beforeHeadIM
|
||||
} else {
|
||||
p.im = afterHeadIM
|
||||
}
|
||||
p.im = beforeHeadIM
|
||||
default:
|
||||
if last {
|
||||
p.im = inBodyIM
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
p.im = inBodyIM
|
||||
}
|
||||
|
||||
const whitespace = " \t\r\n\f"
|
||||
|
||||
// Section 12.2.6.4.1.
|
||||
// Section 12.2.5.4.1.
|
||||
func initialIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken:
|
||||
@@ -547,7 +479,7 @@ func initialIM(p *parser) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.2.
|
||||
// Section 12.2.5.4.2.
|
||||
func beforeHTMLIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case DoctypeToken:
|
||||
@@ -585,7 +517,7 @@ func beforeHTMLIM(p *parser) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.3.
|
||||
// Section 12.2.5.4.3.
|
||||
func beforeHeadIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken:
|
||||
@@ -628,7 +560,7 @@ func beforeHeadIM(p *parser) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.4.
|
||||
// Section 12.2.5.4.4.
|
||||
func inHeadIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken:
|
||||
@@ -658,36 +590,19 @@ func inHeadIM(p *parser) bool {
|
||||
case a.Head:
|
||||
// Ignore the token.
|
||||
return true
|
||||
case a.Template:
|
||||
p.addElement()
|
||||
p.afe = append(p.afe, &scopeMarker)
|
||||
p.framesetOK = false
|
||||
p.im = inTemplateIM
|
||||
p.templateStack = append(p.templateStack, inTemplateIM)
|
||||
return true
|
||||
}
|
||||
case EndTagToken:
|
||||
switch p.tok.DataAtom {
|
||||
case a.Head:
|
||||
p.oe.pop()
|
||||
n := p.oe.pop()
|
||||
if n.DataAtom != a.Head {
|
||||
panic("html: bad parser state: <head> element not found, in the in-head insertion mode")
|
||||
}
|
||||
p.im = afterHeadIM
|
||||
return true
|
||||
case a.Body, a.Html, a.Br:
|
||||
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
|
||||
return false
|
||||
case a.Template:
|
||||
if !p.oe.contains(a.Template) {
|
||||
return true
|
||||
}
|
||||
p.generateAllImpliedEndTags()
|
||||
if n := p.oe.top(); n.DataAtom != a.Template {
|
||||
return true
|
||||
}
|
||||
p.popUntil(defaultScope, a.Template)
|
||||
p.clearActiveFormattingElements()
|
||||
p.templateStack.pop()
|
||||
p.resetInsertionMode()
|
||||
return true
|
||||
default:
|
||||
// Ignore the token.
|
||||
return true
|
||||
@@ -707,7 +622,7 @@ func inHeadIM(p *parser) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.6.
|
||||
// Section 12.2.5.4.6.
|
||||
func afterHeadIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken:
|
||||
@@ -733,7 +648,7 @@ func afterHeadIM(p *parser) bool {
|
||||
p.addElement()
|
||||
p.im = inFramesetIM
|
||||
return true
|
||||
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
||||
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
|
||||
p.oe = append(p.oe, p.head)
|
||||
defer p.oe.remove(p.head)
|
||||
return inHeadIM(p)
|
||||
@@ -745,8 +660,6 @@ func afterHeadIM(p *parser) bool {
|
||||
switch p.tok.DataAtom {
|
||||
case a.Body, a.Html, a.Br:
|
||||
// Drop down to creating an implied <body> tag.
|
||||
case a.Template:
|
||||
return inHeadIM(p)
|
||||
default:
|
||||
// Ignore the token.
|
||||
return true
|
||||
@@ -784,7 +697,7 @@ func copyAttributes(dst *Node, src Token) {
|
||||
}
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.7.
|
||||
// Section 12.2.5.4.7.
|
||||
func inBodyIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken:
|
||||
@@ -814,16 +727,10 @@ func inBodyIM(p *parser) bool {
|
||||
case StartTagToken:
|
||||
switch p.tok.DataAtom {
|
||||
case a.Html:
|
||||
if p.oe.contains(a.Template) {
|
||||
return true
|
||||
}
|
||||
copyAttributes(p.oe[0], p.tok)
|
||||
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
||||
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
|
||||
return inHeadIM(p)
|
||||
case a.Body:
|
||||
if p.oe.contains(a.Template) {
|
||||
return true
|
||||
}
|
||||
if len(p.oe) >= 2 {
|
||||
body := p.oe[1]
|
||||
if body.Type == ElementNode && body.DataAtom == a.Body {
|
||||
@@ -860,7 +767,7 @@ func inBodyIM(p *parser) bool {
|
||||
// The newline, if any, will be dealt with by the TextToken case.
|
||||
p.framesetOK = false
|
||||
case a.Form:
|
||||
if p.oe.contains(a.Template) || p.form == nil {
|
||||
if p.form == nil {
|
||||
p.popUntil(buttonScope, a.P)
|
||||
p.addElement()
|
||||
p.form = p.top()
|
||||
@@ -1045,14 +952,9 @@ func inBodyIM(p *parser) bool {
|
||||
}
|
||||
p.reconstructActiveFormattingElements()
|
||||
p.addElement()
|
||||
case a.Rb, a.Rtc:
|
||||
if p.elementInScope(defaultScope, a.Ruby) {
|
||||
p.generateImpliedEndTags()
|
||||
}
|
||||
p.addElement()
|
||||
case a.Rp, a.Rt:
|
||||
if p.elementInScope(defaultScope, a.Ruby) {
|
||||
p.generateImpliedEndTags("rtc")
|
||||
p.generateImpliedEndTags()
|
||||
}
|
||||
p.addElement()
|
||||
case a.Math, a.Svg:
|
||||
@@ -1070,13 +972,7 @@ func inBodyIM(p *parser) bool {
|
||||
p.acknowledgeSelfClosingTag()
|
||||
}
|
||||
return true
|
||||
case a.Frame:
|
||||
// TODO: remove this divergence from the HTML5 spec.
|
||||
if p.oe.contains(a.Template) {
|
||||
p.addElement()
|
||||
return true
|
||||
}
|
||||
case a.Caption, a.Col, a.Colgroup, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
||||
case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
||||
// Ignore the token.
|
||||
default:
|
||||
p.reconstructActiveFormattingElements()
|
||||
@@ -1097,28 +993,15 @@ func inBodyIM(p *parser) bool {
|
||||
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
|
||||
p.popUntil(defaultScope, p.tok.DataAtom)
|
||||
case a.Form:
|
||||
if p.oe.contains(a.Template) {
|
||||
if !p.oe.contains(a.Form) {
|
||||
// Ignore the token.
|
||||
return true
|
||||
}
|
||||
p.generateImpliedEndTags()
|
||||
if p.tok.DataAtom == a.Form {
|
||||
// Ignore the token.
|
||||
return true
|
||||
}
|
||||
p.popUntil(defaultScope, a.Form)
|
||||
} else {
|
||||
node := p.form
|
||||
p.form = nil
|
||||
i := p.indexOfElementInScope(defaultScope, a.Form)
|
||||
if node == nil || i == -1 || p.oe[i] != node {
|
||||
// Ignore the token.
|
||||
return true
|
||||
}
|
||||
p.generateImpliedEndTags()
|
||||
p.oe.remove(node)
|
||||
node := p.form
|
||||
p.form = nil
|
||||
i := p.indexOfElementInScope(defaultScope, a.Form)
|
||||
if node == nil || i == -1 || p.oe[i] != node {
|
||||
// Ignore the token.
|
||||
return true
|
||||
}
|
||||
p.generateImpliedEndTags()
|
||||
p.oe.remove(node)
|
||||
case a.P:
|
||||
if !p.elementInScope(buttonScope, a.P) {
|
||||
p.parseImpliedToken(StartTagToken, a.P, a.P.String())
|
||||
@@ -1139,8 +1022,6 @@ func inBodyIM(p *parser) bool {
|
||||
case a.Br:
|
||||
p.tok.Type = StartTagToken
|
||||
return false
|
||||
case a.Template:
|
||||
return inHeadIM(p)
|
||||
default:
|
||||
p.inBodyEndTagOther(p.tok.DataAtom)
|
||||
}
|
||||
@@ -1149,21 +1030,6 @@ func inBodyIM(p *parser) bool {
|
||||
Type: CommentNode,
|
||||
Data: p.tok.Data,
|
||||
})
|
||||
case ErrorToken:
|
||||
// TODO: remove this divergence from the HTML5 spec.
|
||||
if len(p.templateStack) > 0 {
|
||||
p.im = inTemplateIM
|
||||
return false
|
||||
} else {
|
||||
for _, e := range p.oe {
|
||||
switch e.DataAtom {
|
||||
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc, a.Tbody, a.Td, a.Tfoot, a.Th,
|
||||
a.Thead, a.Tr, a.Body, a.Html:
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -1269,12 +1135,6 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
|
||||
switch commonAncestor.DataAtom {
|
||||
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
|
||||
p.fosterParent(lastNode)
|
||||
case a.Template:
|
||||
// TODO: remove namespace checking
|
||||
if commonAncestor.Namespace == "html" {
|
||||
commonAncestor = commonAncestor.LastChild
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
commonAncestor.AppendChild(lastNode)
|
||||
}
|
||||
@@ -1300,7 +1160,7 @@ 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
|
||||
// "Any other end tag" handling from 12.2.5.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) {
|
||||
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||
@@ -1314,7 +1174,7 @@ func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
|
||||
}
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.8.
|
||||
// Section 12.2.5.4.8.
|
||||
func textIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case ErrorToken:
|
||||
@@ -1343,7 +1203,7 @@ func textIM(p *parser) bool {
|
||||
return p.tok.Type == EndTagToken
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.9.
|
||||
// Section 12.2.5.4.9.
|
||||
func inTableIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case ErrorToken:
|
||||
@@ -1389,7 +1249,7 @@ func inTableIM(p *parser) bool {
|
||||
}
|
||||
// Ignore the token.
|
||||
return true
|
||||
case a.Style, a.Script, a.Template:
|
||||
case a.Style, a.Script:
|
||||
return inHeadIM(p)
|
||||
case a.Input:
|
||||
for _, t := range p.tok.Attr {
|
||||
@@ -1401,7 +1261,7 @@ func inTableIM(p *parser) bool {
|
||||
}
|
||||
// Otherwise drop down to the default action.
|
||||
case a.Form:
|
||||
if p.oe.contains(a.Template) || p.form != nil {
|
||||
if p.form != nil {
|
||||
// Ignore the token.
|
||||
return true
|
||||
}
|
||||
@@ -1431,8 +1291,6 @@ func inTableIM(p *parser) bool {
|
||||
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
||||
// Ignore the token.
|
||||
return true
|
||||
case a.Template:
|
||||
return inHeadIM(p)
|
||||
}
|
||||
case CommentToken:
|
||||
p.addChild(&Node{
|
||||
@@ -1451,7 +1309,7 @@ func inTableIM(p *parser) bool {
|
||||
return inBodyIM(p)
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.11.
|
||||
// Section 12.2.5.4.11.
|
||||
func inCaptionIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case StartTagToken:
|
||||
@@ -1497,7 +1355,7 @@ func inCaptionIM(p *parser) bool {
|
||||
return inBodyIM(p)
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.12.
|
||||
// Section 12.2.5.4.12.
|
||||
func inColumnGroupIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken:
|
||||
@@ -1528,13 +1386,11 @@ func inColumnGroupIM(p *parser) bool {
|
||||
p.oe.pop()
|
||||
p.acknowledgeSelfClosingTag()
|
||||
return true
|
||||
case a.Template:
|
||||
return inHeadIM(p)
|
||||
}
|
||||
case EndTagToken:
|
||||
switch p.tok.DataAtom {
|
||||
case a.Colgroup:
|
||||
if p.oe.top().DataAtom == a.Colgroup {
|
||||
if p.oe.top().DataAtom != a.Html {
|
||||
p.oe.pop()
|
||||
p.im = inTableIM
|
||||
}
|
||||
@@ -1542,19 +1398,17 @@ func inColumnGroupIM(p *parser) bool {
|
||||
case a.Col:
|
||||
// Ignore the token.
|
||||
return true
|
||||
case a.Template:
|
||||
return inHeadIM(p)
|
||||
}
|
||||
}
|
||||
if p.oe.top().DataAtom != a.Colgroup {
|
||||
return true
|
||||
if p.oe.top().DataAtom != a.Html {
|
||||
p.oe.pop()
|
||||
p.im = inTableIM
|
||||
return false
|
||||
}
|
||||
p.oe.pop()
|
||||
p.im = inTableIM
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.13.
|
||||
// Section 12.2.5.4.13.
|
||||
func inTableBodyIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case StartTagToken:
|
||||
@@ -1606,7 +1460,7 @@ func inTableBodyIM(p *parser) bool {
|
||||
return inTableIM(p)
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.14.
|
||||
// Section 12.2.5.4.14.
|
||||
func inRowIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case StartTagToken:
|
||||
@@ -1657,7 +1511,7 @@ func inRowIM(p *parser) bool {
|
||||
return inTableIM(p)
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.15.
|
||||
// Section 12.2.5.4.15.
|
||||
func inCellIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case StartTagToken:
|
||||
@@ -1706,7 +1560,7 @@ func inCellIM(p *parser) bool {
|
||||
return inBodyIM(p)
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.16.
|
||||
// Section 12.2.5.4.16.
|
||||
func inSelectIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case ErrorToken:
|
||||
@@ -1743,7 +1597,7 @@ func inSelectIM(p *parser) bool {
|
||||
p.tokenizer.NextIsNotRawText()
|
||||
// Ignore the token.
|
||||
return true
|
||||
case a.Script, a.Template:
|
||||
case a.Script:
|
||||
return inHeadIM(p)
|
||||
}
|
||||
case EndTagToken:
|
||||
@@ -1764,8 +1618,6 @@ func inSelectIM(p *parser) bool {
|
||||
if p.popUntil(selectScope, a.Select) {
|
||||
p.resetInsertionMode()
|
||||
}
|
||||
case a.Template:
|
||||
return inHeadIM(p)
|
||||
}
|
||||
case CommentToken:
|
||||
p.addChild(&Node{
|
||||
@@ -1780,7 +1632,7 @@ func inSelectIM(p *parser) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.17.
|
||||
// Section 12.2.5.4.17.
|
||||
func inSelectInTableIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case StartTagToken, EndTagToken:
|
||||
@@ -1798,62 +1650,7 @@ func inSelectInTableIM(p *parser) bool {
|
||||
return inSelectIM(p)
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.18.
|
||||
func inTemplateIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken, CommentToken, DoctypeToken:
|
||||
return inBodyIM(p)
|
||||
case StartTagToken:
|
||||
switch p.tok.DataAtom {
|
||||
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
||||
return inHeadIM(p)
|
||||
case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
|
||||
p.templateStack.pop()
|
||||
p.templateStack = append(p.templateStack, inTableIM)
|
||||
p.im = inTableIM
|
||||
return false
|
||||
case a.Col:
|
||||
p.templateStack.pop()
|
||||
p.templateStack = append(p.templateStack, inColumnGroupIM)
|
||||
p.im = inColumnGroupIM
|
||||
return false
|
||||
case a.Tr:
|
||||
p.templateStack.pop()
|
||||
p.templateStack = append(p.templateStack, inTableBodyIM)
|
||||
p.im = inTableBodyIM
|
||||
return false
|
||||
case a.Td, a.Th:
|
||||
p.templateStack.pop()
|
||||
p.templateStack = append(p.templateStack, inRowIM)
|
||||
p.im = inRowIM
|
||||
return false
|
||||
default:
|
||||
p.templateStack.pop()
|
||||
p.templateStack = append(p.templateStack, inBodyIM)
|
||||
p.im = inBodyIM
|
||||
return false
|
||||
}
|
||||
case EndTagToken:
|
||||
switch p.tok.DataAtom {
|
||||
case a.Template:
|
||||
return inHeadIM(p)
|
||||
default:
|
||||
// Ignore the token.
|
||||
return true
|
||||
}
|
||||
}
|
||||
if !p.oe.contains(a.Template) {
|
||||
// Ignore the token.
|
||||
return true
|
||||
}
|
||||
p.popUntil(defaultScope, a.Template)
|
||||
p.clearActiveFormattingElements()
|
||||
p.templateStack.pop()
|
||||
p.resetInsertionMode()
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.19.
|
||||
// Section 12.2.5.4.18.
|
||||
func afterBodyIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case ErrorToken:
|
||||
@@ -1891,7 +1688,7 @@ func afterBodyIM(p *parser) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.20.
|
||||
// Section 12.2.5.4.19.
|
||||
func inFramesetIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case CommentToken:
|
||||
@@ -1923,11 +1720,6 @@ func inFramesetIM(p *parser) bool {
|
||||
p.acknowledgeSelfClosingTag()
|
||||
case a.Noframes:
|
||||
return inHeadIM(p)
|
||||
case a.Template:
|
||||
// TODO: remove this divergence from the HTML5 spec.
|
||||
//
|
||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||
return inTemplateIM(p)
|
||||
}
|
||||
case EndTagToken:
|
||||
switch p.tok.DataAtom {
|
||||
@@ -1946,7 +1738,7 @@ func inFramesetIM(p *parser) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.21.
|
||||
// Section 12.2.5.4.20.
|
||||
func afterFramesetIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case CommentToken:
|
||||
@@ -1985,7 +1777,7 @@ func afterFramesetIM(p *parser) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.22.
|
||||
// Section 12.2.5.4.21.
|
||||
func afterAfterBodyIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case ErrorToken:
|
||||
@@ -2014,7 +1806,7 @@ func afterAfterBodyIM(p *parser) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Section 12.2.6.4.23.
|
||||
// Section 12.2.5.4.22.
|
||||
func afterAfterFramesetIM(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case CommentToken:
|
||||
@@ -2052,7 +1844,7 @@ func afterAfterFramesetIM(p *parser) bool {
|
||||
|
||||
const whitespaceOrNUL = whitespace + "\x00"
|
||||
|
||||
// Section 12.2.6.5
|
||||
// Section 12.2.5.5.
|
||||
func parseForeignContent(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken:
|
||||
@@ -2132,7 +1924,7 @@ func parseForeignContent(p *parser) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Section 12.2.6.
|
||||
// Section 12.2.5.
|
||||
func (p *parser) inForeignContent() bool {
|
||||
if len(p.oe) == 0 {
|
||||
return false
|
||||
@@ -2272,9 +2064,6 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
|
||||
}
|
||||
p.doc.AppendChild(root)
|
||||
p.oe = nodeStack{root}
|
||||
if context != nil && context.DataAtom == a.Template {
|
||||
p.templateStack = append(p.templateStack, inTemplateIM)
|
||||
}
|
||||
p.resetInsertionMode()
|
||||
|
||||
for n := context; n != nil; n = n.Parent {
|
||||
|
||||
16
vendor/golang.org/x/net/html/parse_test.go
generated
vendored
16
vendor/golang.org/x/net/html/parse_test.go
generated
vendored
@@ -125,7 +125,6 @@ func (a sortedAttributes) Swap(i, j int) {
|
||||
|
||||
func dumpLevel(w io.Writer, n *Node, level int) error {
|
||||
dumpIndent(w, level)
|
||||
level++
|
||||
switch n.Type {
|
||||
case ErrorNode:
|
||||
return errors.New("unexpected ErrorNode")
|
||||
@@ -141,19 +140,13 @@ func dumpLevel(w io.Writer, n *Node, level int) error {
|
||||
sort.Sort(attr)
|
||||
for _, a := range attr {
|
||||
io.WriteString(w, "\n")
|
||||
dumpIndent(w, level)
|
||||
dumpIndent(w, level+1)
|
||||
if a.Namespace != "" {
|
||||
fmt.Fprintf(w, `%s %s="%s"`, a.Namespace, a.Key, a.Val)
|
||||
} else {
|
||||
fmt.Fprintf(w, `%s="%s"`, a.Key, a.Val)
|
||||
}
|
||||
}
|
||||
if n.Namespace == "" && n.DataAtom == atom.Template {
|
||||
io.WriteString(w, "\n")
|
||||
dumpIndent(w, level)
|
||||
level++
|
||||
io.WriteString(w, "content")
|
||||
}
|
||||
case TextNode:
|
||||
fmt.Fprintf(w, `"%s"`, n.Data)
|
||||
case CommentNode:
|
||||
@@ -183,7 +176,7 @@ func dumpLevel(w io.Writer, n *Node, level int) error {
|
||||
}
|
||||
io.WriteString(w, "\n")
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if err := dumpLevel(w, c, level); err != nil {
|
||||
if err := dumpLevel(w, c, level+1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -380,11 +373,6 @@ func TestNodeConsistency(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFragmentWithNilContext(t *testing.T) {
|
||||
// This shouldn't panic.
|
||||
ParseFragment(strings.NewReader("<p>hello</p>"), nil)
|
||||
}
|
||||
|
||||
func BenchmarkParser(b *testing.B) {
|
||||
buf, err := ioutil.ReadFile("testdata/go1.html")
|
||||
if err != nil {
|
||||
|
||||
298
vendor/golang.org/x/net/html/testdata/webkit/ruby.dat
generated
vendored
298
vendor/golang.org/x/net/html/testdata/webkit/ruby.dat
generated
vendored
@@ -1,298 +0,0 @@
|
||||
#data
|
||||
<html><ruby>a<rb>b<rb></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rb>
|
||||
| "b"
|
||||
| <rb>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rb>b<rt></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rb>
|
||||
| "b"
|
||||
| <rt>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rb>b<rtc></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rb>
|
||||
| "b"
|
||||
| <rtc>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rb>b<rp></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rb>
|
||||
| "b"
|
||||
| <rp>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rb>b<span></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rb>
|
||||
| "b"
|
||||
| <span>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rt>b<rb></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rt>
|
||||
| "b"
|
||||
| <rb>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rt>b<rt></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rt>
|
||||
| "b"
|
||||
| <rt>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rt>b<rtc></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rt>
|
||||
| "b"
|
||||
| <rtc>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rt>b<rp></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rt>
|
||||
| "b"
|
||||
| <rp>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rt>b<span></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rt>
|
||||
| "b"
|
||||
| <span>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rtc>b<rb></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rtc>
|
||||
| "b"
|
||||
| <rb>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rtc>b<rt>c<rt>d</ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rtc>
|
||||
| "b"
|
||||
| <rt>
|
||||
| "c"
|
||||
| <rt>
|
||||
| "d"
|
||||
|
||||
#data
|
||||
<html><ruby>a<rtc>b<rtc></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rtc>
|
||||
| "b"
|
||||
| <rtc>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rtc>b<rp></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rtc>
|
||||
| "b"
|
||||
| <rp>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rtc>b<span></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rtc>
|
||||
| "b"
|
||||
| <span>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rp>b<rb></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rp>
|
||||
| "b"
|
||||
| <rb>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rp>b<rt></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rp>
|
||||
| "b"
|
||||
| <rt>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rp>b<rtc></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rp>
|
||||
| "b"
|
||||
| <rtc>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rp>b<rp></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rp>
|
||||
| "b"
|
||||
| <rp>
|
||||
|
||||
#data
|
||||
<html><ruby>a<rp>b<span></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rp>
|
||||
| "b"
|
||||
| <span>
|
||||
|
||||
#data
|
||||
<html><ruby><rtc><ruby>a<rb>b<rt></ruby></ruby></html>
|
||||
#errors
|
||||
(1,6): expected-doctype-but-got-start-tag
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <ruby>
|
||||
| <rtc>
|
||||
| <ruby>
|
||||
| "a"
|
||||
| <rb>
|
||||
| "b"
|
||||
| <rt>
|
||||
1117
vendor/golang.org/x/net/html/testdata/webkit/template.dat
generated
vendored
1117
vendor/golang.org/x/net/html/testdata/webkit/template.dat
generated
vendored
File diff suppressed because it is too large
Load Diff
4
vendor/golang.org/x/net/html/token.go
generated
vendored
4
vendor/golang.org/x/net/html/token.go
generated
vendored
@@ -1161,8 +1161,8 @@ func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
|
||||
return nil, nil, false
|
||||
}
|
||||
|
||||
// Token returns the current Token. The result's Data and Attr values remain
|
||||
// valid after subsequent Next calls.
|
||||
// Token returns the next Token. The result's Data and Attr values remain valid
|
||||
// after subsequent Next calls.
|
||||
func (z *Tokenizer) Token() Token {
|
||||
t := Token{Type: z.tt}
|
||||
switch z.tt {
|
||||
|
||||
28
vendor/golang.org/x/net/html/token_test.go
generated
vendored
28
vendor/golang.org/x/net/html/token_test.go
generated
vendored
@@ -589,20 +589,20 @@ func TestConvertNewlines(t *testing.T) {
|
||||
"Mac\rDOS\r\nUnix\n": "Mac\nDOS\nUnix\n",
|
||||
"Unix\nMac\rDOS\r\n": "Unix\nMac\nDOS\n",
|
||||
"DOS\r\nDOS\r\nDOS\r\n": "DOS\nDOS\nDOS\n",
|
||||
"": "",
|
||||
"\n": "\n",
|
||||
"\n\r": "\n\n",
|
||||
"\r": "\n",
|
||||
"\r\n": "\n",
|
||||
"\r\n\n": "\n\n",
|
||||
"\r\n\r": "\n\n",
|
||||
"\r\n\r\n": "\n\n",
|
||||
"\r\r": "\n\n",
|
||||
"\r\r\n": "\n\n",
|
||||
"\r\r\n\n": "\n\n\n",
|
||||
"\r\r\r\n": "\n\n\n",
|
||||
"\r \n": "\n \n",
|
||||
"xyz": "xyz",
|
||||
"": "",
|
||||
"\n": "\n",
|
||||
"\n\r": "\n\n",
|
||||
"\r": "\n",
|
||||
"\r\n": "\n",
|
||||
"\r\n\n": "\n\n",
|
||||
"\r\n\r": "\n\n",
|
||||
"\r\n\r\n": "\n\n",
|
||||
"\r\r": "\n\n",
|
||||
"\r\r\n": "\n\n",
|
||||
"\r\r\n\n": "\n\n\n",
|
||||
"\r\r\r\n": "\n\n\n",
|
||||
"\r \n": "\n \n",
|
||||
"xyz": "xyz",
|
||||
}
|
||||
for in, want := range testCases {
|
||||
if got := string(convertNewlines([]byte(in))); got != want {
|
||||
|
||||
65
vendor/golang.org/x/net/http/httpguts/guts.go
generated
vendored
65
vendor/golang.org/x/net/http/httpguts/guts.go
generated
vendored
@@ -1,65 +0,0 @@
|
||||
// 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 httpguts provides functions implementing various details
|
||||
// of the HTTP specification.
|
||||
//
|
||||
// This package is shared by the standard library (which vendors it)
|
||||
// and x/net/http2. It comes with no API stability promise.
|
||||
package httpguts
|
||||
|
||||
import (
|
||||
"net/textproto"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SniffedContentType reports whether ct is a Content-Type that is known
|
||||
// to cause client-side content sniffing.
|
||||
//
|
||||
// This provides just a partial implementation of mime.ParseMediaType
|
||||
// with the assumption that the Content-Type is not attacker controlled.
|
||||
func SniffedContentType(ct string) bool {
|
||||
if i := strings.Index(ct, ";"); i != -1 {
|
||||
ct = ct[:i]
|
||||
}
|
||||
ct = strings.ToLower(strings.TrimSpace(ct))
|
||||
return ct == "text/plain" || ct == "application/octet-stream" ||
|
||||
ct == "application/unknown" || ct == "unknown/unknown" || ct == "*/*" ||
|
||||
!strings.Contains(ct, "/")
|
||||
}
|
||||
|
||||
// ValidTrailerHeader reports whether name is a valid header field name to appear
|
||||
// in trailers.
|
||||
// See RFC 7230, Section 4.1.2
|
||||
func ValidTrailerHeader(name string) bool {
|
||||
name = textproto.CanonicalMIMEHeaderKey(name)
|
||||
if strings.HasPrefix(name, "If-") || badTrailer[name] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var badTrailer = map[string]bool{
|
||||
"Authorization": true,
|
||||
"Cache-Control": true,
|
||||
"Connection": true,
|
||||
"Content-Encoding": true,
|
||||
"Content-Length": true,
|
||||
"Content-Range": true,
|
||||
"Content-Type": true,
|
||||
"Expect": true,
|
||||
"Host": true,
|
||||
"Keep-Alive": true,
|
||||
"Max-Forwards": true,
|
||||
"Pragma": true,
|
||||
"Proxy-Authenticate": true,
|
||||
"Proxy-Authorization": true,
|
||||
"Proxy-Connection": true,
|
||||
"Range": true,
|
||||
"Realm": true,
|
||||
"Te": true,
|
||||
"Trailer": true,
|
||||
"Transfer-Encoding": true,
|
||||
"Www-Authenticate": true,
|
||||
}
|
||||
7
vendor/golang.org/x/net/http/httpproxy/export_test.go
generated
vendored
7
vendor/golang.org/x/net/http/httpproxy/export_test.go
generated
vendored
@@ -1,7 +0,0 @@
|
||||
// Copyright 2017 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 httpproxy
|
||||
|
||||
var ExportUseProxy = (*Config).useProxy
|
||||
13
vendor/golang.org/x/net/http/httpproxy/go19_test.go
generated
vendored
13
vendor/golang.org/x/net/http/httpproxy/go19_test.go
generated
vendored
@@ -1,13 +0,0 @@
|
||||
// Copyright 2017 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.9
|
||||
|
||||
package httpproxy_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func init() {
|
||||
setHelper = func(t *testing.T) { t.Helper() }
|
||||
}
|
||||
239
vendor/golang.org/x/net/http/httpproxy/proxy.go
generated
vendored
239
vendor/golang.org/x/net/http/httpproxy/proxy.go
generated
vendored
@@ -1,239 +0,0 @@
|
||||
// Copyright 2017 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 httpproxy provides support for HTTP proxy determination
|
||||
// based on environment variables, as provided by net/http's
|
||||
// ProxyFromEnvironment function.
|
||||
//
|
||||
// The API is not subject to the Go 1 compatibility promise and may change at
|
||||
// any time.
|
||||
package httpproxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// Config holds configuration for HTTP proxy settings. See
|
||||
// FromEnvironment for details.
|
||||
type Config struct {
|
||||
// HTTPProxy represents the value of the HTTP_PROXY or
|
||||
// http_proxy environment variable. It will be used as the proxy
|
||||
// URL for HTTP requests and HTTPS requests unless overridden by
|
||||
// HTTPSProxy or NoProxy.
|
||||
HTTPProxy string
|
||||
|
||||
// HTTPSProxy represents the HTTPS_PROXY or https_proxy
|
||||
// environment variable. It will be used as the proxy URL for
|
||||
// HTTPS requests unless overridden by NoProxy.
|
||||
HTTPSProxy string
|
||||
|
||||
// NoProxy represents the NO_PROXY or no_proxy environment
|
||||
// variable. It specifies URLs that should be excluded from
|
||||
// proxying as a comma-separated list of domain names or a
|
||||
// single asterisk (*) to indicate that no proxying should be
|
||||
// done. A domain name matches that name and all subdomains. A
|
||||
// domain name with a leading "." matches subdomains only. For
|
||||
// example "foo.com" matches "foo.com" and "bar.foo.com";
|
||||
// ".y.com" matches "x.y.com" but not "y.com".
|
||||
NoProxy string
|
||||
|
||||
// CGI holds whether the current process is running
|
||||
// as a CGI handler (FromEnvironment infers this from the
|
||||
// presence of a REQUEST_METHOD environment variable).
|
||||
// When this is set, ProxyForURL will return an error
|
||||
// when HTTPProxy applies, because a client could be
|
||||
// setting HTTP_PROXY maliciously. See https://golang.org/s/cgihttpproxy.
|
||||
CGI bool
|
||||
}
|
||||
|
||||
// FromEnvironment returns a Config instance populated from the
|
||||
// environment variables HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or the
|
||||
// lowercase versions thereof). HTTPS_PROXY takes precedence over
|
||||
// HTTP_PROXY for https requests.
|
||||
//
|
||||
// The environment values may be either a complete URL or a
|
||||
// "host[:port]", in which case the "http" scheme is assumed. An error
|
||||
// is returned if the value is a different form.
|
||||
func FromEnvironment() *Config {
|
||||
return &Config{
|
||||
HTTPProxy: getEnvAny("HTTP_PROXY", "http_proxy"),
|
||||
HTTPSProxy: getEnvAny("HTTPS_PROXY", "https_proxy"),
|
||||
NoProxy: getEnvAny("NO_PROXY", "no_proxy"),
|
||||
CGI: os.Getenv("REQUEST_METHOD") != "",
|
||||
}
|
||||
}
|
||||
|
||||
func getEnvAny(names ...string) string {
|
||||
for _, n := range names {
|
||||
if val := os.Getenv(n); val != "" {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ProxyFunc returns a function that determines the proxy URL to use for
|
||||
// a given request URL. Changing the contents of cfg will not affect
|
||||
// proxy functions created earlier.
|
||||
//
|
||||
// A nil URL and nil error are returned if no proxy is defined in the
|
||||
// environment, or a proxy should not be used for the given request, as
|
||||
// defined by NO_PROXY.
|
||||
//
|
||||
// As a special case, if req.URL.Host is "localhost" (with or without a
|
||||
// port number), then a nil URL and nil error will be returned.
|
||||
func (cfg *Config) ProxyFunc() func(reqURL *url.URL) (*url.URL, error) {
|
||||
// Prevent Config changes from affecting the function calculation.
|
||||
// TODO Preprocess proxy settings for more efficient evaluation.
|
||||
cfg1 := *cfg
|
||||
return cfg1.proxyForURL
|
||||
}
|
||||
|
||||
func (cfg *Config) proxyForURL(reqURL *url.URL) (*url.URL, error) {
|
||||
var proxy string
|
||||
if reqURL.Scheme == "https" {
|
||||
proxy = cfg.HTTPSProxy
|
||||
}
|
||||
if proxy == "" {
|
||||
proxy = cfg.HTTPProxy
|
||||
if proxy != "" && cfg.CGI {
|
||||
return nil, errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")
|
||||
}
|
||||
}
|
||||
if proxy == "" {
|
||||
return nil, nil
|
||||
}
|
||||
if !cfg.useProxy(canonicalAddr(reqURL)) {
|
||||
return nil, nil
|
||||
}
|
||||
proxyURL, err := url.Parse(proxy)
|
||||
if err != nil ||
|
||||
(proxyURL.Scheme != "http" &&
|
||||
proxyURL.Scheme != "https" &&
|
||||
proxyURL.Scheme != "socks5") {
|
||||
// proxy was bogus. Try prepending "http://" to it and
|
||||
// see if that parses correctly. If not, we fall
|
||||
// through and complain about the original one.
|
||||
if proxyURL, err := url.Parse("http://" + proxy); err == nil {
|
||||
return proxyURL, nil
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid proxy address %q: %v", proxy, err)
|
||||
}
|
||||
return proxyURL, nil
|
||||
}
|
||||
|
||||
// useProxy reports whether requests to addr should use a proxy,
|
||||
// according to the NO_PROXY or no_proxy environment variable.
|
||||
// addr is always a canonicalAddr with a host and port.
|
||||
func (cfg *Config) useProxy(addr string) bool {
|
||||
if len(addr) == 0 {
|
||||
return true
|
||||
}
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if host == "localhost" {
|
||||
return false
|
||||
}
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
if ip.IsLoopback() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
noProxy := cfg.NoProxy
|
||||
if noProxy == "*" {
|
||||
return false
|
||||
}
|
||||
|
||||
addr = strings.ToLower(strings.TrimSpace(addr))
|
||||
if hasPort(addr) {
|
||||
addr = addr[:strings.LastIndex(addr, ":")]
|
||||
}
|
||||
|
||||
for _, p := range strings.Split(noProxy, ",") {
|
||||
p = strings.ToLower(strings.TrimSpace(p))
|
||||
if len(p) == 0 {
|
||||
continue
|
||||
}
|
||||
if hasPort(p) {
|
||||
p = p[:strings.LastIndex(p, ":")]
|
||||
}
|
||||
if addr == p {
|
||||
return false
|
||||
}
|
||||
if len(p) == 0 {
|
||||
// There is no host part, likely the entry is malformed; ignore.
|
||||
continue
|
||||
}
|
||||
if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) {
|
||||
// no_proxy ".foo.com" matches "bar.foo.com" or "foo.com"
|
||||
return false
|
||||
}
|
||||
if p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.' {
|
||||
// no_proxy "foo.com" matches "bar.foo.com"
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var portMap = map[string]string{
|
||||
"http": "80",
|
||||
"https": "443",
|
||||
"socks5": "1080",
|
||||
}
|
||||
|
||||
// canonicalAddr returns url.Host but always with a ":port" suffix
|
||||
func canonicalAddr(url *url.URL) string {
|
||||
addr := url.Hostname()
|
||||
if v, err := idnaASCII(addr); err == nil {
|
||||
addr = v
|
||||
}
|
||||
port := url.Port()
|
||||
if port == "" {
|
||||
port = portMap[url.Scheme]
|
||||
}
|
||||
return net.JoinHostPort(addr, port)
|
||||
}
|
||||
|
||||
// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
|
||||
// return true if the string includes a port.
|
||||
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
|
||||
|
||||
func idnaASCII(v string) (string, error) {
|
||||
// TODO: Consider removing this check after verifying performance is okay.
|
||||
// Right now punycode verification, length checks, context checks, and the
|
||||
// permissible character tests are all omitted. It also prevents the ToASCII
|
||||
// call from salvaging an invalid IDN, when possible. As a result it may be
|
||||
// possible to have two IDNs that appear identical to the user where the
|
||||
// ASCII-only version causes an error downstream whereas the non-ASCII
|
||||
// version does not.
|
||||
// Note that for correct ASCII IDNs ToASCII will only do considerably more
|
||||
// work, but it will not cause an allocation.
|
||||
if isASCII(v) {
|
||||
return v, nil
|
||||
}
|
||||
return idna.Lookup.ToASCII(v)
|
||||
}
|
||||
|
||||
func isASCII(s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] >= utf8.RuneSelf {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
301
vendor/golang.org/x/net/http/httpproxy/proxy_test.go
generated
vendored
301
vendor/golang.org/x/net/http/httpproxy/proxy_test.go
generated
vendored
@@ -1,301 +0,0 @@
|
||||
// Copyright 2017 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 httpproxy_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
)
|
||||
|
||||
// setHelper calls t.Helper() for Go 1.9+ (see go19_test.go) and does nothing otherwise.
|
||||
var setHelper = func(t *testing.T) {}
|
||||
|
||||
type proxyForURLTest struct {
|
||||
cfg httpproxy.Config
|
||||
req string // URL to fetch; blank means "http://example.com"
|
||||
want string
|
||||
wanterr error
|
||||
}
|
||||
|
||||
func (t proxyForURLTest) String() string {
|
||||
var buf bytes.Buffer
|
||||
space := func() {
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
}
|
||||
if t.cfg.HTTPProxy != "" {
|
||||
fmt.Fprintf(&buf, "http_proxy=%q", t.cfg.HTTPProxy)
|
||||
}
|
||||
if t.cfg.HTTPSProxy != "" {
|
||||
space()
|
||||
fmt.Fprintf(&buf, "https_proxy=%q", t.cfg.HTTPSProxy)
|
||||
}
|
||||
if t.cfg.NoProxy != "" {
|
||||
space()
|
||||
fmt.Fprintf(&buf, "no_proxy=%q", t.cfg.NoProxy)
|
||||
}
|
||||
req := "http://example.com"
|
||||
if t.req != "" {
|
||||
req = t.req
|
||||
}
|
||||
space()
|
||||
fmt.Fprintf(&buf, "req=%q", req)
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
var proxyForURLTests = []proxyForURLTest{{
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "127.0.0.1:8080",
|
||||
},
|
||||
want: "http://127.0.0.1:8080",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "cache.corp.example.com:1234",
|
||||
},
|
||||
want: "http://cache.corp.example.com:1234",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "cache.corp.example.com",
|
||||
},
|
||||
want: "http://cache.corp.example.com",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "https://cache.corp.example.com",
|
||||
},
|
||||
want: "https://cache.corp.example.com",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "http://127.0.0.1:8080",
|
||||
},
|
||||
want: "http://127.0.0.1:8080",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "https://127.0.0.1:8080",
|
||||
},
|
||||
want: "https://127.0.0.1:8080",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "socks5://127.0.0.1",
|
||||
},
|
||||
want: "socks5://127.0.0.1",
|
||||
}, {
|
||||
// Don't use secure for http
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "http.proxy.tld",
|
||||
HTTPSProxy: "secure.proxy.tld",
|
||||
},
|
||||
req: "http://insecure.tld/",
|
||||
want: "http://http.proxy.tld",
|
||||
}, {
|
||||
// Use secure for https.
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "http.proxy.tld",
|
||||
HTTPSProxy: "secure.proxy.tld",
|
||||
},
|
||||
req: "https://secure.tld/",
|
||||
want: "http://secure.proxy.tld",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "http.proxy.tld",
|
||||
HTTPSProxy: "https://secure.proxy.tld",
|
||||
},
|
||||
req: "https://secure.tld/",
|
||||
want: "https://secure.proxy.tld",
|
||||
}, {
|
||||
// Issue 16405: don't use HTTP_PROXY in a CGI environment,
|
||||
// where HTTP_PROXY can be attacker-controlled.
|
||||
cfg: httpproxy.Config{
|
||||
HTTPProxy: "http://10.1.2.3:8080",
|
||||
CGI: true,
|
||||
},
|
||||
want: "<nil>",
|
||||
wanterr: errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy"),
|
||||
}, {
|
||||
// HTTPS proxy is still used even in CGI environment.
|
||||
// (perhaps dubious but it's the historical behaviour).
|
||||
cfg: httpproxy.Config{
|
||||
HTTPSProxy: "https://secure.proxy.tld",
|
||||
CGI: true,
|
||||
},
|
||||
req: "https://secure.tld/",
|
||||
want: "https://secure.proxy.tld",
|
||||
}, {
|
||||
want: "<nil>",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
NoProxy: "example.com",
|
||||
HTTPProxy: "proxy",
|
||||
},
|
||||
req: "http://example.com/",
|
||||
want: "<nil>",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
NoProxy: ".example.com",
|
||||
HTTPProxy: "proxy",
|
||||
},
|
||||
req: "http://example.com/",
|
||||
want: "<nil>",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
NoProxy: "ample.com",
|
||||
HTTPProxy: "proxy",
|
||||
},
|
||||
req: "http://example.com/",
|
||||
want: "http://proxy",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
NoProxy: "example.com",
|
||||
HTTPProxy: "proxy",
|
||||
},
|
||||
req: "http://foo.example.com/",
|
||||
want: "<nil>",
|
||||
}, {
|
||||
cfg: httpproxy.Config{
|
||||
NoProxy: ".foo.com",
|
||||
HTTPProxy: "proxy",
|
||||
},
|
||||
req: "http://example.com/",
|
||||
want: "http://proxy",
|
||||
}}
|
||||
|
||||
func testProxyForURL(t *testing.T, tt proxyForURLTest) {
|
||||
setHelper(t)
|
||||
reqURLStr := tt.req
|
||||
if reqURLStr == "" {
|
||||
reqURLStr = "http://example.com"
|
||||
}
|
||||
reqURL, err := url.Parse(reqURLStr)
|
||||
if err != nil {
|
||||
t.Errorf("invalid URL %q", reqURLStr)
|
||||
return
|
||||
}
|
||||
cfg := tt.cfg
|
||||
proxyForURL := cfg.ProxyFunc()
|
||||
url, err := proxyForURL(reqURL)
|
||||
if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
|
||||
t.Errorf("%v: got error = %q, want %q", tt, g, e)
|
||||
return
|
||||
}
|
||||
if got := fmt.Sprintf("%s", url); got != tt.want {
|
||||
t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want)
|
||||
}
|
||||
|
||||
// Check that changing the Config doesn't change the results
|
||||
// of the functuon.
|
||||
cfg = httpproxy.Config{}
|
||||
url, err = proxyForURL(reqURL)
|
||||
if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
|
||||
t.Errorf("(after mutating config) %v: got error = %q, want %q", tt, g, e)
|
||||
return
|
||||
}
|
||||
if got := fmt.Sprintf("%s", url); got != tt.want {
|
||||
t.Errorf("(after mutating config) %v: got URL = %q, want %q", tt, url, tt.want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxyForURL(t *testing.T) {
|
||||
for _, tt := range proxyForURLTests {
|
||||
testProxyForURL(t, tt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromEnvironment(t *testing.T) {
|
||||
os.Setenv("HTTP_PROXY", "httpproxy")
|
||||
os.Setenv("HTTPS_PROXY", "httpsproxy")
|
||||
os.Setenv("NO_PROXY", "noproxy")
|
||||
os.Setenv("REQUEST_METHOD", "")
|
||||
got := httpproxy.FromEnvironment()
|
||||
want := httpproxy.Config{
|
||||
HTTPProxy: "httpproxy",
|
||||
HTTPSProxy: "httpsproxy",
|
||||
NoProxy: "noproxy",
|
||||
}
|
||||
if *got != want {
|
||||
t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromEnvironmentWithRequestMethod(t *testing.T) {
|
||||
os.Setenv("HTTP_PROXY", "httpproxy")
|
||||
os.Setenv("HTTPS_PROXY", "httpsproxy")
|
||||
os.Setenv("NO_PROXY", "noproxy")
|
||||
os.Setenv("REQUEST_METHOD", "PUT")
|
||||
got := httpproxy.FromEnvironment()
|
||||
want := httpproxy.Config{
|
||||
HTTPProxy: "httpproxy",
|
||||
HTTPSProxy: "httpsproxy",
|
||||
NoProxy: "noproxy",
|
||||
CGI: true,
|
||||
}
|
||||
if *got != want {
|
||||
t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromEnvironmentLowerCase(t *testing.T) {
|
||||
os.Setenv("http_proxy", "httpproxy")
|
||||
os.Setenv("https_proxy", "httpsproxy")
|
||||
os.Setenv("no_proxy", "noproxy")
|
||||
os.Setenv("REQUEST_METHOD", "")
|
||||
got := httpproxy.FromEnvironment()
|
||||
want := httpproxy.Config{
|
||||
HTTPProxy: "httpproxy",
|
||||
HTTPSProxy: "httpsproxy",
|
||||
NoProxy: "noproxy",
|
||||
}
|
||||
if *got != want {
|
||||
t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
var UseProxyTests = []struct {
|
||||
host string
|
||||
match bool
|
||||
}{
|
||||
// Never proxy localhost:
|
||||
{"localhost", false},
|
||||
{"127.0.0.1", false},
|
||||
{"127.0.0.2", false},
|
||||
{"[::1]", false},
|
||||
{"[::2]", true}, // not a loopback address
|
||||
|
||||
{"barbaz.net", false}, // match as .barbaz.net
|
||||
{"foobar.com", false}, // have a port but match
|
||||
{"foofoobar.com", true}, // not match as a part of foobar.com
|
||||
{"baz.com", true}, // not match as a part of barbaz.com
|
||||
{"localhost.net", true}, // not match as suffix of address
|
||||
{"local.localhost", true}, // not match as prefix as address
|
||||
{"barbarbaz.net", true}, // not match because NO_PROXY have a '.'
|
||||
{"www.foobar.com", false}, // match because NO_PROXY includes "foobar.com"
|
||||
}
|
||||
|
||||
func TestUseProxy(t *testing.T) {
|
||||
cfg := &httpproxy.Config{
|
||||
NoProxy: "foobar.com, .barbaz.net",
|
||||
}
|
||||
for _, test := range UseProxyTests {
|
||||
if httpproxy.ExportUseProxy(cfg, test.host+":80") != test.match {
|
||||
t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidNoProxy(t *testing.T) {
|
||||
cfg := &httpproxy.Config{
|
||||
NoProxy: ":1",
|
||||
}
|
||||
ok := httpproxy.ExportUseProxy(cfg, "example.com:80") // should not panic
|
||||
if !ok {
|
||||
t.Errorf("useProxy unexpected return; got false; want true")
|
||||
}
|
||||
}
|
||||
2
vendor/golang.org/x/net/http2/ciphers.go
generated
vendored
2
vendor/golang.org/x/net/http2/ciphers.go
generated
vendored
@@ -5,7 +5,7 @@
|
||||
package http2
|
||||
|
||||
// A list of the possible cipher suite ids. Taken from
|
||||
// https://www.iana.org/assignments/tls-parameters/tls-parameters.txt
|
||||
// http://www.iana.org/assignments/tls-parameters/tls-parameters.txt
|
||||
|
||||
const (
|
||||
cipher_TLS_NULL_WITH_NULL_NULL uint16 = 0x0000
|
||||
|
||||
2
vendor/golang.org/x/net/http2/configure_transport.go
generated
vendored
2
vendor/golang.org/x/net/http2/configure_transport.go
generated
vendored
@@ -73,7 +73,7 @@ type noDialH2RoundTripper struct{ t *Transport }
|
||||
|
||||
func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
res, err := rt.t.RoundTrip(req)
|
||||
if isNoCachedConnError(err) {
|
||||
if err == ErrNoCachedConn {
|
||||
return nil, http.ErrSkipAltProtocol
|
||||
}
|
||||
return res, err
|
||||
|
||||
4
vendor/golang.org/x/net/http2/frame.go
generated
vendored
4
vendor/golang.org/x/net/http2/frame.go
generated
vendored
@@ -14,8 +14,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
const frameHeaderLen = 9
|
||||
@@ -1462,7 +1462,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
|
||||
if VerboseLogs && fr.logReads {
|
||||
fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
|
||||
}
|
||||
if !httpguts.ValidHeaderFieldValue(hf.Value) {
|
||||
if !httplex.ValidHeaderFieldValue(hf.Value) {
|
||||
invalid = headerFieldValueError(hf.Value)
|
||||
}
|
||||
isPseudo := strings.HasPrefix(hf.Name, ":")
|
||||
|
||||
1
vendor/golang.org/x/net/http2/go19_test.go
generated
vendored
1
vendor/golang.org/x/net/http2/go19_test.go
generated
vendored
@@ -46,6 +46,7 @@ func TestServerGracefulShutdown(t *testing.T) {
|
||||
wanth := [][2]string{
|
||||
{":status", "200"},
|
||||
{"x-foo", "bar"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", "0"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
|
||||
1
vendor/golang.org/x/net/http2/h2demo/.gitignore
generated
vendored
1
vendor/golang.org/x/net/http2/h2demo/.gitignore
generated
vendored
@@ -3,4 +3,3 @@ h2demo.linux
|
||||
client-id.dat
|
||||
client-secret.dat
|
||||
token.dat
|
||||
ca-certificates.crt
|
||||
|
||||
11
vendor/golang.org/x/net/http2/h2demo/Dockerfile
generated
vendored
11
vendor/golang.org/x/net/http2/h2demo/Dockerfile
generated
vendored
@@ -1,11 +0,0 @@
|
||||
# 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.
|
||||
|
||||
FROM scratch
|
||||
LABEL maintainer "golang-dev@googlegroups.com"
|
||||
|
||||
COPY ca-certificates.crt /etc/ssl/certs/
|
||||
COPY h2demo /
|
||||
ENTRYPOINT ["/h2demo", "-prod"]
|
||||
|
||||
134
vendor/golang.org/x/net/http2/h2demo/Dockerfile.0
generated
vendored
134
vendor/golang.org/x/net/http2/h2demo/Dockerfile.0
generated
vendored
@@ -1,134 +0,0 @@
|
||||
# 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.
|
||||
|
||||
FROM golang:1.9
|
||||
LABEL maintainer "golang-dev@googlegroups.com"
|
||||
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
# BEGIN deps (run `make update-deps` to update)
|
||||
|
||||
# Repo cloud.google.com/go at 1d0c2da (2018-01-30)
|
||||
ENV REV=1d0c2da40456a9b47f5376165f275424acc15c09
|
||||
RUN go get -d cloud.google.com/go/compute/metadata `#and 6 other pkgs` &&\
|
||||
(cd /go/src/cloud.google.com/go && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo github.com/golang/protobuf at 9255415 (2018-01-25)
|
||||
ENV REV=925541529c1fa6821df4e44ce2723319eb2be768
|
||||
RUN go get -d github.com/golang/protobuf/proto `#and 6 other pkgs` &&\
|
||||
(cd /go/src/github.com/golang/protobuf && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo github.com/googleapis/gax-go at 317e000 (2017-09-15)
|
||||
ENV REV=317e0006254c44a0ac427cc52a0e083ff0b9622f
|
||||
RUN go get -d github.com/googleapis/gax-go &&\
|
||||
(cd /go/src/github.com/googleapis/gax-go && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo go4.org at 034d17a (2017-05-25)
|
||||
ENV REV=034d17a462f7b2dcd1a4a73553ec5357ff6e6c6e
|
||||
RUN go get -d go4.org/syncutil/singleflight &&\
|
||||
(cd /go/src/go4.org && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo golang.org/x/build at 8aa9ee0 (2018-02-01)
|
||||
ENV REV=8aa9ee0e557fd49c14113e5ba106e13a5b455460
|
||||
RUN go get -d golang.org/x/build/autocertcache &&\
|
||||
(cd /go/src/golang.org/x/build && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo golang.org/x/crypto at 1875d0a (2018-01-27)
|
||||
ENV REV=1875d0a70c90e57f11972aefd42276df65e895b9
|
||||
RUN go get -d golang.org/x/crypto/acme `#and 2 other pkgs` &&\
|
||||
(cd /go/src/golang.org/x/crypto && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo golang.org/x/oauth2 at 30785a2 (2018-01-04)
|
||||
ENV REV=30785a2c434e431ef7c507b54617d6a951d5f2b4
|
||||
RUN go get -d golang.org/x/oauth2 `#and 5 other pkgs` &&\
|
||||
(cd /go/src/golang.org/x/oauth2 && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo golang.org/x/text at e19ae14 (2017-12-27)
|
||||
ENV REV=e19ae1496984b1c655b8044a65c0300a3c878dd3
|
||||
RUN go get -d golang.org/x/text/secure/bidirule `#and 4 other pkgs` &&\
|
||||
(cd /go/src/golang.org/x/text && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo google.golang.org/api at 7d0e2d3 (2018-01-30)
|
||||
ENV REV=7d0e2d350555821bef5a5b8aecf0d12cc1def633
|
||||
RUN go get -d google.golang.org/api/gensupport `#and 9 other pkgs` &&\
|
||||
(cd /go/src/google.golang.org/api && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo google.golang.org/genproto at 4eb30f4 (2018-01-25)
|
||||
ENV REV=4eb30f4778eed4c258ba66527a0d4f9ec8a36c45
|
||||
RUN go get -d google.golang.org/genproto/googleapis/api/annotations `#and 3 other pkgs` &&\
|
||||
(cd /go/src/google.golang.org/genproto && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Repo google.golang.org/grpc at 0bd008f (2018-01-25)
|
||||
ENV REV=0bd008f5fadb62d228f12b18d016709e8139a7af
|
||||
RUN go get -d google.golang.org/grpc `#and 23 other pkgs` &&\
|
||||
(cd /go/src/google.golang.org/grpc && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
|
||||
|
||||
# Optimization to speed up iterative development, not necessary for correctness:
|
||||
RUN go install cloud.google.com/go/compute/metadata \
|
||||
cloud.google.com/go/iam \
|
||||
cloud.google.com/go/internal \
|
||||
cloud.google.com/go/internal/optional \
|
||||
cloud.google.com/go/internal/version \
|
||||
cloud.google.com/go/storage \
|
||||
github.com/golang/protobuf/proto \
|
||||
github.com/golang/protobuf/protoc-gen-go/descriptor \
|
||||
github.com/golang/protobuf/ptypes \
|
||||
github.com/golang/protobuf/ptypes/any \
|
||||
github.com/golang/protobuf/ptypes/duration \
|
||||
github.com/golang/protobuf/ptypes/timestamp \
|
||||
github.com/googleapis/gax-go \
|
||||
go4.org/syncutil/singleflight \
|
||||
golang.org/x/build/autocertcache \
|
||||
golang.org/x/crypto/acme \
|
||||
golang.org/x/crypto/acme/autocert \
|
||||
golang.org/x/oauth2 \
|
||||
golang.org/x/oauth2/google \
|
||||
golang.org/x/oauth2/internal \
|
||||
golang.org/x/oauth2/jws \
|
||||
golang.org/x/oauth2/jwt \
|
||||
golang.org/x/text/secure/bidirule \
|
||||
golang.org/x/text/transform \
|
||||
golang.org/x/text/unicode/bidi \
|
||||
golang.org/x/text/unicode/norm \
|
||||
google.golang.org/api/gensupport \
|
||||
google.golang.org/api/googleapi \
|
||||
google.golang.org/api/googleapi/internal/uritemplates \
|
||||
google.golang.org/api/googleapi/transport \
|
||||
google.golang.org/api/internal \
|
||||
google.golang.org/api/iterator \
|
||||
google.golang.org/api/option \
|
||||
google.golang.org/api/storage/v1 \
|
||||
google.golang.org/api/transport/http \
|
||||
google.golang.org/genproto/googleapis/api/annotations \
|
||||
google.golang.org/genproto/googleapis/iam/v1 \
|
||||
google.golang.org/genproto/googleapis/rpc/status \
|
||||
google.golang.org/grpc \
|
||||
google.golang.org/grpc/balancer \
|
||||
google.golang.org/grpc/balancer/base \
|
||||
google.golang.org/grpc/balancer/roundrobin \
|
||||
google.golang.org/grpc/codes \
|
||||
google.golang.org/grpc/connectivity \
|
||||
google.golang.org/grpc/credentials \
|
||||
google.golang.org/grpc/encoding \
|
||||
google.golang.org/grpc/encoding/proto \
|
||||
google.golang.org/grpc/grpclb/grpc_lb_v1/messages \
|
||||
google.golang.org/grpc/grpclog \
|
||||
google.golang.org/grpc/internal \
|
||||
google.golang.org/grpc/keepalive \
|
||||
google.golang.org/grpc/metadata \
|
||||
google.golang.org/grpc/naming \
|
||||
google.golang.org/grpc/peer \
|
||||
google.golang.org/grpc/resolver \
|
||||
google.golang.org/grpc/resolver/dns \
|
||||
google.golang.org/grpc/resolver/passthrough \
|
||||
google.golang.org/grpc/stats \
|
||||
google.golang.org/grpc/status \
|
||||
google.golang.org/grpc/tap \
|
||||
google.golang.org/grpc/transport
|
||||
# END deps
|
||||
|
||||
COPY . /go/src/golang.org/x/net/
|
||||
|
||||
RUN go install -tags "h2demo netgo" -ldflags "-linkmode=external -extldflags '-static -pthread'" golang.org/x/net/http2/h2demo
|
||||
|
||||
59
vendor/golang.org/x/net/http2/h2demo/Makefile
generated
vendored
59
vendor/golang.org/x/net/http2/h2demo/Makefile
generated
vendored
@@ -1,55 +1,8 @@
|
||||
# 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.
|
||||
|
||||
MUTABLE_VERSION ?= latest
|
||||
VERSION ?= $(shell git rev-parse --short HEAD)
|
||||
|
||||
IMAGE_STAGING := gcr.io/go-dashboard-dev/h2demo
|
||||
IMAGE_PROD := gcr.io/symbolic-datum-552/h2demo
|
||||
|
||||
DOCKER_IMAGE_build0=build0/h2demo:latest
|
||||
DOCKER_CTR_build0=h2demo-build0
|
||||
|
||||
build0: *.go Dockerfile.0
|
||||
docker build --force-rm -f Dockerfile.0 --tag=$(DOCKER_IMAGE_build0) ../..
|
||||
|
||||
h2demo: build0
|
||||
docker create --name $(DOCKER_CTR_build0) $(DOCKER_IMAGE_build0)
|
||||
docker cp $(DOCKER_CTR_build0):/go/bin/$@ $@
|
||||
docker rm $(DOCKER_CTR_build0)
|
||||
|
||||
ca-certificates.crt:
|
||||
docker create --name $(DOCKER_CTR_build0) $(DOCKER_IMAGE_build0)
|
||||
docker cp $(DOCKER_CTR_build0):/etc/ssl/certs/$@ $@
|
||||
docker rm $(DOCKER_CTR_build0)
|
||||
|
||||
update-deps:
|
||||
go install golang.org/x/build/cmd/gitlock
|
||||
gitlock --update=Dockerfile.0 --ignore=golang.org/x/net --tags=h2demo golang.org/x/net/http2/h2demo
|
||||
|
||||
docker-prod: Dockerfile h2demo ca-certificates.crt
|
||||
docker build --force-rm --tag=$(IMAGE_PROD):$(VERSION) .
|
||||
docker tag $(IMAGE_PROD):$(VERSION) $(IMAGE_PROD):$(MUTABLE_VERSION)
|
||||
docker-staging: Dockerfile h2demo ca-certificates.crt
|
||||
docker build --force-rm --tag=$(IMAGE_STAGING):$(VERSION) .
|
||||
docker tag $(IMAGE_STAGING):$(VERSION) $(IMAGE_STAGING):$(MUTABLE_VERSION)
|
||||
|
||||
push-prod: docker-prod
|
||||
gcloud docker -- push $(IMAGE_PROD):$(MUTABLE_VERSION)
|
||||
gcloud docker -- push $(IMAGE_PROD):$(VERSION)
|
||||
push-staging: docker-staging
|
||||
gcloud docker -- push $(IMAGE_STAGING):$(MUTABLE_VERSION)
|
||||
gcloud docker -- push $(IMAGE_STAGING):$(VERSION)
|
||||
|
||||
deploy-prod: push-prod
|
||||
kubectl set image deployment/h2demo-deployment h2demo=$(IMAGE_PROD):$(VERSION)
|
||||
deploy-staging: push-staging
|
||||
kubectl set image deployment/h2demo-deployment h2demo=$(IMAGE_STAGING):$(VERSION)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) h2demo
|
||||
$(RM) ca-certificates.crt
|
||||
h2demo.linux: h2demo.go
|
||||
GOOS=linux go build --tags=h2demo -o h2demo.linux .
|
||||
|
||||
FORCE:
|
||||
|
||||
upload: FORCE
|
||||
go install golang.org/x/build/cmd/upload
|
||||
upload --verbose --osarch=linux-amd64 --tags=h2demo --file=go:golang.org/x/net/http2/h2demo --public http2-demo-server-tls/h2demo
|
||||
|
||||
28
vendor/golang.org/x/net/http2/h2demo/deployment-prod.yaml
generated
vendored
28
vendor/golang.org/x/net/http2/h2demo/deployment-prod.yaml
generated
vendored
@@ -1,28 +0,0 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: h2demo-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: h2demo
|
||||
annotations:
|
||||
container.seccomp.security.alpha.kubernetes.io/h2demo: docker/default
|
||||
container.apparmor.security.beta.kubernetes.io/h2demo: runtime/default
|
||||
spec:
|
||||
containers:
|
||||
- name: h2demo
|
||||
image: gcr.io/symbolic-datum-552/h2demo:latest
|
||||
imagePullPolicy: Always
|
||||
command: ["/h2demo", "-prod"]
|
||||
ports:
|
||||
- containerPort: 80
|
||||
- containerPort: 443
|
||||
resources:
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: "1Gi"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
33
vendor/golang.org/x/net/http2/h2demo/h2demo.go
generated
vendored
33
vendor/golang.org/x/net/http2/h2demo/h2demo.go
generated
vendored
@@ -8,7 +8,6 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
@@ -20,6 +19,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"runtime"
|
||||
@@ -28,9 +28,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
"go4.org/syncutil/singleflight"
|
||||
"golang.org/x/build/autocertcache"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
@@ -428,10 +426,19 @@ func httpHost() string {
|
||||
}
|
||||
}
|
||||
|
||||
func serveProdTLS(autocertManager *autocert.Manager) error {
|
||||
func serveProdTLS() error {
|
||||
const cacheDir = "/var/cache/autocert"
|
||||
if err := os.MkdirAll(cacheDir, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
m := autocert.Manager{
|
||||
Cache: autocert.DirCache(cacheDir),
|
||||
Prompt: autocert.AcceptTOS,
|
||||
HostPolicy: autocert.HostWhitelist("http2.golang.org"),
|
||||
}
|
||||
srv := &http.Server{
|
||||
TLSConfig: &tls.Config{
|
||||
GetCertificate: autocertManager.GetCertificate,
|
||||
GetCertificate: m.GetCertificate,
|
||||
},
|
||||
}
|
||||
http2.ConfigureServer(srv, &http2.Server{
|
||||
@@ -461,21 +468,9 @@ func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||
}
|
||||
|
||||
func serveProd() error {
|
||||
log.Printf("running in production mode")
|
||||
|
||||
storageClient, err := storage.NewClient(context.Background())
|
||||
if err != nil {
|
||||
log.Fatalf("storage.NewClient: %v", err)
|
||||
}
|
||||
autocertManager := &autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
HostPolicy: autocert.HostWhitelist("http2.golang.org"),
|
||||
Cache: autocertcache.NewGoogleCloudStorageCache(storageClient, "golang-h2demo-autocert"),
|
||||
}
|
||||
|
||||
errc := make(chan error, 2)
|
||||
go func() { errc <- http.ListenAndServe(":80", autocertManager.HTTPHandler(http.DefaultServeMux)) }()
|
||||
go func() { errc <- serveProdTLS(autocertManager) }()
|
||||
go func() { errc <- http.ListenAndServe(":80", nil) }()
|
||||
go func() { errc <- serveProdTLS() }()
|
||||
return <-errc
|
||||
}
|
||||
|
||||
|
||||
17
vendor/golang.org/x/net/http2/h2demo/service.yaml
generated
vendored
17
vendor/golang.org/x/net/http2/h2demo/service.yaml
generated
vendored
@@ -1,17 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: h2demo
|
||||
spec:
|
||||
externalTrafficPolicy: Local
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
name: http
|
||||
- port: 443
|
||||
targetPort: 443
|
||||
name: https
|
||||
selector:
|
||||
app: h2demo
|
||||
type: LoadBalancer
|
||||
loadBalancerIP: 130.211.116.44
|
||||
2
vendor/golang.org/x/net/http2/hpack/encode.go
generated
vendored
2
vendor/golang.org/x/net/http2/hpack/encode.go
generated
vendored
@@ -206,7 +206,7 @@ func appendVarInt(dst []byte, n byte, i uint64) []byte {
|
||||
}
|
||||
|
||||
// appendHpackString appends s, as encoded in "String Literal"
|
||||
// representation, to dst and returns the extended buffer.
|
||||
// representation, to dst and returns the the extended buffer.
|
||||
//
|
||||
// s will be encoded in Huffman codes only when it produces strictly
|
||||
// shorter byte string.
|
||||
|
||||
6
vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
6
vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
@@ -389,12 +389,6 @@ func (d *Decoder) callEmit(hf HeaderField) error {
|
||||
|
||||
// (same invariants and behavior as parseHeaderFieldRepr)
|
||||
func (d *Decoder) parseDynamicTableSizeUpdate() error {
|
||||
// RFC 7541, sec 4.2: This dynamic table size update MUST occur at the
|
||||
// beginning of the first header block following the change to the dynamic table size.
|
||||
if d.dynTab.size > 0 {
|
||||
return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
|
||||
}
|
||||
|
||||
buf := d.buf
|
||||
size, buf, err := readVarInt(5, buf)
|
||||
if err != nil {
|
||||
|
||||
19
vendor/golang.org/x/net/http2/hpack/hpack_test.go
generated
vendored
19
vendor/golang.org/x/net/http2/hpack/hpack_test.go
generated
vendored
@@ -720,22 +720,3 @@ func TestSaveBufLimit(t *testing.T) {
|
||||
t.Fatalf("Write error = %v; want ErrStringLength", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDynamicSizeUpdate(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
enc := NewEncoder(&buf)
|
||||
enc.SetMaxDynamicTableSize(255)
|
||||
enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
|
||||
|
||||
d := NewDecoder(4096, nil)
|
||||
_, err := d.DecodeFull(buf.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: got = %v", err)
|
||||
}
|
||||
|
||||
// must fail since the dynamic table update must be at the beginning
|
||||
_, err = d.DecodeFull(buf.Bytes())
|
||||
if err == nil {
|
||||
t.Fatalf("dynamic table size update not at the beginning of a header block")
|
||||
}
|
||||
}
|
||||
|
||||
8
vendor/golang.org/x/net/http2/http2.go
generated
vendored
8
vendor/golang.org/x/net/http2/http2.go
generated
vendored
@@ -29,7 +29,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -179,7 +179,7 @@ var (
|
||||
)
|
||||
|
||||
// validWireHeaderFieldName reports whether v is a valid header field
|
||||
// name (key). See httpguts.ValidHeaderName for the base rules.
|
||||
// name (key). See httplex.ValidHeaderName for the base rules.
|
||||
//
|
||||
// Further, http2 says:
|
||||
// "Just as in HTTP/1.x, header field names are strings of ASCII
|
||||
@@ -191,7 +191,7 @@ func validWireHeaderFieldName(v string) bool {
|
||||
return false
|
||||
}
|
||||
for _, r := range v {
|
||||
if !httpguts.IsTokenRune(r) {
|
||||
if !httplex.IsTokenRune(r) {
|
||||
return false
|
||||
}
|
||||
if 'A' <= r && r <= 'Z' {
|
||||
@@ -312,7 +312,7 @@ func mustUint31(v int32) uint32 {
|
||||
}
|
||||
|
||||
// bodyAllowedForStatus reports whether a given response status code
|
||||
// permits a body. See RFC 7230, section 3.3.
|
||||
// permits a body. See RFC 2616, section 4.4.
|
||||
func bodyAllowedForStatus(status int) bool {
|
||||
switch {
|
||||
case status >= 100 && status <= 199:
|
||||
|
||||
160
vendor/golang.org/x/net/http2/server.go
generated
vendored
160
vendor/golang.org/x/net/http2/server.go
generated
vendored
@@ -46,7 +46,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
)
|
||||
|
||||
@@ -221,15 +220,12 @@ func ConfigureServer(s *http.Server, conf *Server) error {
|
||||
} else if s.TLSConfig.CipherSuites != nil {
|
||||
// If they already provided a CipherSuite list, return
|
||||
// an error if it has a bad order or is missing
|
||||
// ECDHE_RSA_WITH_AES_128_GCM_SHA256 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
|
||||
// ECDHE_RSA_WITH_AES_128_GCM_SHA256.
|
||||
const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
haveRequired := false
|
||||
sawBad := false
|
||||
for i, cs := range s.TLSConfig.CipherSuites {
|
||||
switch cs {
|
||||
case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
// Alternative MTI cipher to not discourage ECDSA-only servers.
|
||||
// See http://golang.org/cl/30721 for further information.
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
|
||||
if cs == requiredCipher {
|
||||
haveRequired = true
|
||||
}
|
||||
if isBadCipher(cs) {
|
||||
@@ -239,7 +235,7 @@ func ConfigureServer(s *http.Server, conf *Server) error {
|
||||
}
|
||||
}
|
||||
if !haveRequired {
|
||||
return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher.")
|
||||
return fmt.Errorf("http2: TLSConfig.CipherSuites is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,7 +403,7 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
||||
// addresses during development.
|
||||
//
|
||||
// TODO: optionally enforce? Or enforce at the time we receive
|
||||
// a new request, and verify the ServerName matches the :authority?
|
||||
// a new request, and verify the the ServerName matches the :authority?
|
||||
// But that precludes proxy situations, perhaps.
|
||||
//
|
||||
// So for now, do nothing here again.
|
||||
@@ -653,7 +649,7 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) || err == errPrefaceTimeout {
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) {
|
||||
// Boring, expected errors.
|
||||
sc.vlogf(format, args...)
|
||||
} else {
|
||||
@@ -857,13 +853,8 @@ func (sc *serverConn) serve() {
|
||||
}
|
||||
}
|
||||
|
||||
// Start the shutdown timer after sending a GOAWAY. When sending GOAWAY
|
||||
// with no error code (graceful shutdown), don't start the timer until
|
||||
// all open streams have been completed.
|
||||
sentGoAway := sc.inGoAway && !sc.needToSendGoAway && !sc.writingFrame
|
||||
gracefulShutdownComplete := sc.goAwayCode == ErrCodeNo && sc.curOpenStreams() == 0
|
||||
if sentGoAway && sc.shutdownTimer == nil && (sc.goAwayCode != ErrCodeNo || gracefulShutdownComplete) {
|
||||
sc.shutDownIn(goAwayTimeout)
|
||||
if sc.inGoAway && sc.curOpenStreams() == 0 && !sc.needToSendGoAway && !sc.writingFrame {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -898,11 +889,8 @@ func (sc *serverConn) sendServeMsg(msg interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
var errPrefaceTimeout = errors.New("timeout waiting for client preface")
|
||||
|
||||
// readPreface reads the ClientPreface greeting from the peer or
|
||||
// returns errPrefaceTimeout on timeout, or an error if the greeting
|
||||
// is invalid.
|
||||
// readPreface reads the ClientPreface greeting from the peer
|
||||
// or returns an error on timeout or an invalid greeting.
|
||||
func (sc *serverConn) readPreface() error {
|
||||
errc := make(chan error, 1)
|
||||
go func() {
|
||||
@@ -920,7 +908,7 @@ func (sc *serverConn) readPreface() error {
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case <-timer.C:
|
||||
return errPrefaceTimeout
|
||||
return errors.New("timeout waiting for client preface")
|
||||
case err := <-errc:
|
||||
if err == nil {
|
||||
if VerboseLogs {
|
||||
@@ -1230,31 +1218,30 @@ func (sc *serverConn) startGracefulShutdown() {
|
||||
sc.shutdownOnce.Do(func() { sc.sendServeMsg(gracefulShutdownMsg) })
|
||||
}
|
||||
|
||||
// After sending GOAWAY, the connection will close after goAwayTimeout.
|
||||
// If we close the connection immediately after sending GOAWAY, there may
|
||||
// be unsent data in our kernel receive buffer, which will cause the kernel
|
||||
// to send a TCP RST on close() instead of a FIN. This RST will abort the
|
||||
// connection immediately, whether or not the client had received the GOAWAY.
|
||||
//
|
||||
// Ideally we should delay for at least 1 RTT + epsilon so the client has
|
||||
// a chance to read the GOAWAY and stop sending messages. Measuring RTT
|
||||
// is hard, so we approximate with 1 second. See golang.org/issue/18701.
|
||||
//
|
||||
// This is a var so it can be shorter in tests, where all requests uses the
|
||||
// loopback interface making the expected RTT very small.
|
||||
//
|
||||
// TODO: configurable?
|
||||
var goAwayTimeout = 1 * time.Second
|
||||
|
||||
func (sc *serverConn) startGracefulShutdownInternal() {
|
||||
sc.goAway(ErrCodeNo)
|
||||
sc.goAwayIn(ErrCodeNo, 0)
|
||||
}
|
||||
|
||||
func (sc *serverConn) goAway(code ErrCode) {
|
||||
sc.serveG.check()
|
||||
var forceCloseIn time.Duration
|
||||
if code != ErrCodeNo {
|
||||
forceCloseIn = 250 * time.Millisecond
|
||||
} else {
|
||||
// TODO: configurable
|
||||
forceCloseIn = 1 * time.Second
|
||||
}
|
||||
sc.goAwayIn(code, forceCloseIn)
|
||||
}
|
||||
|
||||
func (sc *serverConn) goAwayIn(code ErrCode, forceCloseIn time.Duration) {
|
||||
sc.serveG.check()
|
||||
if sc.inGoAway {
|
||||
return
|
||||
}
|
||||
if forceCloseIn != 0 {
|
||||
sc.shutDownIn(forceCloseIn)
|
||||
}
|
||||
sc.inGoAway = true
|
||||
sc.needToSendGoAway = true
|
||||
sc.goAwayCode = code
|
||||
@@ -1818,7 +1805,7 @@ func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
|
||||
if st.trailer != nil {
|
||||
for _, hf := range f.RegularFields() {
|
||||
key := sc.canonicalHeader(hf.Name)
|
||||
if !httpguts.ValidTrailerHeader(key) {
|
||||
if !ValidTrailerHeader(key) {
|
||||
// TODO: send more details to the peer somehow. But http2 has
|
||||
// no way to send debug data at a stream level. Discuss with
|
||||
// HTTP folk.
|
||||
@@ -2285,8 +2272,8 @@ func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) !=
|
||||
// written in the trailers at the end of the response.
|
||||
func (rws *responseWriterState) declareTrailer(k string) {
|
||||
k = http.CanonicalHeaderKey(k)
|
||||
if !httpguts.ValidTrailerHeader(k) {
|
||||
// Forbidden by RFC 7230, section 4.1.2.
|
||||
if !ValidTrailerHeader(k) {
|
||||
// Forbidden by RFC 2616 14.40.
|
||||
rws.conn.logf("ignoring invalid trailer %q", k)
|
||||
return
|
||||
}
|
||||
@@ -2309,7 +2296,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
||||
isHeadResp := rws.req.Method == "HEAD"
|
||||
if !rws.sentHeader {
|
||||
rws.sentHeader = true
|
||||
|
||||
var ctype, clen string
|
||||
if clen = rws.snapHeader.Get("Content-Length"); clen != "" {
|
||||
rws.snapHeader.Del("Content-Length")
|
||||
@@ -2323,33 +2309,10 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
||||
if clen == "" && rws.handlerDone && bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) {
|
||||
clen = strconv.Itoa(len(p))
|
||||
}
|
||||
|
||||
_, hasContentType := rws.snapHeader["Content-Type"]
|
||||
if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
|
||||
if cto := rws.snapHeader.Get("X-Content-Type-Options"); strings.EqualFold("nosniff", cto) {
|
||||
// nosniff is an explicit directive not to guess a content-type.
|
||||
// Content-sniffing is no less susceptible to polyglot attacks via
|
||||
// hosted content when done on the server.
|
||||
ctype = "application/octet-stream"
|
||||
rws.conn.logf("http2: WriteHeader called with X-Content-Type-Options:nosniff but no Content-Type")
|
||||
} else {
|
||||
ctype = http.DetectContentType(p)
|
||||
}
|
||||
if !hasContentType && bodyAllowedForStatus(rws.status) {
|
||||
ctype = http.DetectContentType(p)
|
||||
}
|
||||
|
||||
var noSniff bool
|
||||
if bodyAllowedForStatus(rws.status) && (rws.sentContentLen > 0 || len(p) > 0) {
|
||||
// If the content type triggers client-side sniffing on old browsers,
|
||||
// attach a X-Content-Type-Options header if not present (or explicitly nil).
|
||||
if _, ok := rws.snapHeader["X-Content-Type-Options"]; !ok {
|
||||
if hasContentType {
|
||||
noSniff = httpguts.SniffedContentType(rws.snapHeader.Get("Content-Type"))
|
||||
} else if ctype != "" {
|
||||
noSniff = httpguts.SniffedContentType(ctype)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var date string
|
||||
if _, ok := rws.snapHeader["Date"]; !ok {
|
||||
// TODO(bradfitz): be faster here, like net/http? measure.
|
||||
@@ -2368,7 +2331,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
||||
endStream: endStream,
|
||||
contentType: ctype,
|
||||
contentLength: clen,
|
||||
noSniff: noSniff,
|
||||
date: date,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -2432,7 +2394,7 @@ const TrailerPrefix = "Trailer:"
|
||||
// after the header has already been flushed. Because the Go
|
||||
// ResponseWriter interface has no way to set Trailers (only the
|
||||
// Header), and because we didn't want to expand the ResponseWriter
|
||||
// interface, and because nobody used trailers, and because RFC 7230
|
||||
// interface, and because nobody used trailers, and because RFC 2616
|
||||
// says you SHOULD (but not must) predeclare any trailers in the
|
||||
// header, the official ResponseWriter rules said trailers in Go must
|
||||
// be predeclared, and then we reuse the same ResponseWriter.Header()
|
||||
@@ -2516,24 +2478,6 @@ func (w *responseWriter) Header() http.Header {
|
||||
return rws.handlerHeader
|
||||
}
|
||||
|
||||
// checkWriteHeaderCode is a copy of net/http's checkWriteHeaderCode.
|
||||
func checkWriteHeaderCode(code int) {
|
||||
// Issue 22880: require valid WriteHeader status codes.
|
||||
// For now we only enforce that it's three digits.
|
||||
// In the future we might block things over 599 (600 and above aren't defined
|
||||
// at http://httpwg.org/specs/rfc7231.html#status.codes)
|
||||
// and we might block under 200 (once we have more mature 1xx support).
|
||||
// But for now any three digits.
|
||||
//
|
||||
// We used to send "HTTP/1.1 000 0" on the wire in responses but there's
|
||||
// no equivalent bogus thing we can realistically send in HTTP/2,
|
||||
// so we'll consistently panic instead and help people find their bugs
|
||||
// early. (We can't return an error from WriteHeader even if we wanted to.)
|
||||
if code < 100 || code > 999 {
|
||||
panic(fmt.Sprintf("invalid WriteHeader code %v", code))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *responseWriter) WriteHeader(code int) {
|
||||
rws := w.rws
|
||||
if rws == nil {
|
||||
@@ -2544,7 +2488,6 @@ func (w *responseWriter) WriteHeader(code int) {
|
||||
|
||||
func (rws *responseWriterState) writeHeader(code int) {
|
||||
if !rws.wroteHeader {
|
||||
checkWriteHeaderCode(code)
|
||||
rws.wroteHeader = true
|
||||
rws.status = code
|
||||
if len(rws.handlerHeader) > 0 {
|
||||
@@ -2816,7 +2759,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
|
||||
}
|
||||
|
||||
// foreachHeaderElement splits v according to the "#rule" construction
|
||||
// in RFC 7230 section 7 and calls fn for each non-empty element.
|
||||
// in RFC 2616 section 2.1 and calls fn for each non-empty element.
|
||||
func foreachHeaderElement(v string, fn func(string)) {
|
||||
v = textproto.TrimString(v)
|
||||
if v == "" {
|
||||
@@ -2864,6 +2807,41 @@ func new400Handler(err error) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// ValidTrailerHeader reports whether name is a valid header field name to appear
|
||||
// in trailers.
|
||||
// See: http://tools.ietf.org/html/rfc7230#section-4.1.2
|
||||
func ValidTrailerHeader(name string) bool {
|
||||
name = http.CanonicalHeaderKey(name)
|
||||
if strings.HasPrefix(name, "If-") || badTrailer[name] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var badTrailer = map[string]bool{
|
||||
"Authorization": true,
|
||||
"Cache-Control": true,
|
||||
"Connection": true,
|
||||
"Content-Encoding": true,
|
||||
"Content-Length": true,
|
||||
"Content-Range": true,
|
||||
"Content-Type": true,
|
||||
"Expect": true,
|
||||
"Host": true,
|
||||
"Keep-Alive": true,
|
||||
"Max-Forwards": true,
|
||||
"Pragma": true,
|
||||
"Proxy-Authenticate": true,
|
||||
"Proxy-Authorization": true,
|
||||
"Proxy-Connection": true,
|
||||
"Range": true,
|
||||
"Realm": true,
|
||||
"Te": true,
|
||||
"Trailer": true,
|
||||
"Transfer-Encoding": true,
|
||||
"Www-Authenticate": true,
|
||||
}
|
||||
|
||||
// h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
|
||||
// disabled. See comments on h1ServerShutdownChan above for why
|
||||
// the code is written this way.
|
||||
|
||||
67
vendor/golang.org/x/net/http2/server_test.go
generated
vendored
67
vendor/golang.org/x/net/http2/server_test.go
generated
vendored
@@ -68,7 +68,6 @@ type serverTester struct {
|
||||
|
||||
func init() {
|
||||
testHookOnPanicMu = new(sync.Mutex)
|
||||
goAwayTimeout = 25 * time.Millisecond
|
||||
}
|
||||
|
||||
func resetHooks() {
|
||||
@@ -1718,6 +1717,7 @@ func TestServer_Response_NoData_Header_FooBar(t *testing.T) {
|
||||
wanth := [][2]string{
|
||||
{":status", "200"},
|
||||
{"foo-bar", "some-value"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", "0"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
@@ -1760,42 +1760,6 @@ func TestServer_Response_Data_Sniff_DoesntOverride(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_Response_Nosniff_WithoutContentType(t *testing.T) {
|
||||
const msg = "<html>this is HTML."
|
||||
testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(200)
|
||||
io.WriteString(w, msg)
|
||||
return nil
|
||||
}, func(st *serverTester) {
|
||||
getSlash(st)
|
||||
hf := st.wantHeaders()
|
||||
if hf.StreamEnded() {
|
||||
t.Fatal("don't want END_STREAM, expecting data")
|
||||
}
|
||||
if !hf.HeadersEnded() {
|
||||
t.Fatal("want END_HEADERS flag")
|
||||
}
|
||||
goth := st.decodeHeader(hf.HeaderBlockFragment())
|
||||
wanth := [][2]string{
|
||||
{":status", "200"},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
{"content-type", "application/octet-stream"},
|
||||
{"content-length", strconv.Itoa(len(msg))},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
t.Errorf("Got headers %v; want %v", goth, wanth)
|
||||
}
|
||||
df := st.wantData()
|
||||
if !df.StreamEnded() {
|
||||
t.Error("expected DATA to have END_STREAM flag")
|
||||
}
|
||||
if got := string(df.Data()); got != msg {
|
||||
t.Errorf("got DATA %q; want %q", got, msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_Response_TransferEncoding_chunked(t *testing.T) {
|
||||
const msg = "hi"
|
||||
testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
|
||||
@@ -1810,7 +1774,6 @@ func TestServer_Response_TransferEncoding_chunked(t *testing.T) {
|
||||
{":status", "200"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", strconv.Itoa(len(msg))},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
t.Errorf("Got headers %v; want %v", goth, wanth)
|
||||
@@ -1999,7 +1962,6 @@ func TestServer_Response_LargeWrite(t *testing.T) {
|
||||
wanth := [][2]string{
|
||||
{":status", "200"},
|
||||
{"content-type", "text/plain; charset=utf-8"}, // sniffed
|
||||
{"x-content-type-options", "nosniff"},
|
||||
// and no content-length
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
@@ -2214,7 +2176,6 @@ func TestServer_Response_Automatic100Continue(t *testing.T) {
|
||||
{":status", "200"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", strconv.Itoa(len(reply))},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
t.Errorf("Got headers %v; want %v", goth, wanth)
|
||||
@@ -2916,9 +2877,9 @@ func testServerWritesTrailers(t *testing.T, withFlush bool) {
|
||||
w.Header().Set("Trailer:post-header-trailer2", "hi2")
|
||||
w.Header().Set("Trailer:Range", "invalid")
|
||||
w.Header().Set("Trailer:Foo\x01Bogus", "invalid")
|
||||
w.Header().Set("Transfer-Encoding", "should not be included; Forbidden by RFC 7230 4.1.2")
|
||||
w.Header().Set("Content-Length", "should not be included; Forbidden by RFC 7230 4.1.2")
|
||||
w.Header().Set("Trailer", "should not be included; Forbidden by RFC 7230 4.1.2")
|
||||
w.Header().Set("Transfer-Encoding", "should not be included; Forbidden by RFC 2616 14.40")
|
||||
w.Header().Set("Content-Length", "should not be included; Forbidden by RFC 2616 14.40")
|
||||
w.Header().Set("Trailer", "should not be included; Forbidden by RFC 2616 14.40")
|
||||
return nil
|
||||
}, func(st *serverTester) {
|
||||
getSlash(st)
|
||||
@@ -2938,7 +2899,6 @@ func testServerWritesTrailers(t *testing.T, withFlush bool) {
|
||||
{"trailer", "Transfer-Encoding, Content-Length, Trailer"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", "5"},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth)
|
||||
@@ -2992,6 +2952,7 @@ func TestServerDoesntWriteInvalidHeaders(t *testing.T) {
|
||||
wanth := [][2]string{
|
||||
{":status", "200"},
|
||||
{"ok1", "x"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", "0"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
@@ -3011,7 +2972,7 @@ func BenchmarkServerGets(b *testing.B) {
|
||||
defer st.Close()
|
||||
st.greet()
|
||||
|
||||
// Give the server quota to reply. (plus it has the 64KB)
|
||||
// Give the server quota to reply. (plus it has the the 64KB)
|
||||
if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -3049,7 +3010,7 @@ func BenchmarkServerPosts(b *testing.B) {
|
||||
defer st.Close()
|
||||
st.greet()
|
||||
|
||||
// Give the server quota to reply. (plus it has the 64KB)
|
||||
// Give the server quota to reply. (plus it has the the 64KB)
|
||||
if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -3227,18 +3188,12 @@ func TestConfigureServer(t *testing.T) {
|
||||
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "just the alternative required cipher suite",
|
||||
tlsConfig: &tls.Config{
|
||||
CipherSuites: []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "missing required cipher suite",
|
||||
tlsConfig: &tls.Config{
|
||||
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
|
||||
},
|
||||
wantErr: "is missing an HTTP/2-required AES_128_GCM_SHA256 cipher.",
|
||||
wantErr: "is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
},
|
||||
{
|
||||
name: "required after bad",
|
||||
@@ -3304,6 +3259,7 @@ func TestServerNoAutoContentLengthOnHead(t *testing.T) {
|
||||
headers := st.decodeHeader(h.HeaderBlockFragment())
|
||||
want := [][2]string{
|
||||
{":status", "200"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
}
|
||||
if !reflect.DeepEqual(headers, want) {
|
||||
t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
|
||||
@@ -3330,7 +3286,6 @@ func TestServerNoDuplicateContentType(t *testing.T) {
|
||||
{":status", "200"},
|
||||
{"content-type", ""},
|
||||
{"content-length", "41"},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
}
|
||||
if !reflect.DeepEqual(headers, want) {
|
||||
t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
|
||||
@@ -3357,7 +3312,7 @@ func BenchmarkServer_GetRequest(b *testing.B) {
|
||||
defer st.Close()
|
||||
|
||||
st.greet()
|
||||
// Give the server quota to reply. (plus it has the 64KB)
|
||||
// Give the server quota to reply. (plus it has the the 64KB)
|
||||
if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -3388,7 +3343,7 @@ func BenchmarkServer_PostRequest(b *testing.B) {
|
||||
})
|
||||
defer st.Close()
|
||||
st.greet()
|
||||
// Give the server quota to reply. (plus it has the 64KB)
|
||||
// Give the server quota to reply. (plus it has the the 64KB)
|
||||
if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
371
vendor/golang.org/x/net/http2/transport.go
generated
vendored
371
vendor/golang.org/x/net/http2/transport.go
generated
vendored
@@ -27,9 +27,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/idna"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -87,7 +87,7 @@ type Transport struct {
|
||||
|
||||
// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
|
||||
// send in the initial settings frame. It is how many bytes
|
||||
// of response headers are allowed. Unlike the http2 spec, zero here
|
||||
// of response headers are allow. Unlike the http2 spec, zero here
|
||||
// means to use a default limit (currently 10MB). If you actually
|
||||
// want to advertise an ulimited value to the peer, Transport
|
||||
// interprets the highest possible value here (0xffffffff or 1<<32-1)
|
||||
@@ -172,10 +172,9 @@ type ClientConn struct {
|
||||
fr *Framer
|
||||
lastActive time.Time
|
||||
// Settings from peer: (also guarded by mu)
|
||||
maxFrameSize uint32
|
||||
maxConcurrentStreams uint32
|
||||
peerMaxHeaderListSize uint64
|
||||
initialWindowSize uint32
|
||||
maxFrameSize uint32
|
||||
maxConcurrentStreams uint32
|
||||
initialWindowSize uint32
|
||||
|
||||
hbuf bytes.Buffer // HPACK encoder writes into this
|
||||
henc *hpack.Encoder
|
||||
@@ -274,13 +273,6 @@ func (cs *clientStream) checkResetOrDone() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *clientStream) getStartedWrite() bool {
|
||||
cc := cs.cc
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
return cs.startedWrite
|
||||
}
|
||||
|
||||
func (cs *clientStream) abortRequestBodyWrite(err error) {
|
||||
if err == nil {
|
||||
panic("nil error")
|
||||
@@ -306,26 +298,7 @@ func (sew stickyErrWriter) Write(p []byte) (n int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// noCachedConnError is the concrete type of ErrNoCachedConn, which
|
||||
// needs to be detected by net/http regardless of whether it's its
|
||||
// bundled version (in h2_bundle.go with a rewritten type name) or
|
||||
// from a user's x/net/http2. As such, as it has a unique method name
|
||||
// (IsHTTP2NoCachedConnError) that net/http sniffs for via func
|
||||
// isNoCachedConnError.
|
||||
type noCachedConnError struct{}
|
||||
|
||||
func (noCachedConnError) IsHTTP2NoCachedConnError() {}
|
||||
func (noCachedConnError) Error() string { return "http2: no cached connection was available" }
|
||||
|
||||
// isNoCachedConnError reports whether err is of type noCachedConnError
|
||||
// or its equivalent renamed type in net/http2's h2_bundle.go. Both types
|
||||
// may coexist in the same running program.
|
||||
func isNoCachedConnError(err error) bool {
|
||||
_, ok := err.(interface{ IsHTTP2NoCachedConnError() })
|
||||
return ok
|
||||
}
|
||||
|
||||
var ErrNoCachedConn error = noCachedConnError{}
|
||||
var ErrNoCachedConn = errors.New("http2: no cached connection was available")
|
||||
|
||||
// RoundTripOpt are options for the Transport.RoundTripOpt method.
|
||||
type RoundTripOpt struct {
|
||||
@@ -375,9 +348,14 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
|
||||
return nil, err
|
||||
}
|
||||
traceGotConn(req, cc)
|
||||
res, gotErrAfterReqBodyWrite, err := cc.roundTrip(req)
|
||||
res, err := cc.RoundTrip(req)
|
||||
if err != nil && retry <= 6 {
|
||||
if req, err = shouldRetryRequest(req, err, gotErrAfterReqBodyWrite); err == nil {
|
||||
afterBodyWrite := false
|
||||
if e, ok := err.(afterReqBodyWriteError); ok {
|
||||
err = e
|
||||
afterBodyWrite = true
|
||||
}
|
||||
if req, err = shouldRetryRequest(req, err, afterBodyWrite); err == nil {
|
||||
// After the first retry, do exponential backoff with 10% jitter.
|
||||
if retry == 0 {
|
||||
continue
|
||||
@@ -415,6 +393,16 @@ var (
|
||||
errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY")
|
||||
)
|
||||
|
||||
// afterReqBodyWriteError is a wrapper around errors returned by ClientConn.RoundTrip.
|
||||
// It is used to signal that err happened after part of Request.Body was sent to the server.
|
||||
type afterReqBodyWriteError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e afterReqBodyWriteError) Error() string {
|
||||
return e.err.Error() + "; some request body already written"
|
||||
}
|
||||
|
||||
// shouldRetryRequest is called by RoundTrip when a request fails to get
|
||||
// response headers. It is always called with a non-nil error.
|
||||
// It returns either a request to retry (either the same request, or a
|
||||
@@ -531,18 +519,17 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
|
||||
func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
|
||||
cc := &ClientConn{
|
||||
t: t,
|
||||
tconn: c,
|
||||
readerDone: make(chan struct{}),
|
||||
nextStreamID: 1,
|
||||
maxFrameSize: 16 << 10, // spec default
|
||||
initialWindowSize: 65535, // spec default
|
||||
maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough.
|
||||
peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead.
|
||||
streams: make(map[uint32]*clientStream),
|
||||
singleUse: singleUse,
|
||||
wantSettingsAck: true,
|
||||
pings: make(map[[8]byte]chan struct{}),
|
||||
t: t,
|
||||
tconn: c,
|
||||
readerDone: make(chan struct{}),
|
||||
nextStreamID: 1,
|
||||
maxFrameSize: 16 << 10, // spec default
|
||||
initialWindowSize: 65535, // spec default
|
||||
maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough.
|
||||
streams: make(map[uint32]*clientStream),
|
||||
singleUse: singleUse,
|
||||
wantSettingsAck: true,
|
||||
pings: make(map[[8]byte]chan struct{}),
|
||||
}
|
||||
if d := t.idleConnTimeout(); d != 0 {
|
||||
cc.idleTimeout = d
|
||||
@@ -567,10 +554,6 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
|
||||
// henc in response to SETTINGS frames?
|
||||
cc.henc = hpack.NewEncoder(&cc.hbuf)
|
||||
|
||||
if t.AllowHTTP {
|
||||
cc.nextStreamID = 3
|
||||
}
|
||||
|
||||
if cs, ok := c.(connectionStater); ok {
|
||||
state := cs.ConnectionState()
|
||||
cc.tlsState = &state
|
||||
@@ -767,13 +750,8 @@ func actualContentLength(req *http.Request) int64 {
|
||||
}
|
||||
|
||||
func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
resp, _, err := cc.roundTrip(req)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAfterReqBodyWrite bool, err error) {
|
||||
if err := checkConnHeaders(req); err != nil {
|
||||
return nil, false, err
|
||||
return nil, err
|
||||
}
|
||||
if cc.idleTimer != nil {
|
||||
cc.idleTimer.Stop()
|
||||
@@ -781,14 +759,14 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
|
||||
trailers, err := commaSeparatedTrailers(req)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
return nil, err
|
||||
}
|
||||
hasTrailers := trailers != ""
|
||||
|
||||
cc.mu.Lock()
|
||||
if err := cc.awaitOpenSlotForRequest(req); err != nil {
|
||||
cc.mu.Unlock()
|
||||
return nil, false, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
body := req.Body
|
||||
@@ -822,7 +800,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen)
|
||||
if err != nil {
|
||||
cc.mu.Unlock()
|
||||
return nil, false, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs := cc.newStream()
|
||||
@@ -834,7 +812,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
|
||||
cc.wmu.Lock()
|
||||
endStream := !hasBody && !hasTrailers
|
||||
werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
|
||||
werr := cc.writeHeaders(cs.ID, endStream, hdrs)
|
||||
cc.wmu.Unlock()
|
||||
traceWroteHeaders(cs.trace)
|
||||
cc.mu.Unlock()
|
||||
@@ -848,7 +826,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
// Don't bother sending a RST_STREAM (our write already failed;
|
||||
// no need to keep writing)
|
||||
traceWroteRequest(cs.trace, werr)
|
||||
return nil, false, werr
|
||||
return nil, werr
|
||||
}
|
||||
|
||||
var respHeaderTimer <-chan time.Time
|
||||
@@ -867,7 +845,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
bodyWritten := false
|
||||
ctx := reqContext(req)
|
||||
|
||||
handleReadLoopResponse := func(re resAndError) (*http.Response, bool, error) {
|
||||
handleReadLoopResponse := func(re resAndError) (*http.Response, error) {
|
||||
res := re.res
|
||||
if re.err != nil || res.StatusCode > 299 {
|
||||
// On error or status code 3xx, 4xx, 5xx, etc abort any
|
||||
@@ -883,12 +861,18 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWrite)
|
||||
}
|
||||
if re.err != nil {
|
||||
cc.mu.Lock()
|
||||
afterBodyWrite := cs.startedWrite
|
||||
cc.mu.Unlock()
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return nil, cs.getStartedWrite(), re.err
|
||||
if afterBodyWrite {
|
||||
return nil, afterReqBodyWriteError{re.err}
|
||||
}
|
||||
return nil, re.err
|
||||
}
|
||||
res.Request = req
|
||||
res.TLS = cc.tlsState
|
||||
return res, false, nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
for {
|
||||
@@ -903,7 +887,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel)
|
||||
}
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return nil, cs.getStartedWrite(), errTimeout
|
||||
return nil, errTimeout
|
||||
case <-ctx.Done():
|
||||
if !hasBody || bodyWritten {
|
||||
cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
|
||||
@@ -912,7 +896,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel)
|
||||
}
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return nil, cs.getStartedWrite(), ctx.Err()
|
||||
return nil, ctx.Err()
|
||||
case <-req.Cancel:
|
||||
if !hasBody || bodyWritten {
|
||||
cc.writeStreamReset(cs.ID, ErrCodeCancel, nil)
|
||||
@@ -921,12 +905,12 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel)
|
||||
}
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return nil, cs.getStartedWrite(), errRequestCanceled
|
||||
return nil, errRequestCanceled
|
||||
case <-cs.peerReset:
|
||||
// processResetStream already removed the
|
||||
// stream from the streams map; no need for
|
||||
// forgetStreamID.
|
||||
return nil, cs.getStartedWrite(), cs.resetErr
|
||||
return nil, cs.resetErr
|
||||
case err := <-bodyWriter.resc:
|
||||
// Prefer the read loop's response, if available. Issue 16102.
|
||||
select {
|
||||
@@ -935,7 +919,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
||||
default:
|
||||
}
|
||||
if err != nil {
|
||||
return nil, cs.getStartedWrite(), err
|
||||
return nil, err
|
||||
}
|
||||
bodyWritten = true
|
||||
if d := cc.responseHeaderTimeout(); d != 0 {
|
||||
@@ -955,9 +939,6 @@ func (cc *ClientConn) awaitOpenSlotForRequest(req *http.Request) error {
|
||||
for {
|
||||
cc.lastActive = time.Now()
|
||||
if cc.closed || !cc.canTakeNewRequestLocked() {
|
||||
if waitingForConn != nil {
|
||||
close(waitingForConn)
|
||||
}
|
||||
return errClientConnUnusable
|
||||
}
|
||||
if int64(len(cc.streams))+1 <= int64(cc.maxConcurrentStreams) {
|
||||
@@ -990,12 +971,13 @@ func (cc *ClientConn) awaitOpenSlotForRequest(req *http.Request) error {
|
||||
}
|
||||
|
||||
// requires cc.wmu be held
|
||||
func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, maxFrameSize int, hdrs []byte) error {
|
||||
func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, hdrs []byte) error {
|
||||
first := true // first frame written (HEADERS is first, then CONTINUATION)
|
||||
frameSize := int(cc.maxFrameSize)
|
||||
for len(hdrs) > 0 && cc.werr == nil {
|
||||
chunk := hdrs
|
||||
if len(chunk) > maxFrameSize {
|
||||
chunk = chunk[:maxFrameSize]
|
||||
if len(chunk) > frameSize {
|
||||
chunk = chunk[:frameSize]
|
||||
}
|
||||
hdrs = hdrs[len(chunk):]
|
||||
endHeaders := len(hdrs) == 0
|
||||
@@ -1103,26 +1085,17 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (
|
||||
var trls []byte
|
||||
if hasTrailers {
|
||||
cc.mu.Lock()
|
||||
trls, err = cc.encodeTrailers(req)
|
||||
cc.mu.Unlock()
|
||||
if err != nil {
|
||||
cc.writeStreamReset(cs.ID, ErrCodeInternal, err)
|
||||
cc.forgetStreamID(cs.ID)
|
||||
return err
|
||||
}
|
||||
defer cc.mu.Unlock()
|
||||
trls = cc.encodeTrailers(req)
|
||||
}
|
||||
|
||||
cc.mu.Lock()
|
||||
maxFrameSize := int(cc.maxFrameSize)
|
||||
cc.mu.Unlock()
|
||||
|
||||
cc.wmu.Lock()
|
||||
defer cc.wmu.Unlock()
|
||||
|
||||
// Two ways to send END_STREAM: either with trailers, or
|
||||
// with an empty DATA frame.
|
||||
if len(trls) > 0 {
|
||||
err = cc.writeHeaders(cs.ID, true, maxFrameSize, trls)
|
||||
err = cc.writeHeaders(cs.ID, true, trls)
|
||||
} else {
|
||||
err = cc.fr.WriteData(cs.ID, true, nil)
|
||||
}
|
||||
@@ -1181,7 +1154,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
||||
if host == "" {
|
||||
host = req.URL.Host
|
||||
}
|
||||
host, err := httpguts.PunycodeHostPort(host)
|
||||
host, err := httplex.PunycodeHostPort(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1206,96 +1179,72 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
||||
// potentially pollute our hpack state. (We want to be able to
|
||||
// continue to reuse the hpack encoder for future requests)
|
||||
for k, vv := range req.Header {
|
||||
if !httpguts.ValidHeaderFieldName(k) {
|
||||
if !httplex.ValidHeaderFieldName(k) {
|
||||
return nil, fmt.Errorf("invalid HTTP header name %q", k)
|
||||
}
|
||||
for _, v := range vv {
|
||||
if !httpguts.ValidHeaderFieldValue(v) {
|
||||
if !httplex.ValidHeaderFieldValue(v) {
|
||||
return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enumerateHeaders := func(f func(name, value string)) {
|
||||
// 8.1.2.3 Request Pseudo-Header Fields
|
||||
// The :path pseudo-header field includes the path and query parts of the
|
||||
// target URI (the path-absolute production and optionally a '?' character
|
||||
// followed by the query production (see Sections 3.3 and 3.4 of
|
||||
// [RFC3986]).
|
||||
f(":authority", host)
|
||||
f(":method", req.Method)
|
||||
if req.Method != "CONNECT" {
|
||||
f(":path", path)
|
||||
f(":scheme", req.URL.Scheme)
|
||||
}
|
||||
if trailers != "" {
|
||||
f("trailer", trailers)
|
||||
}
|
||||
|
||||
var didUA bool
|
||||
for k, vv := range req.Header {
|
||||
if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") {
|
||||
// Host is :authority, already sent.
|
||||
// Content-Length is automatic, set below.
|
||||
continue
|
||||
} else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") ||
|
||||
strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") ||
|
||||
strings.EqualFold(k, "keep-alive") {
|
||||
// Per 8.1.2.2 Connection-Specific Header
|
||||
// Fields, don't send connection-specific
|
||||
// fields. We have already checked if any
|
||||
// are error-worthy so just ignore the rest.
|
||||
continue
|
||||
} else if strings.EqualFold(k, "user-agent") {
|
||||
// Match Go's http1 behavior: at most one
|
||||
// User-Agent. If set to nil or empty string,
|
||||
// then omit it. Otherwise if not mentioned,
|
||||
// include the default (below).
|
||||
didUA = true
|
||||
if len(vv) < 1 {
|
||||
continue
|
||||
}
|
||||
vv = vv[:1]
|
||||
if vv[0] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for _, v := range vv {
|
||||
f(k, v)
|
||||
}
|
||||
}
|
||||
if shouldSendReqContentLength(req.Method, contentLength) {
|
||||
f("content-length", strconv.FormatInt(contentLength, 10))
|
||||
}
|
||||
if addGzipHeader {
|
||||
f("accept-encoding", "gzip")
|
||||
}
|
||||
if !didUA {
|
||||
f("user-agent", defaultUserAgent)
|
||||
}
|
||||
// 8.1.2.3 Request Pseudo-Header Fields
|
||||
// The :path pseudo-header field includes the path and query parts of the
|
||||
// target URI (the path-absolute production and optionally a '?' character
|
||||
// followed by the query production (see Sections 3.3 and 3.4 of
|
||||
// [RFC3986]).
|
||||
cc.writeHeader(":authority", host)
|
||||
cc.writeHeader(":method", req.Method)
|
||||
if req.Method != "CONNECT" {
|
||||
cc.writeHeader(":path", path)
|
||||
cc.writeHeader(":scheme", req.URL.Scheme)
|
||||
}
|
||||
if trailers != "" {
|
||||
cc.writeHeader("trailer", trailers)
|
||||
}
|
||||
|
||||
// Do a first pass over the headers counting bytes to ensure
|
||||
// we don't exceed cc.peerMaxHeaderListSize. This is done as a
|
||||
// separate pass before encoding the headers to prevent
|
||||
// modifying the hpack state.
|
||||
hlSize := uint64(0)
|
||||
enumerateHeaders(func(name, value string) {
|
||||
hf := hpack.HeaderField{Name: name, Value: value}
|
||||
hlSize += uint64(hf.Size())
|
||||
})
|
||||
|
||||
if hlSize > cc.peerMaxHeaderListSize {
|
||||
return nil, errRequestHeaderListSize
|
||||
var didUA bool
|
||||
for k, vv := range req.Header {
|
||||
lowKey := strings.ToLower(k)
|
||||
switch lowKey {
|
||||
case "host", "content-length":
|
||||
// Host is :authority, already sent.
|
||||
// Content-Length is automatic, set below.
|
||||
continue
|
||||
case "connection", "proxy-connection", "transfer-encoding", "upgrade", "keep-alive":
|
||||
// Per 8.1.2.2 Connection-Specific Header
|
||||
// Fields, don't send connection-specific
|
||||
// fields. We have already checked if any
|
||||
// are error-worthy so just ignore the rest.
|
||||
continue
|
||||
case "user-agent":
|
||||
// Match Go's http1 behavior: at most one
|
||||
// User-Agent. If set to nil or empty string,
|
||||
// then omit it. Otherwise if not mentioned,
|
||||
// include the default (below).
|
||||
didUA = true
|
||||
if len(vv) < 1 {
|
||||
continue
|
||||
}
|
||||
vv = vv[:1]
|
||||
if vv[0] == "" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
for _, v := range vv {
|
||||
cc.writeHeader(lowKey, v)
|
||||
}
|
||||
}
|
||||
if shouldSendReqContentLength(req.Method, contentLength) {
|
||||
cc.writeHeader("content-length", strconv.FormatInt(contentLength, 10))
|
||||
}
|
||||
if addGzipHeader {
|
||||
cc.writeHeader("accept-encoding", "gzip")
|
||||
}
|
||||
if !didUA {
|
||||
cc.writeHeader("user-agent", defaultUserAgent)
|
||||
}
|
||||
|
||||
// Header list size is ok. Write the headers.
|
||||
enumerateHeaders(func(name, value string) {
|
||||
cc.writeHeader(strings.ToLower(name), value)
|
||||
})
|
||||
|
||||
return cc.hbuf.Bytes(), nil
|
||||
}
|
||||
|
||||
@@ -1322,29 +1271,17 @@ func shouldSendReqContentLength(method string, contentLength int64) bool {
|
||||
}
|
||||
|
||||
// requires cc.mu be held.
|
||||
func (cc *ClientConn) encodeTrailers(req *http.Request) ([]byte, error) {
|
||||
func (cc *ClientConn) encodeTrailers(req *http.Request) []byte {
|
||||
cc.hbuf.Reset()
|
||||
|
||||
hlSize := uint64(0)
|
||||
for k, vv := range req.Trailer {
|
||||
for _, v := range vv {
|
||||
hf := hpack.HeaderField{Name: k, Value: v}
|
||||
hlSize += uint64(hf.Size())
|
||||
}
|
||||
}
|
||||
if hlSize > cc.peerMaxHeaderListSize {
|
||||
return nil, errRequestHeaderListSize
|
||||
}
|
||||
|
||||
for k, vv := range req.Trailer {
|
||||
// Transfer-Encoding, etc.. have already been filtered at the
|
||||
// Transfer-Encoding, etc.. have already been filter at the
|
||||
// start of RoundTrip
|
||||
lowKey := strings.ToLower(k)
|
||||
for _, v := range vv {
|
||||
cc.writeHeader(lowKey, v)
|
||||
}
|
||||
}
|
||||
return cc.hbuf.Bytes(), nil
|
||||
return cc.hbuf.Bytes()
|
||||
}
|
||||
|
||||
func (cc *ClientConn) writeHeader(name, value string) {
|
||||
@@ -1402,12 +1339,17 @@ func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream {
|
||||
// clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
|
||||
type clientConnReadLoop struct {
|
||||
cc *ClientConn
|
||||
activeRes map[uint32]*clientStream // keyed by streamID
|
||||
closeWhenIdle bool
|
||||
}
|
||||
|
||||
// readLoop runs in its own goroutine and reads and dispatches frames.
|
||||
func (cc *ClientConn) readLoop() {
|
||||
rl := &clientConnReadLoop{cc: cc}
|
||||
rl := &clientConnReadLoop{
|
||||
cc: cc,
|
||||
activeRes: make(map[uint32]*clientStream),
|
||||
}
|
||||
|
||||
defer rl.cleanup()
|
||||
cc.readerErr = rl.run()
|
||||
if ce, ok := cc.readerErr.(ConnectionError); ok {
|
||||
@@ -1462,8 +1404,10 @@ func (rl *clientConnReadLoop) cleanup() {
|
||||
} else if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
for _, cs := range rl.activeRes {
|
||||
cs.bufPipe.CloseWithError(err)
|
||||
}
|
||||
for _, cs := range cc.streams {
|
||||
cs.bufPipe.CloseWithError(err) // no-op if already closed
|
||||
select {
|
||||
case cs.resc <- resAndError{err: err}:
|
||||
default:
|
||||
@@ -1541,7 +1485,7 @@ func (rl *clientConnReadLoop) run() error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
if rl.closeWhenIdle && gotReply && maybeIdle {
|
||||
if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
|
||||
cc.closeIfIdle()
|
||||
}
|
||||
}
|
||||
@@ -1549,31 +1493,13 @@ func (rl *clientConnReadLoop) run() error {
|
||||
|
||||
func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error {
|
||||
cc := rl.cc
|
||||
cs := cc.streamByID(f.StreamID, false)
|
||||
cs := cc.streamByID(f.StreamID, f.StreamEnded())
|
||||
if cs == nil {
|
||||
// We'd get here if we canceled a request while the
|
||||
// server had its response still in flight. So if this
|
||||
// was just something we canceled, ignore it.
|
||||
return nil
|
||||
}
|
||||
if f.StreamEnded() {
|
||||
// Issue 20521: If the stream has ended, streamByID() causes
|
||||
// clientStream.done to be closed, which causes the request's bodyWriter
|
||||
// to be closed with an errStreamClosed, which may be received by
|
||||
// clientConn.RoundTrip before the result of processing these headers.
|
||||
// Deferring stream closure allows the header processing to occur first.
|
||||
// clientConn.RoundTrip may still receive the bodyWriter error first, but
|
||||
// the fix for issue 16102 prioritises any response.
|
||||
//
|
||||
// Issue 22413: If there is no request body, we should close the
|
||||
// stream before writing to cs.resc so that the stream is closed
|
||||
// immediately once RoundTrip returns.
|
||||
if cs.req.Body != nil {
|
||||
defer cc.forgetStreamID(f.StreamID)
|
||||
} else {
|
||||
cc.forgetStreamID(f.StreamID)
|
||||
}
|
||||
}
|
||||
if !cs.firstByte {
|
||||
if cs.trace != nil {
|
||||
// TODO(bradfitz): move first response byte earlier,
|
||||
@@ -1597,7 +1523,6 @@ func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error {
|
||||
}
|
||||
// Any other error type is a stream error.
|
||||
cs.cc.writeStreamReset(f.StreamID, ErrCodeProtocol, err)
|
||||
cc.forgetStreamID(cs.ID)
|
||||
cs.resc <- resAndError{err: err}
|
||||
return nil // return nil from process* funcs to keep conn alive
|
||||
}
|
||||
@@ -1605,6 +1530,9 @@ func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error {
|
||||
// (nil, nil) special case. See handleResponse docs.
|
||||
return nil
|
||||
}
|
||||
if res.Body != noBody {
|
||||
rl.activeRes[cs.ID] = cs
|
||||
}
|
||||
cs.resTrailer = &res.Trailer
|
||||
cs.resc <- resAndError{res: res}
|
||||
return nil
|
||||
@@ -1624,11 +1552,11 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
|
||||
|
||||
status := f.PseudoValue("status")
|
||||
if status == "" {
|
||||
return nil, errors.New("malformed response from server: missing status pseudo header")
|
||||
return nil, errors.New("missing status pseudo header")
|
||||
}
|
||||
statusCode, err := strconv.Atoi(status)
|
||||
if err != nil {
|
||||
return nil, errors.New("malformed response from server: malformed non-numeric status pseudo header")
|
||||
return nil, errors.New("malformed non-numeric status pseudo header")
|
||||
}
|
||||
|
||||
if statusCode == 100 {
|
||||
@@ -1861,23 +1789,7 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !cs.firstByte {
|
||||
cc.logf("protocol error: received DATA before a HEADERS frame")
|
||||
rl.endStreamError(cs, StreamError{
|
||||
StreamID: f.StreamID,
|
||||
Code: ErrCodeProtocol,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
if f.Length > 0 {
|
||||
if cs.req.Method == "HEAD" && len(data) > 0 {
|
||||
cc.logf("protocol error: received DATA on a HEAD request")
|
||||
rl.endStreamError(cs, StreamError{
|
||||
StreamID: f.StreamID,
|
||||
Code: ErrCodeProtocol,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
// Check connection-level flow control.
|
||||
cc.mu.Lock()
|
||||
if cs.inflow.available() >= int32(f.Length) {
|
||||
@@ -1939,10 +1851,11 @@ func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) {
|
||||
err = io.EOF
|
||||
code = cs.copyTrailers
|
||||
}
|
||||
cs.bufPipe.closeWithErrorAndCode(err, code)
|
||||
delete(rl.activeRes, cs.ID)
|
||||
if isConnectionCloseRequest(cs.req) {
|
||||
rl.closeWhenIdle = true
|
||||
}
|
||||
cs.bufPipe.closeWithErrorAndCode(err, code)
|
||||
|
||||
select {
|
||||
case cs.resc <- resAndError{err: err}:
|
||||
@@ -1990,8 +1903,6 @@ func (rl *clientConnReadLoop) processSettings(f *SettingsFrame) error {
|
||||
cc.maxFrameSize = s.Val
|
||||
case SettingMaxConcurrentStreams:
|
||||
cc.maxConcurrentStreams = s.Val
|
||||
case SettingMaxHeaderListSize:
|
||||
cc.peerMaxHeaderListSize = uint64(s.Val)
|
||||
case SettingInitialWindowSize:
|
||||
// Values above the maximum flow-control
|
||||
// window size of 2^31-1 MUST be treated as a
|
||||
@@ -2069,6 +1980,7 @@ func (rl *clientConnReadLoop) processResetStream(f *RSTStreamFrame) error {
|
||||
cs.bufPipe.CloseWithError(err)
|
||||
cs.cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl
|
||||
}
|
||||
delete(rl.activeRes, cs.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2157,7 +2069,6 @@ func (cc *ClientConn) writeStreamReset(streamID uint32, code ErrCode, err error)
|
||||
|
||||
var (
|
||||
errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit")
|
||||
errRequestHeaderListSize = errors.New("http2: request header list larger than peer's advertised limit")
|
||||
errPseudoTrailers = errors.New("http2: invalid pseudo header in trailers")
|
||||
)
|
||||
|
||||
@@ -2251,7 +2162,7 @@ func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s body
|
||||
}
|
||||
s.delay = t.expectContinueTimeout()
|
||||
if s.delay == 0 ||
|
||||
!httpguts.HeaderValuesContainsToken(
|
||||
!httplex.HeaderValuesContainsToken(
|
||||
cs.req.Header["Expect"],
|
||||
"100-continue") {
|
||||
return
|
||||
@@ -2306,5 +2217,5 @@ func (s bodyWriterState) scheduleBodyWrite() {
|
||||
// isConnectionCloseRequest reports whether req should use its own
|
||||
// connection for a single request and then close the connection.
|
||||
func isConnectionCloseRequest(req *http.Request) bool {
|
||||
return req.Close || httpguts.HeaderValuesContainsToken(req.Header["Connection"], "close")
|
||||
return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
|
||||
}
|
||||
|
||||
538
vendor/golang.org/x/net/http2/transport_test.go
generated
vendored
538
vendor/golang.org/x/net/http2/transport_test.go
generated
vendored
@@ -13,11 +13,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
@@ -145,10 +143,9 @@ func TestTransport(t *testing.T) {
|
||||
t.Errorf("Status = %q; want %q", g, w)
|
||||
}
|
||||
wantHeader := http.Header{
|
||||
"Content-Length": []string{"3"},
|
||||
"X-Content-Type-Options": []string{"nosniff"},
|
||||
"Content-Type": []string{"text/plain; charset=utf-8"},
|
||||
"Date": []string{"XXX"}, // see cleanDate
|
||||
"Content-Length": []string{"3"},
|
||||
"Content-Type": []string{"text/plain; charset=utf-8"},
|
||||
"Date": []string{"XXX"}, // see cleanDate
|
||||
}
|
||||
cleanDate(res)
|
||||
if !reflect.DeepEqual(res.Header, wantHeader) {
|
||||
@@ -1373,269 +1370,6 @@ func testInvalidTrailer(t *testing.T, trailers headerType, wantErr error, writeT
|
||||
ct.run()
|
||||
}
|
||||
|
||||
// headerListSize returns the HTTP2 header list size of h.
|
||||
// http://httpwg.org/specs/rfc7540.html#SETTINGS_MAX_HEADER_LIST_SIZE
|
||||
// http://httpwg.org/specs/rfc7540.html#MaxHeaderBlock
|
||||
func headerListSize(h http.Header) (size uint32) {
|
||||
for k, vv := range h {
|
||||
for _, v := range vv {
|
||||
hf := hpack.HeaderField{Name: k, Value: v}
|
||||
size += hf.Size()
|
||||
}
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// padHeaders adds data to an http.Header until headerListSize(h) ==
|
||||
// limit. Due to the way header list sizes are calculated, padHeaders
|
||||
// cannot add fewer than len("Pad-Headers") + 32 bytes to h, and will
|
||||
// call t.Fatal if asked to do so. PadHeaders first reserves enough
|
||||
// space for an empty "Pad-Headers" key, then adds as many copies of
|
||||
// filler as possible. Any remaining bytes necessary to push the
|
||||
// header list size up to limit are added to h["Pad-Headers"].
|
||||
func padHeaders(t *testing.T, h http.Header, limit uint64, filler string) {
|
||||
if limit > 0xffffffff {
|
||||
t.Fatalf("padHeaders: refusing to pad to more than 2^32-1 bytes. limit = %v", limit)
|
||||
}
|
||||
hf := hpack.HeaderField{Name: "Pad-Headers", Value: ""}
|
||||
minPadding := uint64(hf.Size())
|
||||
size := uint64(headerListSize(h))
|
||||
|
||||
minlimit := size + minPadding
|
||||
if limit < minlimit {
|
||||
t.Fatalf("padHeaders: limit %v < %v", limit, minlimit)
|
||||
}
|
||||
|
||||
// Use a fixed-width format for name so that fieldSize
|
||||
// remains constant.
|
||||
nameFmt := "Pad-Headers-%06d"
|
||||
hf = hpack.HeaderField{Name: fmt.Sprintf(nameFmt, 1), Value: filler}
|
||||
fieldSize := uint64(hf.Size())
|
||||
|
||||
// Add as many complete filler values as possible, leaving
|
||||
// room for at least one empty "Pad-Headers" key.
|
||||
limit = limit - minPadding
|
||||
for i := 0; size+fieldSize < limit; i++ {
|
||||
name := fmt.Sprintf(nameFmt, i)
|
||||
h.Add(name, filler)
|
||||
size += fieldSize
|
||||
}
|
||||
|
||||
// Add enough bytes to reach limit.
|
||||
remain := limit - size
|
||||
lastValue := strings.Repeat("*", int(remain))
|
||||
h.Add("Pad-Headers", lastValue)
|
||||
}
|
||||
|
||||
func TestPadHeaders(t *testing.T) {
|
||||
check := func(h http.Header, limit uint32, fillerLen int) {
|
||||
if h == nil {
|
||||
h = make(http.Header)
|
||||
}
|
||||
filler := strings.Repeat("f", fillerLen)
|
||||
padHeaders(t, h, uint64(limit), filler)
|
||||
gotSize := headerListSize(h)
|
||||
if gotSize != limit {
|
||||
t.Errorf("Got size = %v; want %v", gotSize, limit)
|
||||
}
|
||||
}
|
||||
// Try all possible combinations for small fillerLen and limit.
|
||||
hf := hpack.HeaderField{Name: "Pad-Headers", Value: ""}
|
||||
minLimit := hf.Size()
|
||||
for limit := minLimit; limit <= 128; limit++ {
|
||||
for fillerLen := 0; uint32(fillerLen) <= limit; fillerLen++ {
|
||||
check(nil, limit, fillerLen)
|
||||
}
|
||||
}
|
||||
|
||||
// Try a few tests with larger limits, plus cumulative
|
||||
// tests. Since these tests are cumulative, tests[i+1].limit
|
||||
// must be >= tests[i].limit + minLimit. See the comment on
|
||||
// padHeaders for more info on why the limit arg has this
|
||||
// restriction.
|
||||
tests := []struct {
|
||||
fillerLen int
|
||||
limit uint32
|
||||
}{
|
||||
{
|
||||
fillerLen: 64,
|
||||
limit: 1024,
|
||||
},
|
||||
{
|
||||
fillerLen: 1024,
|
||||
limit: 1286,
|
||||
},
|
||||
{
|
||||
fillerLen: 256,
|
||||
limit: 2048,
|
||||
},
|
||||
{
|
||||
fillerLen: 1024,
|
||||
limit: 10 * 1024,
|
||||
},
|
||||
{
|
||||
fillerLen: 1023,
|
||||
limit: 11 * 1024,
|
||||
},
|
||||
}
|
||||
h := make(http.Header)
|
||||
for _, tc := range tests {
|
||||
check(nil, tc.limit, tc.fillerLen)
|
||||
check(h, tc.limit, tc.fillerLen)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransportChecksRequestHeaderListSize(t *testing.T) {
|
||||
st := newServerTester(t,
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
// Consume body & force client to send
|
||||
// trailers before writing response.
|
||||
// ioutil.ReadAll returns non-nil err for
|
||||
// requests that attempt to send greater than
|
||||
// maxHeaderListSize bytes of trailers, since
|
||||
// those requests generate a stream reset.
|
||||
ioutil.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
},
|
||||
func(ts *httptest.Server) {
|
||||
ts.Config.MaxHeaderBytes = 16 << 10
|
||||
},
|
||||
optOnlyServer,
|
||||
optQuiet,
|
||||
)
|
||||
defer st.Close()
|
||||
|
||||
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
|
||||
defer tr.CloseIdleConnections()
|
||||
|
||||
checkRoundTrip := func(req *http.Request, wantErr error, desc string) {
|
||||
res, err := tr.RoundTrip(req)
|
||||
if err != wantErr {
|
||||
if res != nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
t.Errorf("%v: RoundTrip err = %v; want %v", desc, err, wantErr)
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
if res == nil {
|
||||
t.Errorf("%v: response nil; want non-nil.", desc)
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Errorf("%v: response status = %v; want %v", desc, res.StatusCode, http.StatusOK)
|
||||
}
|
||||
return
|
||||
}
|
||||
if res != nil {
|
||||
t.Errorf("%v: RoundTrip err = %v but response non-nil", desc, err)
|
||||
}
|
||||
}
|
||||
headerListSizeForRequest := func(req *http.Request) (size uint64) {
|
||||
contentLen := actualContentLength(req)
|
||||
trailers, err := commaSeparatedTrailers(req)
|
||||
if err != nil {
|
||||
t.Fatalf("headerListSizeForRequest: %v", err)
|
||||
}
|
||||
cc := &ClientConn{peerMaxHeaderListSize: 0xffffffffffffffff}
|
||||
cc.henc = hpack.NewEncoder(&cc.hbuf)
|
||||
cc.mu.Lock()
|
||||
hdrs, err := cc.encodeHeaders(req, true, trailers, contentLen)
|
||||
cc.mu.Unlock()
|
||||
if err != nil {
|
||||
t.Fatalf("headerListSizeForRequest: %v", err)
|
||||
}
|
||||
hpackDec := hpack.NewDecoder(initialHeaderTableSize, func(hf hpack.HeaderField) {
|
||||
size += uint64(hf.Size())
|
||||
})
|
||||
if len(hdrs) > 0 {
|
||||
if _, err := hpackDec.Write(hdrs); err != nil {
|
||||
t.Fatalf("headerListSizeForRequest: %v", err)
|
||||
}
|
||||
}
|
||||
return size
|
||||
}
|
||||
// Create a new Request for each test, rather than reusing the
|
||||
// same Request, to avoid a race when modifying req.Headers.
|
||||
// See https://github.com/golang/go/issues/21316
|
||||
newRequest := func() *http.Request {
|
||||
// Body must be non-nil to enable writing trailers.
|
||||
body := strings.NewReader("hello")
|
||||
req, err := http.NewRequest("POST", st.ts.URL, body)
|
||||
if err != nil {
|
||||
t.Fatalf("newRequest: NewRequest: %v", err)
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
// Make an arbitrary request to ensure we get the server's
|
||||
// settings frame and initialize peerMaxHeaderListSize.
|
||||
req := newRequest()
|
||||
checkRoundTrip(req, nil, "Initial request")
|
||||
|
||||
// Get the ClientConn associated with the request and validate
|
||||
// peerMaxHeaderListSize.
|
||||
addr := authorityAddr(req.URL.Scheme, req.URL.Host)
|
||||
cc, err := tr.connPool().GetClientConn(req, addr)
|
||||
if err != nil {
|
||||
t.Fatalf("GetClientConn: %v", err)
|
||||
}
|
||||
cc.mu.Lock()
|
||||
peerSize := cc.peerMaxHeaderListSize
|
||||
cc.mu.Unlock()
|
||||
st.scMu.Lock()
|
||||
wantSize := uint64(st.sc.maxHeaderListSize())
|
||||
st.scMu.Unlock()
|
||||
if peerSize != wantSize {
|
||||
t.Errorf("peerMaxHeaderListSize = %v; want %v", peerSize, wantSize)
|
||||
}
|
||||
|
||||
// Sanity check peerSize. (*serverConn) maxHeaderListSize adds
|
||||
// 320 bytes of padding.
|
||||
wantHeaderBytes := uint64(st.ts.Config.MaxHeaderBytes) + 320
|
||||
if peerSize != wantHeaderBytes {
|
||||
t.Errorf("peerMaxHeaderListSize = %v; want %v.", peerSize, wantHeaderBytes)
|
||||
}
|
||||
|
||||
// Pad headers & trailers, but stay under peerSize.
|
||||
req = newRequest()
|
||||
req.Header = make(http.Header)
|
||||
req.Trailer = make(http.Header)
|
||||
filler := strings.Repeat("*", 1024)
|
||||
padHeaders(t, req.Trailer, peerSize, filler)
|
||||
// cc.encodeHeaders adds some default headers to the request,
|
||||
// so we need to leave room for those.
|
||||
defaultBytes := headerListSizeForRequest(req)
|
||||
padHeaders(t, req.Header, peerSize-defaultBytes, filler)
|
||||
checkRoundTrip(req, nil, "Headers & Trailers under limit")
|
||||
|
||||
// Add enough header bytes to push us over peerSize.
|
||||
req = newRequest()
|
||||
req.Header = make(http.Header)
|
||||
padHeaders(t, req.Header, peerSize, filler)
|
||||
checkRoundTrip(req, errRequestHeaderListSize, "Headers over limit")
|
||||
|
||||
// Push trailers over the limit.
|
||||
req = newRequest()
|
||||
req.Trailer = make(http.Header)
|
||||
padHeaders(t, req.Trailer, peerSize+1, filler)
|
||||
checkRoundTrip(req, errRequestHeaderListSize, "Trailers over limit")
|
||||
|
||||
// Send headers with a single large value.
|
||||
req = newRequest()
|
||||
filler = strings.Repeat("*", int(peerSize))
|
||||
req.Header = make(http.Header)
|
||||
req.Header.Set("Big", filler)
|
||||
checkRoundTrip(req, errRequestHeaderListSize, "Single large header")
|
||||
|
||||
// Send trailers with a single large value.
|
||||
req = newRequest()
|
||||
req.Trailer = make(http.Header)
|
||||
req.Trailer.Set("Big", filler)
|
||||
checkRoundTrip(req, errRequestHeaderListSize, "Single large trailer")
|
||||
}
|
||||
|
||||
func TestTransportChecksResponseHeaderListSize(t *testing.T) {
|
||||
ct := newClientTester(t)
|
||||
ct.client = func() error {
|
||||
@@ -1694,7 +1428,7 @@ func TestTransportChecksResponseHeaderListSize(t *testing.T) {
|
||||
ct.run()
|
||||
}
|
||||
|
||||
// Test that the Transport returns a typed error from Response.Body.Read calls
|
||||
// Test that the the Transport returns a typed error from Response.Body.Read calls
|
||||
// when the server sends an error. (here we use a panic, since that should generate
|
||||
// a stream error, but others like cancel should be similar)
|
||||
func TestTransportBodyReadErrorType(t *testing.T) {
|
||||
@@ -2292,65 +2026,6 @@ func TestTransportReadHeadResponse(t *testing.T) {
|
||||
ct.run()
|
||||
}
|
||||
|
||||
func TestTransportReadHeadResponseWithBody(t *testing.T) {
|
||||
// This test use not valid response format.
|
||||
// Discarding logger output to not spam tests output.
|
||||
log.SetOutput(ioutil.Discard)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
|
||||
response := "redirecting to /elsewhere"
|
||||
ct := newClientTester(t)
|
||||
clientDone := make(chan struct{})
|
||||
ct.client = func() error {
|
||||
defer close(clientDone)
|
||||
req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil)
|
||||
res, err := ct.tr.RoundTrip(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.ContentLength != int64(len(response)) {
|
||||
return fmt.Errorf("Content-Length = %d; want %d", res.ContentLength, len(response))
|
||||
}
|
||||
slurp, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ReadAll: %v", err)
|
||||
}
|
||||
if len(slurp) > 0 {
|
||||
return fmt.Errorf("Unexpected non-empty ReadAll body: %q", slurp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ct.server = func() error {
|
||||
ct.greet()
|
||||
for {
|
||||
f, err := ct.fr.ReadFrame()
|
||||
if err != nil {
|
||||
t.Logf("ReadFrame: %v", err)
|
||||
return nil
|
||||
}
|
||||
hf, ok := f.(*HeadersFrame)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
enc := hpack.NewEncoder(&buf)
|
||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
|
||||
enc.WriteField(hpack.HeaderField{Name: "content-length", Value: strconv.Itoa(len(response))})
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: hf.StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: false,
|
||||
BlockFragment: buf.Bytes(),
|
||||
})
|
||||
ct.fr.WriteData(hf.StreamID, true, []byte(response))
|
||||
|
||||
<-clientDone
|
||||
return nil
|
||||
}
|
||||
}
|
||||
ct.run()
|
||||
}
|
||||
|
||||
type neverEnding byte
|
||||
|
||||
func (b neverEnding) Read(p []byte) (int, error) {
|
||||
@@ -2987,7 +2662,7 @@ func TestTransportRequestPathPseudo(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
cc := &ClientConn{peerMaxHeaderListSize: 0xffffffffffffffff}
|
||||
cc := &ClientConn{}
|
||||
cc.henc = hpack.NewEncoder(&cc.hbuf)
|
||||
cc.mu.Lock()
|
||||
hdrs, err := cc.encodeHeaders(tt.req, false, "", -1)
|
||||
@@ -3104,34 +2779,6 @@ func TestTransportCancelDataResponseRace(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 21316: It should be safe to reuse an http.Request after the
|
||||
// request has completed.
|
||||
func TestTransportNoRaceOnRequestObjectAfterRequestComplete(t *testing.T) {
|
||||
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
io.WriteString(w, "body")
|
||||
}, optOnlyServer)
|
||||
defer st.Close()
|
||||
|
||||
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
|
||||
defer tr.CloseIdleConnections()
|
||||
|
||||
req, _ := http.NewRequest("GET", st.ts.URL, nil)
|
||||
resp, err := tr.RoundTrip(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = io.Copy(ioutil.Discard, resp.Body); err != nil {
|
||||
t.Fatalf("error reading response body: %v", err)
|
||||
}
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
t.Fatalf("error closing response body: %v", err)
|
||||
}
|
||||
|
||||
// This access of req.Header should not race with code in the transport.
|
||||
req.Header = http.Header{}
|
||||
}
|
||||
|
||||
func TestTransportRetryAfterGOAWAY(t *testing.T) {
|
||||
var dialer struct {
|
||||
sync.Mutex
|
||||
@@ -3389,65 +3036,6 @@ func TestTransportRetryHasLimit(t *testing.T) {
|
||||
ct.run()
|
||||
}
|
||||
|
||||
func TestTransportResponseDataBeforeHeaders(t *testing.T) {
|
||||
// This test use not valid response format.
|
||||
// Discarding logger output to not spam tests output.
|
||||
log.SetOutput(ioutil.Discard)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
|
||||
ct := newClientTester(t)
|
||||
ct.client = func() error {
|
||||
defer ct.cc.(*net.TCPConn).CloseWrite()
|
||||
req := httptest.NewRequest("GET", "https://dummy.tld/", nil)
|
||||
// First request is normal to ensure the check is per stream and not per connection.
|
||||
_, err := ct.tr.RoundTrip(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("RoundTrip expected no error, got: %v", err)
|
||||
}
|
||||
// Second request returns a DATA frame with no HEADERS.
|
||||
resp, err := ct.tr.RoundTrip(req)
|
||||
if err == nil {
|
||||
return fmt.Errorf("RoundTrip expected error, got response: %+v", resp)
|
||||
}
|
||||
if err, ok := err.(StreamError); !ok || err.Code != ErrCodeProtocol {
|
||||
return fmt.Errorf("expected stream PROTOCOL_ERROR, got: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ct.server = func() error {
|
||||
ct.greet()
|
||||
for {
|
||||
f, err := ct.fr.ReadFrame()
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
switch f := f.(type) {
|
||||
case *WindowUpdateFrame, *SettingsFrame:
|
||||
case *HeadersFrame:
|
||||
switch f.StreamID {
|
||||
case 1:
|
||||
// Send a valid response to first request.
|
||||
var buf bytes.Buffer
|
||||
enc := hpack.NewEncoder(&buf)
|
||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: f.StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: true,
|
||||
BlockFragment: buf.Bytes(),
|
||||
})
|
||||
case 3:
|
||||
ct.fr.WriteData(f.StreamID, true, []byte("payload"))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("Unexpected client frame %v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
ct.run()
|
||||
}
|
||||
func TestTransportRequestsStallAtServerLimit(t *testing.T) {
|
||||
const maxConcurrent = 2
|
||||
|
||||
@@ -3730,119 +3318,3 @@ func TestTransportNoBodyMeansNoDATA(t *testing.T) {
|
||||
}
|
||||
ct.run()
|
||||
}
|
||||
|
||||
func benchSimpleRoundTrip(b *testing.B, nHeaders int) {
|
||||
defer disableGoroutineTracking()()
|
||||
b.ReportAllocs()
|
||||
st := newServerTester(b,
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
},
|
||||
optOnlyServer,
|
||||
optQuiet,
|
||||
)
|
||||
defer st.Close()
|
||||
|
||||
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
|
||||
defer tr.CloseIdleConnections()
|
||||
|
||||
req, err := http.NewRequest("GET", st.ts.URL, nil)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < nHeaders; i++ {
|
||||
name := fmt.Sprint("A-", i)
|
||||
req.Header.Set(name, "*")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
res, err := tr.RoundTrip(req)
|
||||
if err != nil {
|
||||
if res != nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
b.Fatalf("RoundTrip err = %v; want nil", err)
|
||||
}
|
||||
res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
b.Fatalf("Response code = %v; want %v", res.StatusCode, http.StatusOK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type infiniteReader struct{}
|
||||
|
||||
func (r infiniteReader) Read(b []byte) (int, error) {
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// Issue 20521: it is not an error to receive a response and end stream
|
||||
// from the server without the body being consumed.
|
||||
func TestTransportResponseAndResetWithoutConsumingBodyRace(t *testing.T) {
|
||||
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}, optOnlyServer)
|
||||
defer st.Close()
|
||||
|
||||
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
|
||||
defer tr.CloseIdleConnections()
|
||||
|
||||
// The request body needs to be big enough to trigger flow control.
|
||||
req, _ := http.NewRequest("PUT", st.ts.URL, infiniteReader{})
|
||||
res, err := tr.RoundTrip(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Fatalf("Response code = %v; want %v", res.StatusCode, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify transport doesn't crash when receiving bogus response lacking a :status header.
|
||||
// Issue 22880.
|
||||
func TestTransportHandlesInvalidStatuslessResponse(t *testing.T) {
|
||||
ct := newClientTester(t)
|
||||
ct.client = func() error {
|
||||
req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
|
||||
_, err := ct.tr.RoundTrip(req)
|
||||
const substr = "malformed response from server: missing status pseudo header"
|
||||
if !strings.Contains(fmt.Sprint(err), substr) {
|
||||
return fmt.Errorf("RoundTrip error = %v; want substring %q", err, substr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ct.server = func() error {
|
||||
ct.greet()
|
||||
var buf bytes.Buffer
|
||||
enc := hpack.NewEncoder(&buf)
|
||||
|
||||
for {
|
||||
f, err := ct.fr.ReadFrame()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch f := f.(type) {
|
||||
case *HeadersFrame:
|
||||
enc.WriteField(hpack.HeaderField{Name: "content-type", Value: "text/html"}) // no :status header
|
||||
ct.fr.WriteHeaders(HeadersFrameParam{
|
||||
StreamID: f.StreamID,
|
||||
EndHeaders: true,
|
||||
EndStream: false, // we'll send some DATA to try to crash the transport
|
||||
BlockFragment: buf.Bytes(),
|
||||
})
|
||||
ct.fr.WriteData(f.StreamID, true, []byte("payload"))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
ct.run()
|
||||
}
|
||||
|
||||
func BenchmarkClientRequestHeaders(b *testing.B) {
|
||||
b.Run(" 0 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 0) })
|
||||
b.Run(" 10 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 10) })
|
||||
b.Run(" 100 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 100) })
|
||||
b.Run("1000 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 1000) })
|
||||
}
|
||||
|
||||
15
vendor/golang.org/x/net/http2/write.go
generated
vendored
15
vendor/golang.org/x/net/http2/write.go
generated
vendored
@@ -10,9 +10,10 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
// writeFramer is implemented by any type that is used to write frames.
|
||||
@@ -89,7 +90,11 @@ type writeGoAway struct {
|
||||
|
||||
func (p *writeGoAway) writeFrame(ctx writeContext) error {
|
||||
err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
|
||||
ctx.Flush() // ignore error: we're hanging up on them anyway
|
||||
if p.code != 0 {
|
||||
ctx.Flush() // ignore error: we're hanging up on them anyway
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
ctx.CloseConn()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -186,7 +191,6 @@ type writeResHeaders struct {
|
||||
date string
|
||||
contentType string
|
||||
contentLength string
|
||||
noSniff bool
|
||||
}
|
||||
|
||||
func encKV(enc *hpack.Encoder, k, v string) {
|
||||
@@ -223,9 +227,6 @@ func (w *writeResHeaders) writeFrame(ctx writeContext) error {
|
||||
if w.contentLength != "" {
|
||||
encKV(enc, "content-length", w.contentLength)
|
||||
}
|
||||
if w.noSniff {
|
||||
encKV(enc, "x-content-type-options", "nosniff")
|
||||
}
|
||||
if w.date != "" {
|
||||
encKV(enc, "date", w.date)
|
||||
}
|
||||
@@ -354,7 +355,7 @@ func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
|
||||
}
|
||||
isTE := k == "transfer-encoding"
|
||||
for _, v := range vv {
|
||||
if !httpguts.ValidHeaderFieldValue(v) {
|
||||
if !httplex.ValidHeaderFieldValue(v) {
|
||||
// TODO: return an error? golang.org/issue/14048
|
||||
// For now just omit it.
|
||||
continue
|
||||
|
||||
274
vendor/golang.org/x/net/icmp/diag_test.go
generated
vendored
274
vendor/golang.org/x/net/icmp/diag_test.go
generated
vendored
@@ -1,274 +0,0 @@
|
||||
// Copyright 2014 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 icmp_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/internal/iana"
|
||||
"golang.org/x/net/internal/nettest"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
type diagTest struct {
|
||||
network, address string
|
||||
protocol int
|
||||
m icmp.Message
|
||||
}
|
||||
|
||||
func TestDiag(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("avoid external network")
|
||||
}
|
||||
|
||||
t.Run("Ping/NonPrivileged", func(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
case "linux":
|
||||
t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
|
||||
default:
|
||||
t.Logf("not supported on %s", runtime.GOOS)
|
||||
return
|
||||
}
|
||||
for i, dt := range []diagTest{
|
||||
{
|
||||
"udp4", "0.0.0.0", iana.ProtocolICMP,
|
||||
icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: os.Getpid() & 0xffff,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
"udp6", "::", iana.ProtocolIPv6ICMP,
|
||||
icmp.Message{
|
||||
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: os.Getpid() & 0xffff,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := doDiag(dt, i); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("Ping/Privileged", func(t *testing.T) {
|
||||
if m, ok := nettest.SupportsRawIPSocket(); !ok {
|
||||
t.Skip(m)
|
||||
}
|
||||
for i, dt := range []diagTest{
|
||||
{
|
||||
"ip4:icmp", "0.0.0.0", iana.ProtocolICMP,
|
||||
icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: os.Getpid() & 0xffff,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP,
|
||||
icmp.Message{
|
||||
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: os.Getpid() & 0xffff,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := doDiag(dt, i); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("Probe/Privileged", func(t *testing.T) {
|
||||
if m, ok := nettest.SupportsRawIPSocket(); !ok {
|
||||
t.Skip(m)
|
||||
}
|
||||
for i, dt := range []diagTest{
|
||||
{
|
||||
"ip4:icmp", "0.0.0.0", iana.ProtocolICMP,
|
||||
icmp.Message{
|
||||
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: os.Getpid() & 0xffff,
|
||||
Local: true,
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3, Type: 1,
|
||||
Name: "doesnotexist",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP,
|
||||
icmp.Message{
|
||||
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: os.Getpid() & 0xffff,
|
||||
Local: true,
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3, Type: 1,
|
||||
Name: "doesnotexist",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := doDiag(dt, i); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func doDiag(dt diagTest, seq int) error {
|
||||
c, err := icmp.ListenPacket(dt.network, dt.address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
dst, err := googleAddr(c, dt.protocol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dt.network != "udp6" && dt.protocol == iana.ProtocolIPv6ICMP {
|
||||
var f ipv6.ICMPFilter
|
||||
f.SetAll(true)
|
||||
f.Accept(ipv6.ICMPTypeDestinationUnreachable)
|
||||
f.Accept(ipv6.ICMPTypePacketTooBig)
|
||||
f.Accept(ipv6.ICMPTypeTimeExceeded)
|
||||
f.Accept(ipv6.ICMPTypeParameterProblem)
|
||||
f.Accept(ipv6.ICMPTypeEchoReply)
|
||||
f.Accept(ipv6.ICMPTypeExtendedEchoReply)
|
||||
if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
switch m := dt.m.Body.(type) {
|
||||
case *icmp.Echo:
|
||||
m.Seq = 1 << uint(seq)
|
||||
case *icmp.ExtendedEchoRequest:
|
||||
m.Seq = 1 << uint(seq)
|
||||
}
|
||||
wb, err := dt.m.Marshal(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n, err := c.WriteTo(wb, dst); err != nil {
|
||||
return err
|
||||
} else if n != len(wb) {
|
||||
return fmt.Errorf("got %v; want %v", n, len(wb))
|
||||
}
|
||||
|
||||
rb := make([]byte, 1500)
|
||||
if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
|
||||
return err
|
||||
}
|
||||
n, peer, err := c.ReadFrom(rb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rm, err := icmp.ParseMessage(dt.protocol, rb[:n])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case dt.m.Type == ipv4.ICMPTypeEcho && rm.Type == ipv4.ICMPTypeEchoReply:
|
||||
fallthrough
|
||||
case dt.m.Type == ipv6.ICMPTypeEchoRequest && rm.Type == ipv6.ICMPTypeEchoReply:
|
||||
fallthrough
|
||||
case dt.m.Type == ipv4.ICMPTypeExtendedEchoRequest && rm.Type == ipv4.ICMPTypeExtendedEchoReply:
|
||||
fallthrough
|
||||
case dt.m.Type == ipv6.ICMPTypeExtendedEchoRequest && rm.Type == ipv6.ICMPTypeExtendedEchoReply:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("got %+v from %v; want echo reply or extended echo reply", rm, peer)
|
||||
}
|
||||
}
|
||||
|
||||
func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) {
|
||||
host := "ipv4.google.com"
|
||||
if protocol == iana.ProtocolIPv6ICMP {
|
||||
host = "ipv6.google.com"
|
||||
}
|
||||
ips, err := net.LookupIP(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netaddr := func(ip net.IP) (net.Addr, error) {
|
||||
switch c.LocalAddr().(type) {
|
||||
case *net.UDPAddr:
|
||||
return &net.UDPAddr{IP: ip}, nil
|
||||
case *net.IPAddr:
|
||||
return &net.IPAddr{IP: ip}, nil
|
||||
default:
|
||||
return nil, errors.New("neither UDPAddr nor IPAddr")
|
||||
}
|
||||
}
|
||||
if len(ips) > 0 {
|
||||
return netaddr(ips[0])
|
||||
}
|
||||
return nil, errors.New("no A or AAAA record")
|
||||
}
|
||||
|
||||
func TestConcurrentNonPrivilegedListenPacket(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("avoid external network")
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
case "linux":
|
||||
t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
|
||||
default:
|
||||
t.Skipf("not supported on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
network, address := "udp4", "127.0.0.1"
|
||||
if !nettest.SupportsIPv4() {
|
||||
network, address = "udp6", "::1"
|
||||
}
|
||||
const N = 1000
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(N)
|
||||
for i := 0; i < N; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
c, err := icmp.ListenPacket(network, address)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
c.Close()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
8
vendor/golang.org/x/net/icmp/dstunreach.go
generated
vendored
8
vendor/golang.org/x/net/icmp/dstunreach.go
generated
vendored
@@ -16,24 +16,24 @@ func (p *DstUnreach) Len(proto int) int {
|
||||
if p == nil {
|
||||
return 0
|
||||
}
|
||||
l, _ := multipartMessageBodyDataLen(proto, true, p.Data, p.Extensions)
|
||||
l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions)
|
||||
return 4 + l
|
||||
}
|
||||
|
||||
// Marshal implements the Marshal method of MessageBody interface.
|
||||
func (p *DstUnreach) Marshal(proto int) ([]byte, error) {
|
||||
return marshalMultipartMessageBody(proto, true, p.Data, p.Extensions)
|
||||
return marshalMultipartMessageBody(proto, p.Data, p.Extensions)
|
||||
}
|
||||
|
||||
// parseDstUnreach parses b as an ICMP destination unreachable message
|
||||
// body.
|
||||
func parseDstUnreach(proto int, typ Type, b []byte) (MessageBody, error) {
|
||||
func parseDstUnreach(proto int, b []byte) (MessageBody, error) {
|
||||
if len(b) < 4 {
|
||||
return nil, errMessageTooShort
|
||||
}
|
||||
p := &DstUnreach{}
|
||||
var err error
|
||||
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, typ, b)
|
||||
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
114
vendor/golang.org/x/net/icmp/echo.go
generated
vendored
114
vendor/golang.org/x/net/icmp/echo.go
generated
vendored
@@ -31,7 +31,7 @@ func (p *Echo) Marshal(proto int) ([]byte, error) {
|
||||
}
|
||||
|
||||
// parseEcho parses b as an ICMP echo request or reply message body.
|
||||
func parseEcho(proto int, _ Type, b []byte) (MessageBody, error) {
|
||||
func parseEcho(proto int, b []byte) (MessageBody, error) {
|
||||
bodyLen := len(b)
|
||||
if bodyLen < 4 {
|
||||
return nil, errMessageTooShort
|
||||
@@ -43,115 +43,3 @@ func parseEcho(proto int, _ Type, b []byte) (MessageBody, error) {
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// An ExtendedEchoRequest represents an ICMP extended echo request
|
||||
// message body.
|
||||
type ExtendedEchoRequest struct {
|
||||
ID int // identifier
|
||||
Seq int // sequence number
|
||||
Local bool // must be true when identifying by name or index
|
||||
Extensions []Extension // extensions
|
||||
}
|
||||
|
||||
// Len implements the Len method of MessageBody interface.
|
||||
func (p *ExtendedEchoRequest) Len(proto int) int {
|
||||
if p == nil {
|
||||
return 0
|
||||
}
|
||||
l, _ := multipartMessageBodyDataLen(proto, false, nil, p.Extensions)
|
||||
return 4 + l
|
||||
}
|
||||
|
||||
// Marshal implements the Marshal method of MessageBody interface.
|
||||
func (p *ExtendedEchoRequest) Marshal(proto int) ([]byte, error) {
|
||||
b, err := marshalMultipartMessageBody(proto, false, nil, p.Extensions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bb := make([]byte, 4)
|
||||
binary.BigEndian.PutUint16(bb[:2], uint16(p.ID))
|
||||
bb[2] = byte(p.Seq)
|
||||
if p.Local {
|
||||
bb[3] |= 0x01
|
||||
}
|
||||
bb = append(bb, b...)
|
||||
return bb, nil
|
||||
}
|
||||
|
||||
// parseExtendedEchoRequest parses b as an ICMP extended echo request
|
||||
// message body.
|
||||
func parseExtendedEchoRequest(proto int, typ Type, b []byte) (MessageBody, error) {
|
||||
if len(b) < 4+4 {
|
||||
return nil, errMessageTooShort
|
||||
}
|
||||
p := &ExtendedEchoRequest{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(b[2])}
|
||||
if b[3]&0x01 != 0 {
|
||||
p.Local = true
|
||||
}
|
||||
var err error
|
||||
_, p.Extensions, err = parseMultipartMessageBody(proto, typ, b[4:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// An ExtendedEchoReply represents an ICMP extended echo reply message
|
||||
// body.
|
||||
type ExtendedEchoReply struct {
|
||||
ID int // identifier
|
||||
Seq int // sequence number
|
||||
State int // 3-bit state working together with Message.Code
|
||||
Active bool // probed interface is active
|
||||
IPv4 bool // probed interface runs IPv4
|
||||
IPv6 bool // probed interface runs IPv6
|
||||
}
|
||||
|
||||
// Len implements the Len method of MessageBody interface.
|
||||
func (p *ExtendedEchoReply) Len(proto int) int {
|
||||
if p == nil {
|
||||
return 0
|
||||
}
|
||||
return 4
|
||||
}
|
||||
|
||||
// Marshal implements the Marshal method of MessageBody interface.
|
||||
func (p *ExtendedEchoReply) Marshal(proto int) ([]byte, error) {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
|
||||
b[2] = byte(p.Seq)
|
||||
b[3] = byte(p.State<<5) & 0xe0
|
||||
if p.Active {
|
||||
b[3] |= 0x04
|
||||
}
|
||||
if p.IPv4 {
|
||||
b[3] |= 0x02
|
||||
}
|
||||
if p.IPv6 {
|
||||
b[3] |= 0x01
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// parseExtendedEchoReply parses b as an ICMP extended echo reply
|
||||
// message body.
|
||||
func parseExtendedEchoReply(proto int, _ Type, b []byte) (MessageBody, error) {
|
||||
if len(b) < 4 {
|
||||
return nil, errMessageTooShort
|
||||
}
|
||||
p := &ExtendedEchoReply{
|
||||
ID: int(binary.BigEndian.Uint16(b[:2])),
|
||||
Seq: int(b[2]),
|
||||
State: int(b[3]) >> 5,
|
||||
}
|
||||
if b[3]&0x04 != 0 {
|
||||
p.Active = true
|
||||
}
|
||||
if b[3]&0x02 != 0 {
|
||||
p.IPv4 = true
|
||||
}
|
||||
if b[3]&0x01 != 0 {
|
||||
p.IPv6 = true
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
43
vendor/golang.org/x/net/icmp/extension.go
generated
vendored
43
vendor/golang.org/x/net/icmp/extension.go
generated
vendored
@@ -4,12 +4,7 @@
|
||||
|
||||
package icmp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
import "encoding/binary"
|
||||
|
||||
// An Extension represents an ICMP extension.
|
||||
type Extension interface {
|
||||
@@ -43,7 +38,7 @@ func validExtensionHeader(b []byte) bool {
|
||||
// It will return a list of ICMP extensions and an adjusted length
|
||||
// attribute that represents the length of the padded original
|
||||
// datagram field. Otherwise, it returns an error.
|
||||
func parseExtensions(typ Type, b []byte, l int) ([]Extension, int, error) {
|
||||
func parseExtensions(b []byte, l int) ([]Extension, int, error) {
|
||||
// Still a lot of non-RFC 4884 compliant implementations are
|
||||
// out there. Set the length attribute l to 128 when it looks
|
||||
// inappropriate for backwards compatibility.
|
||||
@@ -53,27 +48,19 @@ func parseExtensions(typ Type, b []byte, l int) ([]Extension, int, error) {
|
||||
// header.
|
||||
//
|
||||
// See RFC 4884 for further information.
|
||||
switch typ {
|
||||
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
|
||||
if len(b) < 8 || !validExtensionHeader(b) {
|
||||
return nil, -1, errNoExtension
|
||||
}
|
||||
l = 0
|
||||
default:
|
||||
if 128 > l || l+8 > len(b) {
|
||||
l = 128
|
||||
}
|
||||
if l+8 > len(b) {
|
||||
if 128 > l || l+8 > len(b) {
|
||||
l = 128
|
||||
}
|
||||
if l+8 > len(b) {
|
||||
return nil, -1, errNoExtension
|
||||
}
|
||||
if !validExtensionHeader(b[l:]) {
|
||||
if l == 128 {
|
||||
return nil, -1, errNoExtension
|
||||
}
|
||||
l = 128
|
||||
if !validExtensionHeader(b[l:]) {
|
||||
if l == 128 {
|
||||
return nil, -1, errNoExtension
|
||||
}
|
||||
l = 128
|
||||
if !validExtensionHeader(b[l:]) {
|
||||
return nil, -1, errNoExtension
|
||||
}
|
||||
return nil, -1, errNoExtension
|
||||
}
|
||||
}
|
||||
var exts []Extension
|
||||
@@ -95,12 +82,6 @@ func parseExtensions(typ Type, b []byte, l int) ([]Extension, int, error) {
|
||||
return nil, -1, err
|
||||
}
|
||||
exts = append(exts, ext)
|
||||
case classInterfaceIdent:
|
||||
ext, err := parseInterfaceIdent(b[:ol])
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
exts = append(exts, ext)
|
||||
}
|
||||
b = b[ol:]
|
||||
}
|
||||
|
||||
514
vendor/golang.org/x/net/icmp/extension_test.go
generated
vendored
514
vendor/golang.org/x/net/icmp/extension_test.go
generated
vendored
@@ -5,327 +5,253 @@
|
||||
package icmp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/internal/iana"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
func TestMarshalAndParseExtension(t *testing.T) {
|
||||
fn := func(t *testing.T, proto int, typ Type, hdr, obj []byte, te Extension) error {
|
||||
b, err := te.Marshal(proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !reflect.DeepEqual(b, obj) {
|
||||
return fmt.Errorf("got %#v; want %#v", b, obj)
|
||||
}
|
||||
switch typ {
|
||||
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
|
||||
exts, l, err := parseExtensions(typ, append(hdr, obj...), 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if l != 0 {
|
||||
return fmt.Errorf("got %d; want 0", l)
|
||||
}
|
||||
if !reflect.DeepEqual(exts, []Extension{te}) {
|
||||
return fmt.Errorf("got %#v; want %#v", exts[0], te)
|
||||
}
|
||||
default:
|
||||
for i, wire := range []struct {
|
||||
data []byte // original datagram
|
||||
inlattr int // length of padded original datagram, a hint
|
||||
outlattr int // length of padded original datagram, a want
|
||||
err error
|
||||
}{
|
||||
{nil, 0, -1, errNoExtension},
|
||||
{make([]byte, 127), 128, -1, errNoExtension},
|
||||
|
||||
{make([]byte, 128), 127, -1, errNoExtension},
|
||||
{make([]byte, 128), 128, -1, errNoExtension},
|
||||
{make([]byte, 128), 129, -1, errNoExtension},
|
||||
|
||||
{append(make([]byte, 128), append(hdr, obj...)...), 127, 128, nil},
|
||||
{append(make([]byte, 128), append(hdr, obj...)...), 128, 128, nil},
|
||||
{append(make([]byte, 128), append(hdr, obj...)...), 129, 128, nil},
|
||||
|
||||
{append(make([]byte, 512), append(hdr, obj...)...), 511, -1, errNoExtension},
|
||||
{append(make([]byte, 512), append(hdr, obj...)...), 512, 512, nil},
|
||||
{append(make([]byte, 512), append(hdr, obj...)...), 513, -1, errNoExtension},
|
||||
} {
|
||||
exts, l, err := parseExtensions(typ, wire.data, wire.inlattr)
|
||||
if err != wire.err {
|
||||
return fmt.Errorf("#%d: got %v; want %v", i, err, wire.err)
|
||||
}
|
||||
if wire.err != nil {
|
||||
continue
|
||||
}
|
||||
if l != wire.outlattr {
|
||||
return fmt.Errorf("#%d: got %d; want %d", i, l, wire.outlattr)
|
||||
}
|
||||
if !reflect.DeepEqual(exts, []Extension{te}) {
|
||||
return fmt.Errorf("#%d: got %#v; want %#v", i, exts[0], te)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
t.Run("MPLSLabelStack", func(t *testing.T) {
|
||||
for _, et := range []struct {
|
||||
proto int
|
||||
typ Type
|
||||
hdr []byte
|
||||
obj []byte
|
||||
ext Extension
|
||||
}{
|
||||
// MPLS label stack with no label
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
typ: ipv4.ICMPTypeDestinationUnreachable,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x04, 0x01, 0x01,
|
||||
},
|
||||
ext: &MPLSLabelStack{
|
||||
Class: classMPLSLabelStack,
|
||||
Type: typeIncomingMPLSLabelStack,
|
||||
},
|
||||
var marshalAndParseExtensionTests = []struct {
|
||||
proto int
|
||||
hdr []byte
|
||||
obj []byte
|
||||
exts []Extension
|
||||
}{
|
||||
// MPLS label stack with no label
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x04, 0x01, 0x01,
|
||||
},
|
||||
exts: []Extension{
|
||||
&MPLSLabelStack{
|
||||
Class: classMPLSLabelStack,
|
||||
Type: typeIncomingMPLSLabelStack,
|
||||
},
|
||||
// MPLS label stack with a single label
|
||||
{
|
||||
proto: iana.ProtocolIPv6ICMP,
|
||||
typ: ipv6.ICMPTypeDestinationUnreachable,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x08, 0x01, 0x01,
|
||||
0x03, 0xe8, 0xe9, 0xff,
|
||||
},
|
||||
ext: &MPLSLabelStack{
|
||||
Class: classMPLSLabelStack,
|
||||
Type: typeIncomingMPLSLabelStack,
|
||||
Labels: []MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
// MPLS label stack with a single label
|
||||
{
|
||||
proto: iana.ProtocolIPv6ICMP,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x08, 0x01, 0x01,
|
||||
0x03, 0xe8, 0xe9, 0xff,
|
||||
},
|
||||
exts: []Extension{
|
||||
&MPLSLabelStack{
|
||||
Class: classMPLSLabelStack,
|
||||
Type: typeIncomingMPLSLabelStack,
|
||||
Labels: []MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
// MPLS label stack with multiple labels
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
typ: ipv4.ICMPTypeDestinationUnreachable,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x0c, 0x01, 0x01,
|
||||
0x03, 0xe8, 0xde, 0xfe,
|
||||
0x03, 0xe8, 0xe1, 0xff,
|
||||
},
|
||||
ext: &MPLSLabelStack{
|
||||
Class: classMPLSLabelStack,
|
||||
Type: typeIncomingMPLSLabelStack,
|
||||
Labels: []MPLSLabel{
|
||||
{
|
||||
Label: 16013,
|
||||
TC: 0x7,
|
||||
S: false,
|
||||
TTL: 254,
|
||||
},
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
// MPLS label stack with multiple labels
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x0c, 0x01, 0x01,
|
||||
0x03, 0xe8, 0xde, 0xfe,
|
||||
0x03, 0xe8, 0xe1, 0xff,
|
||||
},
|
||||
exts: []Extension{
|
||||
&MPLSLabelStack{
|
||||
Class: classMPLSLabelStack,
|
||||
Type: typeIncomingMPLSLabelStack,
|
||||
Labels: []MPLSLabel{
|
||||
{
|
||||
Label: 16013,
|
||||
TC: 0x7,
|
||||
S: false,
|
||||
TTL: 254,
|
||||
},
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("InterfaceInfo", func(t *testing.T) {
|
||||
for _, et := range []struct {
|
||||
proto int
|
||||
typ Type
|
||||
hdr []byte
|
||||
obj []byte
|
||||
ext Extension
|
||||
}{
|
||||
// Interface information with no attribute
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
typ: ipv4.ICMPTypeDestinationUnreachable,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x04, 0x02, 0x00,
|
||||
},
|
||||
ext: &InterfaceInfo{
|
||||
Class: classInterfaceInfo,
|
||||
},
|
||||
},
|
||||
},
|
||||
// Interface information with no attribute
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x04, 0x02, 0x00,
|
||||
},
|
||||
exts: []Extension{
|
||||
&InterfaceInfo{
|
||||
Class: classInterfaceInfo,
|
||||
},
|
||||
// Interface information with ifIndex and name
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
typ: ipv4.ICMPTypeDestinationUnreachable,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x10, 0x02, 0x0a,
|
||||
0x00, 0x00, 0x00, 0x10,
|
||||
0x08, byte('e'), byte('n'), byte('1'),
|
||||
byte('0'), byte('1'), 0x00, 0x00,
|
||||
},
|
||||
ext: &InterfaceInfo{
|
||||
Class: classInterfaceInfo,
|
||||
Type: 0x0a,
|
||||
Interface: &net.Interface{
|
||||
Index: 16,
|
||||
Name: "en101",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Interface information with ifIndex, IPAddr, name and MTU
|
||||
{
|
||||
proto: iana.ProtocolIPv6ICMP,
|
||||
typ: ipv6.ICMPTypeDestinationUnreachable,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x28, 0x02, 0x0f,
|
||||
0x00, 0x00, 0x00, 0x0f,
|
||||
0x00, 0x02, 0x00, 0x00,
|
||||
0xfe, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
0x08, byte('e'), byte('n'), byte('1'),
|
||||
byte('0'), byte('1'), 0x00, 0x00,
|
||||
0x00, 0x00, 0x20, 0x00,
|
||||
},
|
||||
ext: &InterfaceInfo{
|
||||
Class: classInterfaceInfo,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.ParseIP("fe80::1"),
|
||||
Zone: "en101",
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("InterfaceIdent", func(t *testing.T) {
|
||||
for _, et := range []struct {
|
||||
proto int
|
||||
typ Type
|
||||
hdr []byte
|
||||
obj []byte
|
||||
ext Extension
|
||||
}{
|
||||
// Interface identification by name
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
typ: ipv4.ICMPTypeExtendedEchoRequest,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x0c, 0x03, 0x01,
|
||||
byte('e'), byte('n'), byte('1'), byte('0'),
|
||||
byte('1'), 0x00, 0x00, 0x00,
|
||||
},
|
||||
ext: &InterfaceIdent{
|
||||
Class: classInterfaceIdent,
|
||||
Type: typeInterfaceByName,
|
||||
},
|
||||
},
|
||||
// Interface information with ifIndex and name
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x10, 0x02, 0x0a,
|
||||
0x00, 0x00, 0x00, 0x10,
|
||||
0x08, byte('e'), byte('n'), byte('1'),
|
||||
byte('0'), byte('1'), 0x00, 0x00,
|
||||
},
|
||||
exts: []Extension{
|
||||
&InterfaceInfo{
|
||||
Class: classInterfaceInfo,
|
||||
Type: 0x0a,
|
||||
Interface: &net.Interface{
|
||||
Index: 16,
|
||||
Name: "en101",
|
||||
},
|
||||
},
|
||||
// Interface identification by index
|
||||
{
|
||||
proto: iana.ProtocolIPv6ICMP,
|
||||
typ: ipv6.ICMPTypeExtendedEchoRequest,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
// Interface information with ifIndex, IPAddr, name and MTU
|
||||
{
|
||||
proto: iana.ProtocolIPv6ICMP,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x28, 0x02, 0x0f,
|
||||
0x00, 0x00, 0x00, 0x0f,
|
||||
0x00, 0x02, 0x00, 0x00,
|
||||
0xfe, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
0x08, byte('e'), byte('n'), byte('1'),
|
||||
byte('0'), byte('1'), 0x00, 0x00,
|
||||
0x00, 0x00, 0x20, 0x00,
|
||||
},
|
||||
exts: []Extension{
|
||||
&InterfaceInfo{
|
||||
Class: classInterfaceInfo,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x0c, 0x03, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x03, 0x8f,
|
||||
},
|
||||
ext: &InterfaceIdent{
|
||||
Class: classInterfaceIdent,
|
||||
Type: typeInterfaceByIndex,
|
||||
Index: 911,
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.ParseIP("fe80::1"),
|
||||
Zone: "en101",
|
||||
},
|
||||
},
|
||||
// Interface identification by address
|
||||
{
|
||||
proto: iana.ProtocolICMP,
|
||||
typ: ipv4.ICMPTypeExtendedEchoRequest,
|
||||
hdr: []byte{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
},
|
||||
obj: []byte{
|
||||
0x00, 0x10, 0x03, 0x03,
|
||||
byte(iana.AddrFamily48bitMAC >> 8), byte(iana.AddrFamily48bitMAC & 0x0f), 0x06, 0x00,
|
||||
0x01, 0x23, 0x45, 0x67,
|
||||
0x89, 0xab, 0x00, 0x00,
|
||||
},
|
||||
ext: &InterfaceIdent{
|
||||
Class: classInterfaceIdent,
|
||||
Type: typeInterfaceByAddress,
|
||||
AFI: iana.AddrFamily48bitMAC,
|
||||
Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
|
||||
t.Error(err)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMarshalAndParseExtension(t *testing.T) {
|
||||
for i, tt := range marshalAndParseExtensionTests {
|
||||
for j, ext := range tt.exts {
|
||||
var err error
|
||||
var b []byte
|
||||
switch ext := ext.(type) {
|
||||
case *MPLSLabelStack:
|
||||
b, err = ext.Marshal(tt.proto)
|
||||
if err != nil {
|
||||
t.Errorf("#%v/%v: %v", i, j, err)
|
||||
continue
|
||||
}
|
||||
case *InterfaceInfo:
|
||||
b, err = ext.Marshal(tt.proto)
|
||||
if err != nil {
|
||||
t.Errorf("#%v/%v: %v", i, j, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(b, tt.obj) {
|
||||
t.Errorf("#%v/%v: got %#v; want %#v", i, j, b, tt.obj)
|
||||
continue
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
for j, wire := range []struct {
|
||||
data []byte // original datagram
|
||||
inlattr int // length of padded original datagram, a hint
|
||||
outlattr int // length of padded original datagram, a want
|
||||
err error
|
||||
}{
|
||||
{nil, 0, -1, errNoExtension},
|
||||
{make([]byte, 127), 128, -1, errNoExtension},
|
||||
|
||||
{make([]byte, 128), 127, -1, errNoExtension},
|
||||
{make([]byte, 128), 128, -1, errNoExtension},
|
||||
{make([]byte, 128), 129, -1, errNoExtension},
|
||||
|
||||
{append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 127, 128, nil},
|
||||
{append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 128, 128, nil},
|
||||
{append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 129, 128, nil},
|
||||
|
||||
{append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 511, -1, errNoExtension},
|
||||
{append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 512, 512, nil},
|
||||
{append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 513, -1, errNoExtension},
|
||||
} {
|
||||
exts, l, err := parseExtensions(wire.data, wire.inlattr)
|
||||
if err != wire.err {
|
||||
t.Errorf("#%v/%v: got %v; want %v", i, j, err, wire.err)
|
||||
continue
|
||||
}
|
||||
if wire.err != nil {
|
||||
continue
|
||||
}
|
||||
if l != wire.outlattr {
|
||||
t.Errorf("#%v/%v: got %v; want %v", i, j, l, wire.outlattr)
|
||||
}
|
||||
if !reflect.DeepEqual(exts, tt.exts) {
|
||||
for j, ext := range exts {
|
||||
switch ext := ext.(type) {
|
||||
case *MPLSLabelStack:
|
||||
want := tt.exts[j].(*MPLSLabelStack)
|
||||
t.Errorf("#%v/%v: got %#v; want %#v", i, j, ext, want)
|
||||
case *InterfaceInfo:
|
||||
want := tt.exts[j].(*InterfaceInfo)
|
||||
t.Errorf("#%v/%v: got %#v; want %#v", i, j, ext, want)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var parseInterfaceNameTests = []struct {
|
||||
b []byte
|
||||
error
|
||||
}{
|
||||
{[]byte{0, 'e', 'n', '0'}, errInvalidExtension},
|
||||
{[]byte{4, 'e', 'n', '0'}, nil},
|
||||
{[]byte{7, 'e', 'n', '0', 0xff, 0xff, 0xff, 0xff}, errInvalidExtension},
|
||||
{[]byte{8, 'e', 'n', '0', 0xff, 0xff, 0xff}, errMessageTooShort},
|
||||
}
|
||||
|
||||
func TestParseInterfaceName(t *testing.T) {
|
||||
ifi := InterfaceInfo{Interface: &net.Interface{}}
|
||||
for i, tt := range []struct {
|
||||
b []byte
|
||||
error
|
||||
}{
|
||||
{[]byte{0, 'e', 'n', '0'}, errInvalidExtension},
|
||||
{[]byte{4, 'e', 'n', '0'}, nil},
|
||||
{[]byte{7, 'e', 'n', '0', 0xff, 0xff, 0xff, 0xff}, errInvalidExtension},
|
||||
{[]byte{8, 'e', 'n', '0', 0xff, 0xff, 0xff}, errMessageTooShort},
|
||||
} {
|
||||
for i, tt := range parseInterfaceNameTests {
|
||||
if _, err := ifi.parseName(tt.b); err != tt.error {
|
||||
t.Errorf("#%d: got %v; want %v", i, err, tt.error)
|
||||
}
|
||||
|
||||
100
vendor/golang.org/x/net/icmp/interface.go
generated
vendored
100
vendor/golang.org/x/net/icmp/interface.go
generated
vendored
@@ -14,6 +14,9 @@ import (
|
||||
|
||||
const (
|
||||
classInterfaceInfo = 2
|
||||
|
||||
afiIPv4 = 1
|
||||
afiIPv6 = 2
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -124,11 +127,11 @@ func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) {
|
||||
func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte {
|
||||
switch proto {
|
||||
case iana.ProtocolICMP:
|
||||
binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv4))
|
||||
binary.BigEndian.PutUint16(b[:2], uint16(afiIPv4))
|
||||
copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4())
|
||||
b = b[4+net.IPv4len:]
|
||||
case iana.ProtocolIPv6ICMP:
|
||||
binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv6))
|
||||
binary.BigEndian.PutUint16(b[:2], uint16(afiIPv6))
|
||||
copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16())
|
||||
b = b[4+net.IPv6len:]
|
||||
}
|
||||
@@ -142,14 +145,14 @@ func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) {
|
||||
afi := int(binary.BigEndian.Uint16(b[:2]))
|
||||
b = b[4:]
|
||||
switch afi {
|
||||
case iana.AddrFamilyIPv4:
|
||||
case afiIPv4:
|
||||
if len(b) < net.IPv4len {
|
||||
return nil, errMessageTooShort
|
||||
}
|
||||
ifi.Addr.IP = make(net.IP, net.IPv4len)
|
||||
copy(ifi.Addr.IP, b[:net.IPv4len])
|
||||
b = b[net.IPv4len:]
|
||||
case iana.AddrFamilyIPv6:
|
||||
case afiIPv6:
|
||||
if len(b) < net.IPv6len {
|
||||
return nil, errMessageTooShort
|
||||
}
|
||||
@@ -231,92 +234,3 @@ func parseInterfaceInfo(b []byte) (Extension, error) {
|
||||
}
|
||||
return ifi, nil
|
||||
}
|
||||
|
||||
const (
|
||||
classInterfaceIdent = 3
|
||||
typeInterfaceByName = 1
|
||||
typeInterfaceByIndex = 2
|
||||
typeInterfaceByAddress = 3
|
||||
)
|
||||
|
||||
// An InterfaceIdent represents interface identification.
|
||||
type InterfaceIdent struct {
|
||||
Class int // extension object class number
|
||||
Type int // extension object sub-type
|
||||
Name string // interface name
|
||||
Index int // interface index
|
||||
AFI int // address family identifier; see address family numbers in IANA registry
|
||||
Addr []byte // address
|
||||
}
|
||||
|
||||
// Len implements the Len method of Extension interface.
|
||||
func (ifi *InterfaceIdent) Len(_ int) int {
|
||||
switch ifi.Type {
|
||||
case typeInterfaceByName:
|
||||
l := len(ifi.Name)
|
||||
if l > 255 {
|
||||
l = 255
|
||||
}
|
||||
return 4 + (l+3)&^3
|
||||
case typeInterfaceByIndex:
|
||||
return 4 + 8
|
||||
case typeInterfaceByAddress:
|
||||
return 4 + 4 + (len(ifi.Addr)+3)&^3
|
||||
default:
|
||||
return 4
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal implements the Marshal method of Extension interface.
|
||||
func (ifi *InterfaceIdent) Marshal(proto int) ([]byte, error) {
|
||||
b := make([]byte, ifi.Len(proto))
|
||||
if err := ifi.marshal(proto, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (ifi *InterfaceIdent) marshal(proto int, b []byte) error {
|
||||
l := ifi.Len(proto)
|
||||
binary.BigEndian.PutUint16(b[:2], uint16(l))
|
||||
b[2], b[3] = classInterfaceIdent, byte(ifi.Type)
|
||||
switch ifi.Type {
|
||||
case typeInterfaceByName:
|
||||
copy(b[4:], ifi.Name)
|
||||
case typeInterfaceByIndex:
|
||||
binary.BigEndian.PutUint64(b[4:4+8], uint64(ifi.Index))
|
||||
case typeInterfaceByAddress:
|
||||
binary.BigEndian.PutUint16(b[4:4+2], uint16(ifi.AFI))
|
||||
b[4+2] = byte(len(ifi.Addr))
|
||||
copy(b[4+4:], ifi.Addr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseInterfaceIdent(b []byte) (Extension, error) {
|
||||
ifi := &InterfaceIdent{
|
||||
Class: int(b[2]),
|
||||
Type: int(b[3]),
|
||||
}
|
||||
switch ifi.Type {
|
||||
case typeInterfaceByName:
|
||||
ifi.Name = strings.Trim(string(b[4:]), string(0))
|
||||
case typeInterfaceByIndex:
|
||||
if len(b[4:]) < 8 {
|
||||
return nil, errInvalidExtension
|
||||
}
|
||||
ifi.Index = int(binary.BigEndian.Uint64(b[4 : 4+8]))
|
||||
case typeInterfaceByAddress:
|
||||
if len(b[4:]) < 4 {
|
||||
return nil, errInvalidExtension
|
||||
}
|
||||
ifi.AFI = int(binary.BigEndian.Uint16(b[4 : 4+2]))
|
||||
l := int(b[4+2])
|
||||
if len(b[4+4:]) < l {
|
||||
return nil, errInvalidExtension
|
||||
}
|
||||
ifi.Addr = make([]byte, l)
|
||||
copy(ifi.Addr, b[4+4:])
|
||||
}
|
||||
return ifi, nil
|
||||
}
|
||||
|
||||
118
vendor/golang.org/x/net/icmp/ipv4_test.go
generated
vendored
118
vendor/golang.org/x/net/icmp/ipv4_test.go
generated
vendored
@@ -15,61 +15,69 @@ import (
|
||||
"golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
type ipv4HeaderTest struct {
|
||||
wireHeaderFromKernel [ipv4.HeaderLen]byte
|
||||
wireHeaderFromTradBSDKernel [ipv4.HeaderLen]byte
|
||||
Header *ipv4.Header
|
||||
}
|
||||
|
||||
var ipv4HeaderLittleEndianTest = ipv4HeaderTest{
|
||||
// TODO(mikio): Add platform dependent wire header formats when
|
||||
// we support new platforms.
|
||||
wireHeaderFromKernel: [ipv4.HeaderLen]byte{
|
||||
0x45, 0x01, 0xbe, 0xef,
|
||||
0xca, 0xfe, 0x45, 0xdc,
|
||||
0xff, 0x01, 0xde, 0xad,
|
||||
172, 16, 254, 254,
|
||||
192, 168, 0, 1,
|
||||
},
|
||||
wireHeaderFromTradBSDKernel: [ipv4.HeaderLen]byte{
|
||||
0x45, 0x01, 0xef, 0xbe,
|
||||
0xca, 0xfe, 0x45, 0xdc,
|
||||
0xff, 0x01, 0xde, 0xad,
|
||||
172, 16, 254, 254,
|
||||
192, 168, 0, 1,
|
||||
},
|
||||
Header: &ipv4.Header{
|
||||
Version: ipv4.Version,
|
||||
Len: ipv4.HeaderLen,
|
||||
TOS: 1,
|
||||
TotalLen: 0xbeef,
|
||||
ID: 0xcafe,
|
||||
Flags: ipv4.DontFragment,
|
||||
FragOff: 1500,
|
||||
TTL: 255,
|
||||
Protocol: 1,
|
||||
Checksum: 0xdead,
|
||||
Src: net.IPv4(172, 16, 254, 254),
|
||||
Dst: net.IPv4(192, 168, 0, 1),
|
||||
},
|
||||
}
|
||||
|
||||
func TestParseIPv4Header(t *testing.T) {
|
||||
switch socket.NativeEndian {
|
||||
case binary.LittleEndian:
|
||||
t.Run("LittleEndian", func(t *testing.T) {
|
||||
// TODO(mikio): Add platform dependent wire
|
||||
// header formats when we support new
|
||||
// platforms.
|
||||
wireHeaderFromKernel := [ipv4.HeaderLen]byte{
|
||||
0x45, 0x01, 0xbe, 0xef,
|
||||
0xca, 0xfe, 0x45, 0xdc,
|
||||
0xff, 0x01, 0xde, 0xad,
|
||||
172, 16, 254, 254,
|
||||
192, 168, 0, 1,
|
||||
}
|
||||
wireHeaderFromTradBSDKernel := [ipv4.HeaderLen]byte{
|
||||
0x45, 0x01, 0xef, 0xbe,
|
||||
0xca, 0xfe, 0x45, 0xdc,
|
||||
0xff, 0x01, 0xde, 0xad,
|
||||
172, 16, 254, 254,
|
||||
192, 168, 0, 1,
|
||||
}
|
||||
th := &ipv4.Header{
|
||||
Version: ipv4.Version,
|
||||
Len: ipv4.HeaderLen,
|
||||
TOS: 1,
|
||||
TotalLen: 0xbeef,
|
||||
ID: 0xcafe,
|
||||
Flags: ipv4.DontFragment,
|
||||
FragOff: 1500,
|
||||
TTL: 255,
|
||||
Protocol: 1,
|
||||
Checksum: 0xdead,
|
||||
Src: net.IPv4(172, 16, 254, 254),
|
||||
Dst: net.IPv4(192, 168, 0, 1),
|
||||
}
|
||||
var wh []byte
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
wh = wireHeaderFromTradBSDKernel[:]
|
||||
case "freebsd":
|
||||
if freebsdVersion >= 1000000 {
|
||||
wh = wireHeaderFromKernel[:]
|
||||
} else {
|
||||
wh = wireHeaderFromTradBSDKernel[:]
|
||||
}
|
||||
default:
|
||||
wh = wireHeaderFromKernel[:]
|
||||
}
|
||||
h, err := ParseIPv4Header(wh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(h, th) {
|
||||
t.Fatalf("got %#v; want %#v", h, th)
|
||||
}
|
||||
})
|
||||
tt := &ipv4HeaderLittleEndianTest
|
||||
if socket.NativeEndian != binary.LittleEndian {
|
||||
t.Skip("no test for non-little endian machine yet")
|
||||
}
|
||||
|
||||
var wh []byte
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
wh = tt.wireHeaderFromTradBSDKernel[:]
|
||||
case "freebsd":
|
||||
if freebsdVersion >= 1000000 {
|
||||
wh = tt.wireHeaderFromKernel[:]
|
||||
} else {
|
||||
wh = tt.wireHeaderFromTradBSDKernel[:]
|
||||
}
|
||||
default:
|
||||
wh = tt.wireHeaderFromKernel[:]
|
||||
}
|
||||
h, err := ParseIPv4Header(wh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(h, tt.Header) {
|
||||
t.Fatalf("got %#v; want %#v", h, tt.Header)
|
||||
}
|
||||
}
|
||||
|
||||
17
vendor/golang.org/x/net/icmp/message.go
generated
vendored
17
vendor/golang.org/x/net/icmp/message.go
generated
vendored
@@ -11,7 +11,6 @@
|
||||
// ICMP extensions for MPLS are defined in RFC 4950.
|
||||
// ICMP extensions for interface and next-hop identification are
|
||||
// defined in RFC 5837.
|
||||
// PROBE: A utility for probing interfaces is defined in RFC 8335.
|
||||
package icmp // import "golang.org/x/net/icmp"
|
||||
|
||||
import (
|
||||
@@ -108,25 +107,21 @@ func (m *Message) Marshal(psh []byte) ([]byte, error) {
|
||||
return b[len(psh):], nil
|
||||
}
|
||||
|
||||
var parseFns = map[Type]func(int, Type, []byte) (MessageBody, error){
|
||||
var parseFns = map[Type]func(int, []byte) (MessageBody, error){
|
||||
ipv4.ICMPTypeDestinationUnreachable: parseDstUnreach,
|
||||
ipv4.ICMPTypeTimeExceeded: parseTimeExceeded,
|
||||
ipv4.ICMPTypeParameterProblem: parseParamProb,
|
||||
|
||||
ipv4.ICMPTypeEcho: parseEcho,
|
||||
ipv4.ICMPTypeEchoReply: parseEcho,
|
||||
ipv4.ICMPTypeExtendedEchoRequest: parseExtendedEchoRequest,
|
||||
ipv4.ICMPTypeExtendedEchoReply: parseExtendedEchoReply,
|
||||
ipv4.ICMPTypeEcho: parseEcho,
|
||||
ipv4.ICMPTypeEchoReply: parseEcho,
|
||||
|
||||
ipv6.ICMPTypeDestinationUnreachable: parseDstUnreach,
|
||||
ipv6.ICMPTypePacketTooBig: parsePacketTooBig,
|
||||
ipv6.ICMPTypeTimeExceeded: parseTimeExceeded,
|
||||
ipv6.ICMPTypeParameterProblem: parseParamProb,
|
||||
|
||||
ipv6.ICMPTypeEchoRequest: parseEcho,
|
||||
ipv6.ICMPTypeEchoReply: parseEcho,
|
||||
ipv6.ICMPTypeExtendedEchoRequest: parseExtendedEchoRequest,
|
||||
ipv6.ICMPTypeExtendedEchoReply: parseExtendedEchoReply,
|
||||
ipv6.ICMPTypeEchoRequest: parseEcho,
|
||||
ipv6.ICMPTypeEchoReply: parseEcho,
|
||||
}
|
||||
|
||||
// ParseMessage parses b as an ICMP message.
|
||||
@@ -148,7 +143,7 @@ func ParseMessage(proto int, b []byte) (*Message, error) {
|
||||
if fn, ok := parseFns[m.Type]; !ok {
|
||||
m.Body, err = parseDefaultMessageBody(proto, b[4:])
|
||||
} else {
|
||||
m.Body, err = fn(proto, m.Type, b[4:])
|
||||
m.Body, err = fn(proto, b[4:])
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
245
vendor/golang.org/x/net/icmp/message_test.go
generated
vendored
245
vendor/golang.org/x/net/icmp/message_test.go
generated
vendored
@@ -15,141 +15,120 @@ import (
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
func TestMarshalAndParseMessage(t *testing.T) {
|
||||
fn := func(t *testing.T, proto int, tms []icmp.Message) {
|
||||
var pshs [][]byte
|
||||
switch proto {
|
||||
case iana.ProtocolICMP:
|
||||
pshs = [][]byte{nil}
|
||||
case iana.ProtocolIPv6ICMP:
|
||||
pshs = [][]byte{
|
||||
icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1")),
|
||||
nil,
|
||||
}
|
||||
var marshalAndParseMessageForIPv4Tests = []icmp.Message{
|
||||
{
|
||||
Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
|
||||
Body: &icmp.DstUnreach{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
|
||||
Body: &icmp.TimeExceeded{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeParameterProblem, Code: 2,
|
||||
Body: &icmp.ParamProb{
|
||||
Pointer: 8,
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeEcho, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: 1, Seq: 2,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypePhoturis,
|
||||
Body: &icmp.DefaultMessageBody{
|
||||
Data: []byte{0x80, 0x40, 0x20, 0x10},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMarshalAndParseMessageForIPv4(t *testing.T) {
|
||||
for i, tt := range marshalAndParseMessageForIPv4Tests {
|
||||
b, err := tt.Marshal(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i, tm := range tms {
|
||||
for _, psh := range pshs {
|
||||
b, err := tm.Marshal(psh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m, err := icmp.ParseMessage(proto, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m.Type != tm.Type || m.Code != tm.Code {
|
||||
t.Errorf("#%d: got %#v; want %#v", i, m, &tm)
|
||||
}
|
||||
if !reflect.DeepEqual(m.Body, tm.Body) {
|
||||
t.Errorf("#%d: got %#v; want %#v", i, m.Body, tm.Body)
|
||||
}
|
||||
m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m.Type != tt.Type || m.Code != tt.Code {
|
||||
t.Errorf("#%v: got %v; want %v", i, m, &tt)
|
||||
}
|
||||
if !reflect.DeepEqual(m.Body, tt.Body) {
|
||||
t.Errorf("#%v: got %v; want %v", i, m.Body, tt.Body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var marshalAndParseMessageForIPv6Tests = []icmp.Message{
|
||||
{
|
||||
Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
|
||||
Body: &icmp.DstUnreach{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypePacketTooBig, Code: 0,
|
||||
Body: &icmp.PacketTooBig{
|
||||
MTU: 1<<16 - 1,
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
|
||||
Body: &icmp.TimeExceeded{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeParameterProblem, Code: 2,
|
||||
Body: &icmp.ParamProb{
|
||||
Pointer: 8,
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: 1, Seq: 2,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeDuplicateAddressConfirmation,
|
||||
Body: &icmp.DefaultMessageBody{
|
||||
Data: []byte{0x80, 0x40, 0x20, 0x10},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMarshalAndParseMessageForIPv6(t *testing.T) {
|
||||
pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1"))
|
||||
for i, tt := range marshalAndParseMessageForIPv6Tests {
|
||||
for _, psh := range [][]byte{pshicmp, nil} {
|
||||
b, err := tt.Marshal(psh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m.Type != tt.Type || m.Code != tt.Code {
|
||||
t.Errorf("#%v: got %v; want %v", i, m, &tt)
|
||||
}
|
||||
if !reflect.DeepEqual(m.Body, tt.Body) {
|
||||
t.Errorf("#%v: got %v; want %v", i, m.Body, tt.Body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("IPv4", func(t *testing.T) {
|
||||
fn(t, iana.ProtocolICMP,
|
||||
[]icmp.Message{
|
||||
{
|
||||
Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
|
||||
Body: &icmp.DstUnreach{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
|
||||
Body: &icmp.TimeExceeded{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeParameterProblem, Code: 2,
|
||||
Body: &icmp.ParamProb{
|
||||
Pointer: 8,
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeEcho, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: 1, Seq: 2,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: 1, Seq: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeExtendedEchoReply, Code: 0,
|
||||
Body: &icmp.ExtendedEchoReply{
|
||||
State: 4 /* Delay */, Active: true, IPv4: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypePhoturis,
|
||||
Body: &icmp.DefaultMessageBody{
|
||||
Data: []byte{0x80, 0x40, 0x20, 0x10},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("IPv6", func(t *testing.T) {
|
||||
fn(t, iana.ProtocolIPv6ICMP,
|
||||
[]icmp.Message{
|
||||
{
|
||||
Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
|
||||
Body: &icmp.DstUnreach{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypePacketTooBig, Code: 0,
|
||||
Body: &icmp.PacketTooBig{
|
||||
MTU: 1<<16 - 1,
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
|
||||
Body: &icmp.TimeExceeded{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeParameterProblem, Code: 2,
|
||||
Body: &icmp.ParamProb{
|
||||
Pointer: 8,
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: 1, Seq: 2,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: 1, Seq: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeExtendedEchoReply, Code: 0,
|
||||
Body: &icmp.ExtendedEchoReply{
|
||||
State: 5 /* Probe */, Active: true, IPv6: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeDuplicateAddressConfirmation,
|
||||
Body: &icmp.DefaultMessageBody{
|
||||
Data: []byte{0x80, 0x40, 0x20, 0x10},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
38
vendor/golang.org/x/net/icmp/multipart.go
generated
vendored
38
vendor/golang.org/x/net/icmp/multipart.go
generated
vendored
@@ -10,14 +10,12 @@ import "golang.org/x/net/internal/iana"
|
||||
// exts as extensions, and returns a required length for message body
|
||||
// and a required length for a padded original datagram in wire
|
||||
// format.
|
||||
func multipartMessageBodyDataLen(proto int, withOrigDgram bool, b []byte, exts []Extension) (bodyLen, dataLen int) {
|
||||
func multipartMessageBodyDataLen(proto int, b []byte, exts []Extension) (bodyLen, dataLen int) {
|
||||
for _, ext := range exts {
|
||||
bodyLen += ext.Len(proto)
|
||||
}
|
||||
if bodyLen > 0 {
|
||||
if withOrigDgram {
|
||||
dataLen = multipartMessageOrigDatagramLen(proto, b)
|
||||
}
|
||||
dataLen = multipartMessageOrigDatagramLen(proto, b)
|
||||
bodyLen += 4 // length of extension header
|
||||
} else {
|
||||
dataLen = len(b)
|
||||
@@ -52,8 +50,8 @@ func multipartMessageOrigDatagramLen(proto int, b []byte) int {
|
||||
// marshalMultipartMessageBody takes data as an original datagram and
|
||||
// exts as extesnsions, and returns a binary encoding of message body.
|
||||
// It can be used for non-multipart message bodies when exts is nil.
|
||||
func marshalMultipartMessageBody(proto int, withOrigDgram bool, data []byte, exts []Extension) ([]byte, error) {
|
||||
bodyLen, dataLen := multipartMessageBodyDataLen(proto, withOrigDgram, data, exts)
|
||||
func marshalMultipartMessageBody(proto int, data []byte, exts []Extension) ([]byte, error) {
|
||||
bodyLen, dataLen := multipartMessageBodyDataLen(proto, data, exts)
|
||||
b := make([]byte, 4+bodyLen)
|
||||
copy(b[4:], data)
|
||||
off := dataLen + 4
|
||||
@@ -73,23 +71,16 @@ func marshalMultipartMessageBody(proto int, withOrigDgram bool, data []byte, ext
|
||||
return nil, err
|
||||
}
|
||||
off += ext.Len(proto)
|
||||
case *InterfaceIdent:
|
||||
if err := ext.marshal(proto, b[off:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
off += ext.Len(proto)
|
||||
}
|
||||
}
|
||||
s := checksum(b[dataLen+4:])
|
||||
b[dataLen+4+2] ^= byte(s)
|
||||
b[dataLen+4+3] ^= byte(s >> 8)
|
||||
if withOrigDgram {
|
||||
switch proto {
|
||||
case iana.ProtocolICMP:
|
||||
b[1] = byte(dataLen / 4)
|
||||
case iana.ProtocolIPv6ICMP:
|
||||
b[0] = byte(dataLen / 8)
|
||||
}
|
||||
switch proto {
|
||||
case iana.ProtocolICMP:
|
||||
b[1] = byte(dataLen / 4)
|
||||
case iana.ProtocolIPv6ICMP:
|
||||
b[0] = byte(dataLen / 8)
|
||||
}
|
||||
}
|
||||
return b, nil
|
||||
@@ -97,7 +88,7 @@ func marshalMultipartMessageBody(proto int, withOrigDgram bool, data []byte, ext
|
||||
|
||||
// parseMultipartMessageBody parses b as either a non-multipart
|
||||
// message body or a multipart message body.
|
||||
func parseMultipartMessageBody(proto int, typ Type, b []byte) ([]byte, []Extension, error) {
|
||||
func parseMultipartMessageBody(proto int, b []byte) ([]byte, []Extension, error) {
|
||||
var l int
|
||||
switch proto {
|
||||
case iana.ProtocolICMP:
|
||||
@@ -108,14 +99,11 @@ func parseMultipartMessageBody(proto int, typ Type, b []byte) ([]byte, []Extensi
|
||||
if len(b) == 4 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
exts, l, err := parseExtensions(typ, b[4:], l)
|
||||
exts, l, err := parseExtensions(b[4:], l)
|
||||
if err != nil {
|
||||
l = len(b) - 4
|
||||
}
|
||||
var data []byte
|
||||
if l > 0 {
|
||||
data = make([]byte, l)
|
||||
copy(data, b[4:])
|
||||
}
|
||||
data := make([]byte, l)
|
||||
copy(data, b[4:])
|
||||
return data, exts, nil
|
||||
}
|
||||
|
||||
925
vendor/golang.org/x/net/icmp/multipart_test.go
generated
vendored
925
vendor/golang.org/x/net/icmp/multipart_test.go
generated
vendored
@@ -5,7 +5,6 @@
|
||||
package icmp_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
@@ -17,557 +16,425 @@ import (
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
func TestMarshalAndParseMultipartMessage(t *testing.T) {
|
||||
fn := func(t *testing.T, proto int, tm icmp.Message) error {
|
||||
b, err := tm.Marshal(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch tm.Type {
|
||||
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
|
||||
default:
|
||||
switch proto {
|
||||
case iana.ProtocolICMP:
|
||||
if b[5] != 32 {
|
||||
return fmt.Errorf("got %d; want 32", b[5])
|
||||
}
|
||||
case iana.ProtocolIPv6ICMP:
|
||||
if b[4] != 16 {
|
||||
return fmt.Errorf("got %d; want 16", b[4])
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown protocol: %d", proto)
|
||||
}
|
||||
}
|
||||
m, err := icmp.ParseMessage(proto, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m.Type != tm.Type || m.Code != tm.Code {
|
||||
return fmt.Errorf("got %v; want %v", m, &tm)
|
||||
}
|
||||
switch m.Type {
|
||||
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
|
||||
got, want := m.Body.(*icmp.ExtendedEchoRequest), tm.Body.(*icmp.ExtendedEchoRequest)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
|
||||
}
|
||||
case ipv4.ICMPTypeDestinationUnreachable:
|
||||
got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
return fmt.Errorf("got %d; want 128", len(got.Data))
|
||||
}
|
||||
case ipv4.ICMPTypeTimeExceeded:
|
||||
got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
return fmt.Errorf("got %d; want 128", len(got.Data))
|
||||
}
|
||||
case ipv4.ICMPTypeParameterProblem:
|
||||
got, want := m.Body.(*icmp.ParamProb), tm.Body.(*icmp.ParamProb)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
return fmt.Errorf("got %d; want 128", len(got.Data))
|
||||
}
|
||||
case ipv6.ICMPTypeDestinationUnreachable:
|
||||
got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
return fmt.Errorf("got %d; want 128", len(got.Data))
|
||||
}
|
||||
case ipv6.ICMPTypeTimeExceeded:
|
||||
got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
return fmt.Errorf("got %d; want 128", len(got.Data))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown message type: %v", m.Type)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
t.Run("IPv4", func(t *testing.T) {
|
||||
for i, tm := range []icmp.Message{
|
||||
{
|
||||
Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
|
||||
Body: &icmp.DstUnreach{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
var marshalAndParseMultipartMessageForIPv4Tests = []icmp.Message{
|
||||
{
|
||||
Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
|
||||
Body: &icmp.DstUnreach{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.IPv4(192, 168, 0, 1).To4(),
|
||||
},
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.IPv4(192, 168, 0, 1).To4(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
|
||||
Body: &icmp.TimeExceeded{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.IPv4(192, 168, 0, 1).To4(),
|
||||
},
|
||||
},
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
|
||||
Body: &icmp.TimeExceeded{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.IPv4(192, 168, 0, 1).To4(),
|
||||
},
|
||||
},
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeParameterProblem, Code: 2,
|
||||
Body: &icmp.ParamProb{
|
||||
Pointer: 8,
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeParameterProblem, Code: 2,
|
||||
Body: &icmp.ParamProb{
|
||||
Pointer: 8,
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.IPv4(192, 168, 0, 1).To4(),
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x2f,
|
||||
Interface: &net.Interface{
|
||||
Index: 16,
|
||||
Name: "en102",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.IPv4(192, 168, 0, 2).To4(),
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.IPv4(192, 168, 0, 1).To4(),
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x2f,
|
||||
Interface: &net.Interface{
|
||||
Index: 16,
|
||||
Name: "en102",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.IPv4(192, 168, 0, 2).To4(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: 1, Seq: 2, Local: true,
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3,
|
||||
Type: 1,
|
||||
Name: "en101",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: 1, Seq: 2, Local: true,
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3,
|
||||
Type: 2,
|
||||
Index: 911,
|
||||
},
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3,
|
||||
Type: 1,
|
||||
Name: "en101",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: 1, Seq: 2,
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3,
|
||||
Type: 3,
|
||||
AFI: iana.AddrFamily48bitMAC,
|
||||
Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := fn(t, iana.ProtocolICMP, tm); err != nil {
|
||||
t.Errorf("#%d: %v", i, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("IPv6", func(t *testing.T) {
|
||||
for i, tm := range []icmp.Message{
|
||||
{
|
||||
Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
|
||||
Body: &icmp.DstUnreach{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.ParseIP("fe80::1"),
|
||||
Zone: "en101",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
|
||||
Body: &icmp.TimeExceeded{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.ParseIP("fe80::1"),
|
||||
Zone: "en101",
|
||||
},
|
||||
},
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x2f,
|
||||
Interface: &net.Interface{
|
||||
Index: 16,
|
||||
Name: "en102",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.ParseIP("fe80::1"),
|
||||
Zone: "en102",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: 1, Seq: 2, Local: true,
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3,
|
||||
Type: 1,
|
||||
Name: "en101",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: 1, Seq: 2, Local: true,
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3,
|
||||
Type: 1,
|
||||
Name: "en101",
|
||||
},
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3,
|
||||
Type: 2,
|
||||
Index: 911,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
|
||||
Body: &icmp.ExtendedEchoRequest{
|
||||
ID: 1, Seq: 2,
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Class: 3,
|
||||
Type: 3,
|
||||
AFI: iana.AddrFamilyIPv4,
|
||||
Addr: []byte{192, 0, 2, 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := fn(t, iana.ProtocolIPv6ICMP, tm); err != nil {
|
||||
t.Errorf("#%d: %v", i, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func dumpExtensions(gotExts, wantExts []icmp.Extension) string {
|
||||
var s string
|
||||
for i, got := range gotExts {
|
||||
switch got := got.(type) {
|
||||
case *icmp.MPLSLabelStack:
|
||||
want := wantExts[i].(*icmp.MPLSLabelStack)
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
|
||||
func TestMarshalAndParseMultipartMessageForIPv4(t *testing.T) {
|
||||
for i, tt := range marshalAndParseMultipartMessageForIPv4Tests {
|
||||
b, err := tt.Marshal(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b[5] != 32 {
|
||||
t.Errorf("#%v: got %v; want 32", i, b[5])
|
||||
}
|
||||
m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m.Type != tt.Type || m.Code != tt.Code {
|
||||
t.Errorf("#%v: got %v; want %v", i, m, &tt)
|
||||
}
|
||||
switch m.Type {
|
||||
case ipv4.ICMPTypeDestinationUnreachable:
|
||||
got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
|
||||
}
|
||||
case *icmp.InterfaceInfo:
|
||||
want := wantExts[i].(*icmp.InterfaceInfo)
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
s += fmt.Sprintf("#%d: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, got, got.Interface, got.Addr, want, want.Interface, want.Addr)
|
||||
if len(got.Data) != 128 {
|
||||
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
|
||||
}
|
||||
case *icmp.InterfaceIdent:
|
||||
want := wantExts[i].(*icmp.InterfaceIdent)
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
|
||||
case ipv4.ICMPTypeTimeExceeded:
|
||||
got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
|
||||
}
|
||||
case ipv4.ICMPTypeParameterProblem:
|
||||
got, want := m.Body.(*icmp.ParamProb), tt.Body.(*icmp.ParamProb)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(s) == 0 {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
var marshalAndParseMultipartMessageForIPv6Tests = []icmp.Message{
|
||||
{
|
||||
Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
|
||||
Body: &icmp.DstUnreach{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.ParseIP("fe80::1"),
|
||||
Zone: "en101",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
|
||||
Body: &icmp.TimeExceeded{
|
||||
Data: []byte("ERROR-INVOKING-PACKET"),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x0f,
|
||||
Interface: &net.Interface{
|
||||
Index: 15,
|
||||
Name: "en101",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.ParseIP("fe80::1"),
|
||||
Zone: "en101",
|
||||
},
|
||||
},
|
||||
&icmp.MPLSLabelStack{
|
||||
Class: 1,
|
||||
Type: 1,
|
||||
Labels: []icmp.MPLSLabel{
|
||||
{
|
||||
Label: 16014,
|
||||
TC: 0x4,
|
||||
S: true,
|
||||
TTL: 255,
|
||||
},
|
||||
},
|
||||
},
|
||||
&icmp.InterfaceInfo{
|
||||
Class: 2,
|
||||
Type: 0x2f,
|
||||
Interface: &net.Interface{
|
||||
Index: 16,
|
||||
Name: "en102",
|
||||
MTU: 8192,
|
||||
},
|
||||
Addr: &net.IPAddr{
|
||||
IP: net.ParseIP("fe80::1"),
|
||||
Zone: "en102",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMarshalAndParseMultipartMessageForIPv6(t *testing.T) {
|
||||
pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1"))
|
||||
for i, tt := range marshalAndParseMultipartMessageForIPv6Tests {
|
||||
for _, psh := range [][]byte{pshicmp, nil} {
|
||||
b, err := tt.Marshal(psh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b[4] != 16 {
|
||||
t.Errorf("#%v: got %v; want 16", i, b[4])
|
||||
}
|
||||
m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m.Type != tt.Type || m.Code != tt.Code {
|
||||
t.Errorf("#%v: got %v; want %v", i, m, &tt)
|
||||
}
|
||||
switch m.Type {
|
||||
case ipv6.ICMPTypeDestinationUnreachable:
|
||||
got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
|
||||
}
|
||||
case ipv6.ICMPTypeTimeExceeded:
|
||||
got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded)
|
||||
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
|
||||
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
|
||||
}
|
||||
if len(got.Data) != 128 {
|
||||
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpExtensions(i int, gotExts, wantExts []icmp.Extension) string {
|
||||
var s string
|
||||
for j, got := range gotExts {
|
||||
switch got := got.(type) {
|
||||
case *icmp.MPLSLabelStack:
|
||||
want := wantExts[j].(*icmp.MPLSLabelStack)
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
s += fmt.Sprintf("#%v/%v: got %#v; want %#v\n", i, j, got, want)
|
||||
}
|
||||
case *icmp.InterfaceInfo:
|
||||
want := wantExts[j].(*icmp.InterfaceInfo)
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
s += fmt.Sprintf("#%v/%v: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, j, got, got.Interface, got.Addr, want, want.Interface, want.Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return s[:len(s)-1]
|
||||
}
|
||||
|
||||
var multipartMessageBodyLenTests = []struct {
|
||||
proto int
|
||||
in icmp.MessageBody
|
||||
out int
|
||||
}{
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, ipv4.HeaderLen),
|
||||
},
|
||||
4 + ipv4.HeaderLen, // unused and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.TimeExceeded{
|
||||
Data: make([]byte, ipv4.HeaderLen),
|
||||
},
|
||||
4 + ipv4.HeaderLen, // unused and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, ipv4.HeaderLen),
|
||||
},
|
||||
4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
|
||||
},
|
||||
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, ipv4.HeaderLen),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, 128),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, 129),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, ipv6.HeaderLen),
|
||||
},
|
||||
4 + ipv6.HeaderLen, // unused and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.PacketTooBig{
|
||||
Data: make([]byte, ipv6.HeaderLen),
|
||||
},
|
||||
4 + ipv6.HeaderLen, // mtu and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.TimeExceeded{
|
||||
Data: make([]byte, ipv6.HeaderLen),
|
||||
},
|
||||
4 + ipv6.HeaderLen, // unused and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, ipv6.HeaderLen),
|
||||
},
|
||||
4 + ipv6.HeaderLen, // pointer and original datagram
|
||||
},
|
||||
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, 127),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, 128),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, 129),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
}
|
||||
|
||||
func TestMultipartMessageBodyLen(t *testing.T) {
|
||||
for i, tt := range []struct {
|
||||
proto int
|
||||
in icmp.MessageBody
|
||||
out int
|
||||
}{
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, ipv4.HeaderLen),
|
||||
},
|
||||
4 + ipv4.HeaderLen, // unused and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.TimeExceeded{
|
||||
Data: make([]byte, ipv4.HeaderLen),
|
||||
},
|
||||
4 + ipv4.HeaderLen, // unused and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, ipv4.HeaderLen),
|
||||
},
|
||||
4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
|
||||
},
|
||||
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, ipv4.HeaderLen),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, 128),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, 129),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, ipv6.HeaderLen),
|
||||
},
|
||||
4 + ipv6.HeaderLen, // unused and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.PacketTooBig{
|
||||
Data: make([]byte, ipv6.HeaderLen),
|
||||
},
|
||||
4 + ipv6.HeaderLen, // mtu and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.TimeExceeded{
|
||||
Data: make([]byte, ipv6.HeaderLen),
|
||||
},
|
||||
4 + ipv6.HeaderLen, // unused and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.ParamProb{
|
||||
Data: make([]byte, ipv6.HeaderLen),
|
||||
},
|
||||
4 + ipv6.HeaderLen, // pointer and original datagram
|
||||
},
|
||||
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, 127),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, 128),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.DstUnreach{
|
||||
Data: make([]byte, 129),
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.MPLSLabelStack{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
|
||||
},
|
||||
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ExtendedEchoRequest{},
|
||||
4, // [id, seq, l-bit]
|
||||
},
|
||||
{
|
||||
iana.ProtocolICMP,
|
||||
&icmp.ExtendedEchoRequest{
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4, // [id, seq, l-bit], extension header, object header
|
||||
},
|
||||
{
|
||||
iana.ProtocolIPv6ICMP,
|
||||
&icmp.ExtendedEchoRequest{
|
||||
Extensions: []icmp.Extension{
|
||||
&icmp.InterfaceIdent{
|
||||
Type: 3,
|
||||
AFI: iana.AddrFamilyNSAP,
|
||||
Addr: []byte{0x49, 0x00, 0x01, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0x00},
|
||||
},
|
||||
},
|
||||
},
|
||||
4 + 4 + 4 + 16, // [id, seq, l-bit], extension header, object header, object payload
|
||||
},
|
||||
} {
|
||||
for i, tt := range multipartMessageBodyLenTests {
|
||||
if out := tt.in.Len(tt.proto); out != tt.out {
|
||||
t.Errorf("#%d: got %d; want %d", i, out, tt.out)
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/net/icmp/packettoobig.go
generated
vendored
2
vendor/golang.org/x/net/icmp/packettoobig.go
generated
vendored
@@ -29,7 +29,7 @@ func (p *PacketTooBig) Marshal(proto int) ([]byte, error) {
|
||||
}
|
||||
|
||||
// parsePacketTooBig parses b as an ICMP packet too big message body.
|
||||
func parsePacketTooBig(proto int, _ Type, b []byte) (MessageBody, error) {
|
||||
func parsePacketTooBig(proto int, b []byte) (MessageBody, error) {
|
||||
bodyLen := len(b)
|
||||
if bodyLen < 4 {
|
||||
return nil, errMessageTooShort
|
||||
|
||||
8
vendor/golang.org/x/net/icmp/paramprob.go
generated
vendored
8
vendor/golang.org/x/net/icmp/paramprob.go
generated
vendored
@@ -21,7 +21,7 @@ func (p *ParamProb) Len(proto int) int {
|
||||
if p == nil {
|
||||
return 0
|
||||
}
|
||||
l, _ := multipartMessageBodyDataLen(proto, true, p.Data, p.Extensions)
|
||||
l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions)
|
||||
return 4 + l
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (p *ParamProb) Marshal(proto int) ([]byte, error) {
|
||||
copy(b[4:], p.Data)
|
||||
return b, nil
|
||||
}
|
||||
b, err := marshalMultipartMessageBody(proto, true, p.Data, p.Extensions)
|
||||
b, err := marshalMultipartMessageBody(proto, p.Data, p.Extensions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -42,7 +42,7 @@ func (p *ParamProb) Marshal(proto int) ([]byte, error) {
|
||||
}
|
||||
|
||||
// parseParamProb parses b as an ICMP parameter problem message body.
|
||||
func parseParamProb(proto int, typ Type, b []byte) (MessageBody, error) {
|
||||
func parseParamProb(proto int, b []byte) (MessageBody, error) {
|
||||
if len(b) < 4 {
|
||||
return nil, errMessageTooShort
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func parseParamProb(proto int, typ Type, b []byte) (MessageBody, error) {
|
||||
}
|
||||
p.Pointer = uintptr(b[0])
|
||||
var err error
|
||||
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, typ, b)
|
||||
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
200
vendor/golang.org/x/net/icmp/ping_test.go
generated
vendored
Normal file
200
vendor/golang.org/x/net/icmp/ping_test.go
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright 2014 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 icmp_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/internal/iana"
|
||||
"golang.org/x/net/internal/nettest"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) {
|
||||
const host = "www.google.com"
|
||||
ips, err := net.LookupIP(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netaddr := func(ip net.IP) (net.Addr, error) {
|
||||
switch c.LocalAddr().(type) {
|
||||
case *net.UDPAddr:
|
||||
return &net.UDPAddr{IP: ip}, nil
|
||||
case *net.IPAddr:
|
||||
return &net.IPAddr{IP: ip}, nil
|
||||
default:
|
||||
return nil, errors.New("neither UDPAddr nor IPAddr")
|
||||
}
|
||||
}
|
||||
for _, ip := range ips {
|
||||
switch protocol {
|
||||
case iana.ProtocolICMP:
|
||||
if ip.To4() != nil {
|
||||
return netaddr(ip)
|
||||
}
|
||||
case iana.ProtocolIPv6ICMP:
|
||||
if ip.To16() != nil && ip.To4() == nil {
|
||||
return netaddr(ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, errors.New("no A or AAAA record")
|
||||
}
|
||||
|
||||
type pingTest struct {
|
||||
network, address string
|
||||
protocol int
|
||||
mtype icmp.Type
|
||||
}
|
||||
|
||||
var nonPrivilegedPingTests = []pingTest{
|
||||
{"udp4", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
|
||||
|
||||
{"udp6", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
|
||||
}
|
||||
|
||||
func TestNonPrivilegedPing(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("avoid external network")
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
case "linux":
|
||||
t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
|
||||
default:
|
||||
t.Skipf("not supported on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
for i, tt := range nonPrivilegedPingTests {
|
||||
if err := doPing(tt, i); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var privilegedPingTests = []pingTest{
|
||||
{"ip4:icmp", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
|
||||
|
||||
{"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
|
||||
}
|
||||
|
||||
func TestPrivilegedPing(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("avoid external network")
|
||||
}
|
||||
if m, ok := nettest.SupportsRawIPSocket(); !ok {
|
||||
t.Skip(m)
|
||||
}
|
||||
|
||||
for i, tt := range privilegedPingTests {
|
||||
if err := doPing(tt, i); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doPing(tt pingTest, seq int) error {
|
||||
c, err := icmp.ListenPacket(tt.network, tt.address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
dst, err := googleAddr(c, tt.protocol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tt.network != "udp6" && tt.protocol == iana.ProtocolIPv6ICMP {
|
||||
var f ipv6.ICMPFilter
|
||||
f.SetAll(true)
|
||||
f.Accept(ipv6.ICMPTypeDestinationUnreachable)
|
||||
f.Accept(ipv6.ICMPTypePacketTooBig)
|
||||
f.Accept(ipv6.ICMPTypeTimeExceeded)
|
||||
f.Accept(ipv6.ICMPTypeParameterProblem)
|
||||
f.Accept(ipv6.ICMPTypeEchoReply)
|
||||
if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wm := icmp.Message{
|
||||
Type: tt.mtype, Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
}
|
||||
wb, err := wm.Marshal(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n, err := c.WriteTo(wb, dst); err != nil {
|
||||
return err
|
||||
} else if n != len(wb) {
|
||||
return fmt.Errorf("got %v; want %v", n, len(wb))
|
||||
}
|
||||
|
||||
rb := make([]byte, 1500)
|
||||
if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
|
||||
return err
|
||||
}
|
||||
n, peer, err := c.ReadFrom(rb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch rm.Type {
|
||||
case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcurrentNonPrivilegedListenPacket(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("avoid external network")
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
case "linux":
|
||||
t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
|
||||
default:
|
||||
t.Skipf("not supported on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
network, address := "udp4", "127.0.0.1"
|
||||
if !nettest.SupportsIPv4() {
|
||||
network, address = "udp6", "::1"
|
||||
}
|
||||
const N = 1000
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(N)
|
||||
for i := 0; i < N; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
c, err := icmp.ListenPacket(network, address)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
c.Close()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
8
vendor/golang.org/x/net/icmp/timeexceeded.go
generated
vendored
8
vendor/golang.org/x/net/icmp/timeexceeded.go
generated
vendored
@@ -15,23 +15,23 @@ func (p *TimeExceeded) Len(proto int) int {
|
||||
if p == nil {
|
||||
return 0
|
||||
}
|
||||
l, _ := multipartMessageBodyDataLen(proto, true, p.Data, p.Extensions)
|
||||
l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions)
|
||||
return 4 + l
|
||||
}
|
||||
|
||||
// Marshal implements the Marshal method of MessageBody interface.
|
||||
func (p *TimeExceeded) Marshal(proto int) ([]byte, error) {
|
||||
return marshalMultipartMessageBody(proto, true, p.Data, p.Extensions)
|
||||
return marshalMultipartMessageBody(proto, p.Data, p.Extensions)
|
||||
}
|
||||
|
||||
// parseTimeExceeded parses b as an ICMP time exceeded message body.
|
||||
func parseTimeExceeded(proto int, typ Type, b []byte) (MessageBody, error) {
|
||||
func parseTimeExceeded(proto int, b []byte) (MessageBody, error) {
|
||||
if len(b) < 4 {
|
||||
return nil, errMessageTooShort
|
||||
}
|
||||
p := &TimeExceeded{}
|
||||
var err error
|
||||
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, typ, b)
|
||||
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
126
vendor/golang.org/x/net/idna/idna.go
generated
vendored
126
vendor/golang.org/x/net/idna/idna.go
generated
vendored
@@ -21,7 +21,6 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/secure/bidirule"
|
||||
"golang.org/x/text/unicode/bidi"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
|
||||
@@ -69,7 +68,7 @@ func VerifyDNSLength(verify bool) Option {
|
||||
}
|
||||
|
||||
// RemoveLeadingDots removes leading label separators. Leading runes that map to
|
||||
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well.
|
||||
// dots, such as U+3002, are removed as well.
|
||||
//
|
||||
// This is the behavior suggested by the UTS #46 and is adopted by some
|
||||
// browsers.
|
||||
@@ -93,7 +92,7 @@ func ValidateLabels(enable bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// StrictDomainName limits the set of permissible ASCII characters to those
|
||||
// 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.
|
||||
//
|
||||
@@ -143,6 +142,7 @@ func MapForLookup() Option {
|
||||
o.mapping = validateAndMap
|
||||
StrictDomainName(true)(o)
|
||||
ValidateLabels(true)(o)
|
||||
RemoveLeadingDots(true)(o)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,14 +160,14 @@ type options struct {
|
||||
|
||||
// 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)
|
||||
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 an IDNA mapper.
|
||||
// A Profile defines the configuration of a IDNA mapper.
|
||||
type Profile struct {
|
||||
options
|
||||
}
|
||||
@@ -251,21 +251,23 @@ var (
|
||||
|
||||
punycode = &Profile{}
|
||||
lookup = &Profile{options{
|
||||
transitional: true,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
transitional: true,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
removeLeadingDots: 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,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
removeLeadingDots: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
}}
|
||||
registration = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
@@ -300,16 +302,14 @@ func (e runeError) Error() string {
|
||||
// see http://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)
|
||||
s, 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 == "" {
|
||||
@@ -335,7 +335,6 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
|
||||
// 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)
|
||||
@@ -350,14 +349,6 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
|
||||
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()
|
||||
@@ -389,26 +380,16 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
|
||||
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 normalize(p *Profile, s string) (string, error) {
|
||||
return norm.NFC.String(s), nil
|
||||
}
|
||||
|
||||
func validateRegistration(p *Profile, s string) (idem string, bidi bool, err error) {
|
||||
// TODO: filter need for normalization in loop below.
|
||||
func validateRegistration(p *Profile, s string) (string, error) {
|
||||
if !norm.NFC.IsNormalString(s) {
|
||||
return s, false, &labelError{s, "V1"}
|
||||
return s, &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
|
||||
@@ -416,50 +397,21 @@ func validateRegistration(p *Profile, s string) (idem string, bidi bool, err err
|
||||
case valid, deviation:
|
||||
case disallowed, mapped, unknown, ignored:
|
||||
r, _ := utf8.DecodeRuneInString(s[i:])
|
||||
return s, bidi, runeError(r)
|
||||
return s, runeError(r)
|
||||
}
|
||||
i += sz
|
||||
}
|
||||
return s, bidi, nil
|
||||
return s, 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) {
|
||||
func validateAndMap(p *Profile, s string) (string, error) {
|
||||
var (
|
||||
b []byte
|
||||
k int
|
||||
err error
|
||||
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.
|
||||
@@ -486,9 +438,7 @@ func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) {
|
||||
}
|
||||
if k == 0 {
|
||||
// No changes so far.
|
||||
if combinedInfoBits&mayNeedNorm != 0 {
|
||||
s = norm.NFC.String(s)
|
||||
}
|
||||
s = norm.NFC.String(s)
|
||||
} else {
|
||||
b = append(b, s[k:]...)
|
||||
if norm.NFC.QuickSpan(b) != len(b) {
|
||||
@@ -497,7 +447,7 @@ func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) {
|
||||
// TODO: the punycode converters require strings as input.
|
||||
s = string(b)
|
||||
}
|
||||
return s, bidi, err
|
||||
return s, err
|
||||
}
|
||||
|
||||
// A labelIter allows iterating over domain name labels.
|
||||
@@ -592,13 +542,8 @@ 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"}
|
||||
}
|
||||
@@ -671,13 +616,16 @@ var joinStates = [][numJoinTypes]joinState{
|
||||
|
||||
// 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) {
|
||||
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
|
||||
}
|
||||
|
||||
65
vendor/golang.org/x/net/idna/idna_test.go
generated
vendored
65
vendor/golang.org/x/net/idna/idna_test.go
generated
vendored
@@ -39,70 +39,5 @@ func TestIDNA(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDNASeparators(t *testing.T) {
|
||||
type subCase struct {
|
||||
unicode string
|
||||
wantASCII string
|
||||
wantErr bool
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
profile *Profile
|
||||
subCases []subCase
|
||||
}{
|
||||
{
|
||||
name: "Punycode", profile: Punycode,
|
||||
subCases: []subCase{
|
||||
{"example\u3002jp", "xn--examplejp-ck3h", false},
|
||||
{"東京\uFF0Ejp", "xn--jp-l92cn98g071o", false},
|
||||
{"大阪\uFF61jp", "xn--jp-ku9cz72u463f", false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Lookup", profile: Lookup,
|
||||
subCases: []subCase{
|
||||
{"example\u3002jp", "example.jp", false},
|
||||
{"東京\uFF0Ejp", "xn--1lqs71d.jp", false},
|
||||
{"大阪\uFF61jp", "xn--pssu33l.jp", false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Display", profile: Display,
|
||||
subCases: []subCase{
|
||||
{"example\u3002jp", "example.jp", false},
|
||||
{"東京\uFF0Ejp", "xn--1lqs71d.jp", false},
|
||||
{"大阪\uFF61jp", "xn--pssu33l.jp", false},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Registration", profile: Registration,
|
||||
subCases: []subCase{
|
||||
{"example\u3002jp", "", true},
|
||||
{"東京\uFF0Ejp", "", true},
|
||||
{"大阪\uFF61jp", "", true},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
for _, c := range tc.subCases {
|
||||
gotA, err := tc.profile.ToASCII(c.unicode)
|
||||
if c.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("ToASCII(%q): got no error, but an error expected", c.unicode)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("ToASCII(%q): got err=%v, but no error expected", c.unicode, err)
|
||||
} else if gotA != c.wantASCII {
|
||||
t.Errorf("ToASCII(%q): got %q, want %q", c.unicode, gotA, c.wantASCII)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(nigeltao): test errors, once we've specified when ToASCII and ToUnicode
|
||||
// return errors.
|
||||
|
||||
4396
vendor/golang.org/x/net/idna/tables.go
generated
vendored
4396
vendor/golang.org/x/net/idna/tables.go
generated
vendored
File diff suppressed because it is too large
Load Diff
17
vendor/golang.org/x/net/idna/trieval.go
generated
vendored
17
vendor/golang.org/x/net/idna/trieval.go
generated
vendored
@@ -26,9 +26,9 @@ package idna
|
||||
// 15..3 index into xor or mapping table
|
||||
// }
|
||||
// } else {
|
||||
// 15..14 unused
|
||||
// 13 mayNeedNorm
|
||||
// 12..11 attributes
|
||||
// 15..13 unused
|
||||
// 12 modifier (including virama)
|
||||
// 11 virama modifier
|
||||
// 10..8 joining type
|
||||
// 7..3 category type
|
||||
// }
|
||||
@@ -49,20 +49,15 @@ const (
|
||||
joinShift = 8
|
||||
joinMask = 0x07
|
||||
|
||||
// Attributes
|
||||
attributesMask = 0x1800
|
||||
viramaModifier = 0x1800
|
||||
viramaModifier = 0x0800
|
||||
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.
|
||||
unknown category = 0 // not defined currently in unicode.
|
||||
mapped category = 1
|
||||
disallowedSTD3Mapped category = 2
|
||||
deviation category = 3
|
||||
@@ -115,5 +110,5 @@ func (c info) isModifier() bool {
|
||||
}
|
||||
|
||||
func (c info) isViramaModifier() bool {
|
||||
return c&(attributesMask|catSmallMask) == viramaModifier
|
||||
return c&(viramaModifier|catSmallMask) == viramaModifier
|
||||
}
|
||||
|
||||
51
vendor/golang.org/x/net/internal/iana/const.go
generated
vendored
51
vendor/golang.org/x/net/internal/iana/const.go
generated
vendored
@@ -1,5 +1,5 @@
|
||||
// go generate gen.go
|
||||
// Code generated by the command above; DO NOT EDIT.
|
||||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
|
||||
package iana // import "golang.org/x/net/internal/iana"
|
||||
@@ -38,7 +38,7 @@ const (
|
||||
CongestionExperienced = 0x3 // CE (Congestion Experienced)
|
||||
)
|
||||
|
||||
// Protocol Numbers, Updated: 2017-10-13
|
||||
// Protocol Numbers, Updated: 2016-06-22
|
||||
const (
|
||||
ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
|
||||
ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
|
||||
@@ -178,50 +178,3 @@ const (
|
||||
ProtocolROHC = 142 // Robust Header Compression
|
||||
ProtocolReserved = 255 // Reserved
|
||||
)
|
||||
|
||||
// Address Family Numbers, Updated: 2016-10-25
|
||||
const (
|
||||
AddrFamilyIPv4 = 1 // IP (IP version 4)
|
||||
AddrFamilyIPv6 = 2 // IP6 (IP version 6)
|
||||
AddrFamilyNSAP = 3 // NSAP
|
||||
AddrFamilyHDLC = 4 // HDLC (8-bit multidrop)
|
||||
AddrFamilyBBN1822 = 5 // BBN 1822
|
||||
AddrFamily802 = 6 // 802 (includes all 802 media plus Ethernet "canonical format")
|
||||
AddrFamilyE163 = 7 // E.163
|
||||
AddrFamilyE164 = 8 // E.164 (SMDS, Frame Relay, ATM)
|
||||
AddrFamilyF69 = 9 // F.69 (Telex)
|
||||
AddrFamilyX121 = 10 // X.121 (X.25, Frame Relay)
|
||||
AddrFamilyIPX = 11 // IPX
|
||||
AddrFamilyAppletalk = 12 // Appletalk
|
||||
AddrFamilyDecnetIV = 13 // Decnet IV
|
||||
AddrFamilyBanyanVines = 14 // Banyan Vines
|
||||
AddrFamilyE164withSubaddress = 15 // E.164 with NSAP format subaddress
|
||||
AddrFamilyDNS = 16 // DNS (Domain Name System)
|
||||
AddrFamilyDistinguishedName = 17 // Distinguished Name
|
||||
AddrFamilyASNumber = 18 // AS Number
|
||||
AddrFamilyXTPoverIPv4 = 19 // XTP over IP version 4
|
||||
AddrFamilyXTPoverIPv6 = 20 // XTP over IP version 6
|
||||
AddrFamilyXTPnativemodeXTP = 21 // XTP native mode XTP
|
||||
AddrFamilyFibreChannelWorldWidePortName = 22 // Fibre Channel World-Wide Port Name
|
||||
AddrFamilyFibreChannelWorldWideNodeName = 23 // Fibre Channel World-Wide Node Name
|
||||
AddrFamilyGWID = 24 // GWID
|
||||
AddrFamilyL2VPN = 25 // AFI for L2VPN information
|
||||
AddrFamilyMPLSTPSectionEndpointID = 26 // MPLS-TP Section Endpoint Identifier
|
||||
AddrFamilyMPLSTPLSPEndpointID = 27 // MPLS-TP LSP Endpoint Identifier
|
||||
AddrFamilyMPLSTPPseudowireEndpointID = 28 // MPLS-TP Pseudowire Endpoint Identifier
|
||||
AddrFamilyMTIPv4 = 29 // MT IP: Multi-Topology IP version 4
|
||||
AddrFamilyMTIPv6 = 30 // MT IPv6: Multi-Topology IP version 6
|
||||
AddrFamilyEIGRPCommonServiceFamily = 16384 // EIGRP Common Service Family
|
||||
AddrFamilyEIGRPIPv4ServiceFamily = 16385 // EIGRP IPv4 Service Family
|
||||
AddrFamilyEIGRPIPv6ServiceFamily = 16386 // EIGRP IPv6 Service Family
|
||||
AddrFamilyLISPCanonicalAddressFormat = 16387 // LISP Canonical Address Format (LCAF)
|
||||
AddrFamilyBGPLS = 16388 // BGP-LS
|
||||
AddrFamily48bitMAC = 16389 // 48-bit MAC
|
||||
AddrFamily64bitMAC = 16390 // 64-bit MAC
|
||||
AddrFamilyOUI = 16391 // OUI
|
||||
AddrFamilyMACFinal24bits = 16392 // MAC/24
|
||||
AddrFamilyMACFinal40bits = 16393 // MAC/40
|
||||
AddrFamilyIPv6Initial64bits = 16394 // IPv6/64
|
||||
AddrFamilyRBridgePortID = 16395 // RBridge Port ID
|
||||
AddrFamilyTRILLNickname = 16396 // TRILL Nickname
|
||||
)
|
||||
|
||||
102
vendor/golang.org/x/net/internal/iana/gen.go
generated
vendored
102
vendor/golang.org/x/net/internal/iana/gen.go
generated
vendored
@@ -28,27 +28,23 @@ var registries = []struct {
|
||||
parse func(io.Writer, io.Reader) error
|
||||
}{
|
||||
{
|
||||
"https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
|
||||
"http://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
|
||||
parseDSCPRegistry,
|
||||
},
|
||||
{
|
||||
"https://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml",
|
||||
"http://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml",
|
||||
parseTOSTCByte,
|
||||
},
|
||||
{
|
||||
"https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
|
||||
"http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
|
||||
parseProtocolNumbers,
|
||||
},
|
||||
{
|
||||
"http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
|
||||
parseAddrFamilyNumbers,
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
var bb bytes.Buffer
|
||||
fmt.Fprintf(&bb, "// go generate gen.go\n")
|
||||
fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
|
||||
fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
|
||||
fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n")
|
||||
fmt.Fprintf(&bb, `package iana // import "golang.org/x/net/internal/iana"`+"\n\n")
|
||||
for _, r := range registries {
|
||||
@@ -295,93 +291,3 @@ func (pn *protocolNumbers) escape() []canonProtocolRecord {
|
||||
}
|
||||
return prs
|
||||
}
|
||||
|
||||
func parseAddrFamilyNumbers(w io.Writer, r io.Reader) error {
|
||||
dec := xml.NewDecoder(r)
|
||||
var afn addrFamilylNumbers
|
||||
if err := dec.Decode(&afn); err != nil {
|
||||
return err
|
||||
}
|
||||
afrs := afn.escape()
|
||||
fmt.Fprintf(w, "// %s, Updated: %s\n", afn.Title, afn.Updated)
|
||||
fmt.Fprintf(w, "const (\n")
|
||||
for _, afr := range afrs {
|
||||
if afr.Name == "" {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(w, "AddrFamily%s = %d", afr.Name, afr.Value)
|
||||
fmt.Fprintf(w, "// %s\n", afr.Descr)
|
||||
}
|
||||
fmt.Fprintf(w, ")\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
type addrFamilylNumbers struct {
|
||||
XMLName xml.Name `xml:"registry"`
|
||||
Title string `xml:"title"`
|
||||
Updated string `xml:"updated"`
|
||||
RegTitle string `xml:"registry>title"`
|
||||
Note string `xml:"registry>note"`
|
||||
Records []struct {
|
||||
Value string `xml:"value"`
|
||||
Descr string `xml:"description"`
|
||||
} `xml:"registry>record"`
|
||||
}
|
||||
|
||||
type canonAddrFamilyRecord struct {
|
||||
Name string
|
||||
Descr string
|
||||
Value int
|
||||
}
|
||||
|
||||
func (afn *addrFamilylNumbers) escape() []canonAddrFamilyRecord {
|
||||
afrs := make([]canonAddrFamilyRecord, len(afn.Records))
|
||||
sr := strings.NewReplacer(
|
||||
"IP version 4", "IPv4",
|
||||
"IP version 6", "IPv6",
|
||||
"Identifier", "ID",
|
||||
"-", "",
|
||||
"-", "",
|
||||
"/", "",
|
||||
".", "",
|
||||
" ", "",
|
||||
)
|
||||
for i, afr := range afn.Records {
|
||||
if strings.Contains(afr.Descr, "Unassigned") ||
|
||||
strings.Contains(afr.Descr, "Reserved") {
|
||||
continue
|
||||
}
|
||||
afrs[i].Descr = afr.Descr
|
||||
s := strings.TrimSpace(afr.Descr)
|
||||
switch s {
|
||||
case "IP (IP version 4)":
|
||||
afrs[i].Name = "IPv4"
|
||||
case "IP6 (IP version 6)":
|
||||
afrs[i].Name = "IPv6"
|
||||
case "AFI for L2VPN information":
|
||||
afrs[i].Name = "L2VPN"
|
||||
case "E.164 with NSAP format subaddress":
|
||||
afrs[i].Name = "E164withSubaddress"
|
||||
case "MT IP: Multi-Topology IP version 4":
|
||||
afrs[i].Name = "MTIPv4"
|
||||
case "MAC/24":
|
||||
afrs[i].Name = "MACFinal24bits"
|
||||
case "MAC/40":
|
||||
afrs[i].Name = "MACFinal40bits"
|
||||
case "IPv6/64":
|
||||
afrs[i].Name = "IPv6Initial64bits"
|
||||
default:
|
||||
n := strings.Index(s, "(")
|
||||
if n > 0 {
|
||||
s = s[:n]
|
||||
}
|
||||
n = strings.Index(s, ":")
|
||||
if n > 0 {
|
||||
s = s[:n]
|
||||
}
|
||||
afrs[i].Name = sr.Replace(s)
|
||||
}
|
||||
afrs[i].Value, _ = strconv.Atoi(afr.Value)
|
||||
}
|
||||
return afrs
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/net/internal/nettest/helper_stub.go
generated
vendored
2
vendor/golang.org/x/net/internal/nettest/helper_stub.go
generated
vendored
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build js,wasm nacl plan9
|
||||
// +build nacl plan9
|
||||
|
||||
package nettest
|
||||
|
||||
|
||||
9
vendor/golang.org/x/net/internal/nettest/stack.go
generated
vendored
9
vendor/golang.org/x/net/internal/nettest/stack.go
generated
vendored
@@ -64,7 +64,7 @@ func TestableNetwork(network string) bool {
|
||||
switch network {
|
||||
case "unix", "unixgram":
|
||||
switch runtime.GOOS {
|
||||
case "android", "js", "nacl", "plan9", "windows":
|
||||
case "android", "nacl", "plan9", "windows":
|
||||
return false
|
||||
}
|
||||
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
|
||||
@@ -72,13 +72,8 @@ func TestableNetwork(network string) bool {
|
||||
}
|
||||
case "unixpacket":
|
||||
switch runtime.GOOS {
|
||||
case "android", "darwin", "freebsd", "js", "nacl", "plan9", "windows":
|
||||
case "android", "darwin", "freebsd", "nacl", "plan9", "windows":
|
||||
return false
|
||||
case "netbsd":
|
||||
// It passes on amd64 at least. 386 fails (Issue 22927). arm is unknown.
|
||||
if runtime.GOARCH == "386" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/iovec_32bit.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/iovec_32bit.go
generated
vendored
@@ -10,10 +10,6 @@ package socket
|
||||
import "unsafe"
|
||||
|
||||
func (v *iovec) set(b []byte) {
|
||||
l := len(b)
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
v.Base = (*byte)(unsafe.Pointer(&b[0]))
|
||||
v.Len = uint32(l)
|
||||
v.Len = uint32(len(b))
|
||||
}
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/iovec_64bit.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/iovec_64bit.go
generated
vendored
@@ -10,10 +10,6 @@ package socket
|
||||
import "unsafe"
|
||||
|
||||
func (v *iovec) set(b []byte) {
|
||||
l := len(b)
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
v.Base = (*byte)(unsafe.Pointer(&b[0]))
|
||||
v.Len = uint64(l)
|
||||
v.Len = uint64(len(b))
|
||||
}
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/iovec_solaris_64bit.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/iovec_solaris_64bit.go
generated
vendored
@@ -10,10 +10,6 @@ package socket
|
||||
import "unsafe"
|
||||
|
||||
func (v *iovec) set(b []byte) {
|
||||
l := len(b)
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
v.Base = (*int8)(unsafe.Pointer(&b[0]))
|
||||
v.Len = uint64(l)
|
||||
v.Len = uint64(len(b))
|
||||
}
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/msghdr_bsdvar.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/msghdr_bsdvar.go
generated
vendored
@@ -7,10 +7,6 @@
|
||||
package socket
|
||||
|
||||
func (h *msghdr) setIov(vs []iovec) {
|
||||
l := len(vs)
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
h.Iov = &vs[0]
|
||||
h.Iovlen = int32(l)
|
||||
h.Iovlen = int32(len(vs))
|
||||
}
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/msghdr_linux_32bit.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/msghdr_linux_32bit.go
generated
vendored
@@ -10,12 +10,8 @@ package socket
|
||||
import "unsafe"
|
||||
|
||||
func (h *msghdr) setIov(vs []iovec) {
|
||||
l := len(vs)
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
h.Iov = &vs[0]
|
||||
h.Iovlen = uint32(l)
|
||||
h.Iovlen = uint32(len(vs))
|
||||
}
|
||||
|
||||
func (h *msghdr) setControl(b []byte) {
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go
generated
vendored
@@ -10,12 +10,8 @@ package socket
|
||||
import "unsafe"
|
||||
|
||||
func (h *msghdr) setIov(vs []iovec) {
|
||||
l := len(vs)
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
h.Iov = &vs[0]
|
||||
h.Iovlen = uint64(l)
|
||||
h.Iovlen = uint64(len(vs))
|
||||
}
|
||||
|
||||
func (h *msghdr) setControl(b []byte) {
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/msghdr_openbsd.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/msghdr_openbsd.go
generated
vendored
@@ -5,10 +5,6 @@
|
||||
package socket
|
||||
|
||||
func (h *msghdr) setIov(vs []iovec) {
|
||||
l := len(vs)
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
h.Iov = &vs[0]
|
||||
h.Iovlen = uint32(l)
|
||||
h.Iovlen = uint32(len(vs))
|
||||
}
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/msghdr_solaris_64bit.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/msghdr_solaris_64bit.go
generated
vendored
@@ -13,10 +13,8 @@ func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
|
||||
for i := range vs {
|
||||
vs[i].set(bs[i])
|
||||
}
|
||||
if len(vs) > 0 {
|
||||
h.Iov = &vs[0]
|
||||
h.Iovlen = int32(len(vs))
|
||||
}
|
||||
h.Iov = &vs[0]
|
||||
h.Iovlen = int32(len(vs))
|
||||
if len(oob) > 0 {
|
||||
h.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
|
||||
h.Accrightslen = int32(len(oob))
|
||||
|
||||
12
vendor/golang.org/x/net/internal/socket/socket.go
generated
vendored
12
vendor/golang.org/x/net/internal/socket/socket.go
generated
vendored
@@ -110,7 +110,7 @@ func ControlMessageSpace(dataLen int) int {
|
||||
type ControlMessage []byte
|
||||
|
||||
// Data returns the data field of the control message at the head on
|
||||
// m.
|
||||
// w.
|
||||
func (m ControlMessage) Data(dataLen int) []byte {
|
||||
l := controlHeaderLen()
|
||||
if len(m) < l || len(m) < l+dataLen {
|
||||
@@ -119,7 +119,7 @@ func (m ControlMessage) Data(dataLen int) []byte {
|
||||
return m[l : l+dataLen]
|
||||
}
|
||||
|
||||
// Next returns the control message at the next on m.
|
||||
// Next returns the control message at the next on w.
|
||||
//
|
||||
// Next works only for standard control messages.
|
||||
func (m ControlMessage) Next(dataLen int) ControlMessage {
|
||||
@@ -131,7 +131,7 @@ func (m ControlMessage) Next(dataLen int) ControlMessage {
|
||||
}
|
||||
|
||||
// MarshalHeader marshals the header fields of the control message at
|
||||
// the head on m.
|
||||
// the head on w.
|
||||
func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
|
||||
if len(m) < controlHeaderLen() {
|
||||
return errors.New("short message")
|
||||
@@ -142,7 +142,7 @@ func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
|
||||
}
|
||||
|
||||
// ParseHeader parses and returns the header fields of the control
|
||||
// message at the head on m.
|
||||
// message at the head on w.
|
||||
func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
|
||||
l := controlHeaderLen()
|
||||
if len(m) < l {
|
||||
@@ -152,7 +152,7 @@ func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
|
||||
return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil
|
||||
}
|
||||
|
||||
// Marshal marshals the control message at the head on m, and returns
|
||||
// Marshal marshals the control message at the head on w, and returns
|
||||
// the next control message.
|
||||
func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) {
|
||||
l := len(data)
|
||||
@@ -167,7 +167,7 @@ func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, erro
|
||||
return m.Next(l), nil
|
||||
}
|
||||
|
||||
// Parse parses m as a single or multiple control messages.
|
||||
// Parse parses w as a single or multiple control messages.
|
||||
//
|
||||
// Parse works for both standard and compatible messages.
|
||||
func (m ControlMessage) Parse() ([]ControlMessage, error) {
|
||||
|
||||
141
vendor/golang.org/x/net/internal/socket/socket_go1_9_test.go
generated
vendored
141
vendor/golang.org/x/net/internal/socket/socket_go1_9_test.go
generated
vendored
@@ -119,84 +119,81 @@ func TestUDP(t *testing.T) {
|
||||
t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
|
||||
}
|
||||
defer c.Close()
|
||||
cc, err := socket.NewConn(c.(net.Conn))
|
||||
|
||||
t.Run("Message", func(t *testing.T) {
|
||||
testUDPMessage(t, c.(net.Conn))
|
||||
})
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
t.Run("Messages", func(t *testing.T) {
|
||||
testUDPMessages(t, c.(net.Conn))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testUDPMessage(t *testing.T, c net.Conn) {
|
||||
cc, err := socket.NewConn(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Run("Message", func(t *testing.T) {
|
||||
data := []byte("HELLO-R-U-THERE")
|
||||
wm := socket.Message{
|
||||
Buffers: bytes.SplitAfter(data, []byte("-")),
|
||||
Addr: c.LocalAddr(),
|
||||
}
|
||||
if err := cc.SendMsg(&wm, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b := make([]byte, 32)
|
||||
rm := socket.Message{
|
||||
Buffers: [][]byte{b[:1], b[1:3], b[3:7], b[7:11], b[11:]},
|
||||
}
|
||||
if err := cc.RecvMsg(&rm, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b[:rm.N], data) {
|
||||
t.Fatalf("got %#v; want %#v", b[:rm.N], data)
|
||||
}
|
||||
})
|
||||
switch runtime.GOOS {
|
||||
case "android", "linux":
|
||||
t.Run("Messages", func(t *testing.T) {
|
||||
data := []byte("HELLO-R-U-THERE")
|
||||
wmbs := bytes.SplitAfter(data, []byte("-"))
|
||||
wms := []socket.Message{
|
||||
{Buffers: wmbs[:1], Addr: c.LocalAddr()},
|
||||
{Buffers: wmbs[1:], Addr: c.LocalAddr()},
|
||||
}
|
||||
n, err := cc.SendMsgs(wms, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != len(wms) {
|
||||
t.Fatalf("got %d; want %d", n, len(wms))
|
||||
}
|
||||
b := make([]byte, 32)
|
||||
rmbs := [][][]byte{{b[:len(wmbs[0])]}, {b[len(wmbs[0]):]}}
|
||||
rms := []socket.Message{
|
||||
{Buffers: rmbs[0]},
|
||||
{Buffers: rmbs[1]},
|
||||
}
|
||||
n, err = cc.RecvMsgs(rms, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != len(rms) {
|
||||
t.Fatalf("got %d; want %d", n, len(rms))
|
||||
}
|
||||
nn := 0
|
||||
for i := 0; i < n; i++ {
|
||||
nn += rms[i].N
|
||||
}
|
||||
if !bytes.Equal(b[:nn], data) {
|
||||
t.Fatalf("got %#v; want %#v", b[:nn], data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// The behavior of transmission for zero byte paylaod depends
|
||||
// on each platform implementation. Some may transmit only
|
||||
// protocol header and options, other may transmit nothing.
|
||||
// We test only that SendMsg and SendMsgs will not crash with
|
||||
// empty buffers.
|
||||
data := []byte("HELLO-R-U-THERE")
|
||||
wm := socket.Message{
|
||||
Buffers: [][]byte{{}},
|
||||
Buffers: bytes.SplitAfter(data, []byte("-")),
|
||||
Addr: c.LocalAddr(),
|
||||
}
|
||||
cc.SendMsg(&wm, 0)
|
||||
wms := []socket.Message{
|
||||
{Buffers: [][]byte{{}}, Addr: c.LocalAddr()},
|
||||
if err := cc.SendMsg(&wm, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b := make([]byte, 32)
|
||||
rm := socket.Message{
|
||||
Buffers: [][]byte{b[:1], b[1:3], b[3:7], b[7:11], b[11:]},
|
||||
}
|
||||
if err := cc.RecvMsg(&rm, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b[:rm.N], data) {
|
||||
t.Fatalf("got %#v; want %#v", b[:rm.N], data)
|
||||
}
|
||||
}
|
||||
|
||||
func testUDPMessages(t *testing.T, c net.Conn) {
|
||||
cc, err := socket.NewConn(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data := []byte("HELLO-R-U-THERE")
|
||||
wmbs := bytes.SplitAfter(data, []byte("-"))
|
||||
wms := []socket.Message{
|
||||
{Buffers: wmbs[:1], Addr: c.LocalAddr()},
|
||||
{Buffers: wmbs[1:], Addr: c.LocalAddr()},
|
||||
}
|
||||
n, err := cc.SendMsgs(wms, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != len(wms) {
|
||||
t.Fatalf("got %d; want %d", n, len(wms))
|
||||
}
|
||||
b := make([]byte, 32)
|
||||
rmbs := [][][]byte{{b[:len(wmbs[0])]}, {b[len(wmbs[0]):]}}
|
||||
rms := []socket.Message{
|
||||
{Buffers: rmbs[0]},
|
||||
{Buffers: rmbs[1]},
|
||||
}
|
||||
n, err = cc.RecvMsgs(rms, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != len(rms) {
|
||||
t.Fatalf("got %d; want %d", n, len(rms))
|
||||
}
|
||||
nn := 0
|
||||
for i := 0; i < n; i++ {
|
||||
nn += rms[i].N
|
||||
}
|
||||
if !bytes.Equal(b[:nn], data) {
|
||||
t.Fatalf("got %#v; want %#v", b[:nn], data)
|
||||
}
|
||||
cc.SendMsgs(wms, 0)
|
||||
}
|
||||
|
||||
func BenchmarkUDP(b *testing.B) {
|
||||
@@ -233,7 +230,7 @@ func BenchmarkUDP(b *testing.B) {
|
||||
}
|
||||
})
|
||||
switch runtime.GOOS {
|
||||
case "android", "linux":
|
||||
case "linux":
|
||||
wms := make([]socket.Message, M)
|
||||
for i := range wms {
|
||||
wms[i].Buffers = [][]byte{data}
|
||||
|
||||
6
vendor/golang.org/x/net/internal/socket/sys_posix.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/sys_posix.go
generated
vendored
@@ -34,7 +34,7 @@ func marshalSockaddr(ip net.IP, port int, zone string) []byte {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
b := make([]byte, sizeofSockaddrInet)
|
||||
switch runtime.GOOS {
|
||||
case "android", "linux", "solaris", "windows":
|
||||
case "linux", "solaris", "windows":
|
||||
NativeEndian.PutUint16(b[:2], uint16(sysAF_INET))
|
||||
default:
|
||||
b[0] = sizeofSockaddrInet
|
||||
@@ -47,7 +47,7 @@ func marshalSockaddr(ip net.IP, port int, zone string) []byte {
|
||||
if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
|
||||
b := make([]byte, sizeofSockaddrInet6)
|
||||
switch runtime.GOOS {
|
||||
case "android", "linux", "solaris", "windows":
|
||||
case "linux", "solaris", "windows":
|
||||
NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6))
|
||||
default:
|
||||
b[0] = sizeofSockaddrInet6
|
||||
@@ -69,7 +69,7 @@ func parseInetAddr(b []byte, network string) (net.Addr, error) {
|
||||
}
|
||||
var af int
|
||||
switch runtime.GOOS {
|
||||
case "android", "linux", "solaris", "windows":
|
||||
case "linux", "solaris", "windows":
|
||||
af = int(NativeEndian.Uint16(b[:2]))
|
||||
default:
|
||||
af = int(b[1])
|
||||
|
||||
61
vendor/golang.org/x/net/internal/socket/zsys_darwin_arm64.go
generated
vendored
61
vendor/golang.org/x/net/internal/socket/zsys_darwin_arm64.go
generated
vendored
@@ -1,61 +0,0 @@
|
||||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs defs_darwin.go
|
||||
|
||||
package socket
|
||||
|
||||
const (
|
||||
sysAF_UNSPEC = 0x0
|
||||
sysAF_INET = 0x2
|
||||
sysAF_INET6 = 0x1e
|
||||
|
||||
sysSOCK_RAW = 0x3
|
||||
)
|
||||
|
||||
type iovec struct {
|
||||
Base *byte
|
||||
Len uint64
|
||||
}
|
||||
|
||||
type msghdr struct {
|
||||
Name *byte
|
||||
Namelen uint32
|
||||
Pad_cgo_0 [4]byte
|
||||
Iov *iovec
|
||||
Iovlen int32
|
||||
Pad_cgo_1 [4]byte
|
||||
Control *byte
|
||||
Controllen uint32
|
||||
Flags int32
|
||||
}
|
||||
|
||||
type cmsghdr struct {
|
||||
Len uint32
|
||||
Level int32
|
||||
Type int32
|
||||
}
|
||||
|
||||
type sockaddrInet struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Port uint16
|
||||
Addr [4]byte /* in_addr */
|
||||
Zero [8]int8
|
||||
}
|
||||
|
||||
type sockaddrInet6 struct {
|
||||
Len uint8
|
||||
Family uint8
|
||||
Port uint16
|
||||
Flowinfo uint32
|
||||
Addr [16]byte /* in6_addr */
|
||||
Scope_id uint32
|
||||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x30
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
sizeofSockaddrInet6 = 0x1c
|
||||
)
|
||||
6
vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm.go
generated
vendored
6
vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm.go
generated
vendored
@@ -26,11 +26,6 @@ type msghdr struct {
|
||||
Flags int32
|
||||
}
|
||||
|
||||
type mmsghdr struct {
|
||||
Hdr msghdr
|
||||
Len uint32
|
||||
}
|
||||
|
||||
type cmsghdr struct {
|
||||
Len uint32
|
||||
Level int32
|
||||
@@ -57,7 +52,6 @@ type sockaddrInet6 struct {
|
||||
const (
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
sizeofMmsghdr = 0x20
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
||||
168
vendor/golang.org/x/net/internal/socks/client.go
generated
vendored
168
vendor/golang.org/x/net/internal/socks/client.go
generated
vendored
@@ -1,168 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
158
vendor/golang.org/x/net/internal/socks/dial_test.go
generated
vendored
158
vendor/golang.org/x/net/internal/socks/dial_test.go
generated
vendored
@@ -1,158 +0,0 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/internal/socks"
|
||||
"golang.org/x/net/internal/sockstest"
|
||||
)
|
||||
|
||||
const (
|
||||
targetNetwork = "tcp6"
|
||||
targetHostname = "fqdn.doesnotexist"
|
||||
targetHostIP = "2001:db8::1"
|
||||
targetPort = "5963"
|
||||
)
|
||||
|
||||
func TestDial(t *testing.T) {
|
||||
t.Run("Connect", func(t *testing.T) {
|
||||
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
defer ss.Close()
|
||||
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
|
||||
d.AuthMethods = []socks.AuthMethod{
|
||||
socks.AuthMethodNotRequired,
|
||||
socks.AuthMethodUsernamePassword,
|
||||
}
|
||||
d.Authenticate = (&socks.UsernamePassword{
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
}).Authenticate
|
||||
c, err := d.Dial(targetNetwork, net.JoinHostPort(targetHostIP, targetPort))
|
||||
if err == nil {
|
||||
c.(*socks.Conn).BoundAddr()
|
||||
c.Close()
|
||||
}
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
})
|
||||
t.Run("Cancel", func(t *testing.T) {
|
||||
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
defer ss.Close()
|
||||
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
dialErr := make(chan error)
|
||||
go func() {
|
||||
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), net.JoinHostPort(targetHostname, targetPort))
|
||||
if err == nil {
|
||||
c.Close()
|
||||
}
|
||||
dialErr <- err
|
||||
}()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
cancel()
|
||||
err = <-dialErr
|
||||
if perr, nerr := parseDialError(err); perr != context.Canceled && nerr == nil {
|
||||
t.Errorf("got %v; want context.Canceled or equivalent", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
t.Run("Deadline", func(t *testing.T) {
|
||||
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
defer ss.Close()
|
||||
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
|
||||
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
|
||||
defer cancel()
|
||||
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), net.JoinHostPort(targetHostname, targetPort))
|
||||
if err == nil {
|
||||
c.Close()
|
||||
}
|
||||
if perr, nerr := parseDialError(err); perr != context.DeadlineExceeded && nerr == nil {
|
||||
t.Errorf("got %v; want context.DeadlineExceeded or equivalent", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
t.Run("WithRogueServer", func(t *testing.T) {
|
||||
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, rogueCmdFunc)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
defer ss.Close()
|
||||
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
|
||||
for i := 0; i < 2*len(rogueCmdList); i++ {
|
||||
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
|
||||
defer cancel()
|
||||
c, err := d.DialContext(ctx, targetNetwork, net.JoinHostPort(targetHostIP, targetPort))
|
||||
if err == nil {
|
||||
t.Log(c.(*socks.Conn).BoundAddr())
|
||||
c.Close()
|
||||
t.Error("should fail")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func blackholeCmdFunc(rw io.ReadWriter, b []byte) error {
|
||||
if _, err := sockstest.ParseCmdRequest(b); err != nil {
|
||||
return err
|
||||
}
|
||||
var bb [1]byte
|
||||
for {
|
||||
if _, err := rw.Read(bb[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func rogueCmdFunc(rw io.ReadWriter, b []byte) error {
|
||||
if _, err := sockstest.ParseCmdRequest(b); err != nil {
|
||||
return err
|
||||
}
|
||||
rw.Write(rogueCmdList[rand.Intn(len(rogueCmdList))])
|
||||
return nil
|
||||
}
|
||||
|
||||
var rogueCmdList = [][]byte{
|
||||
{0x05},
|
||||
{0x06, 0x00, 0x00, 0x01, 192, 0, 2, 1, 0x17, 0x4b},
|
||||
{0x05, 0x00, 0xff, 0x01, 192, 0, 2, 2, 0x17, 0x4b},
|
||||
{0x05, 0x00, 0x00, 0x01, 192, 0, 2, 3},
|
||||
{0x05, 0x00, 0x00, 0x03, 0x04, 'F', 'Q', 'D', 'N'},
|
||||
}
|
||||
|
||||
func parseDialError(err error) (perr, nerr error) {
|
||||
if e, ok := err.(*net.OpError); ok {
|
||||
err = e.Err
|
||||
nerr = e
|
||||
}
|
||||
if e, ok := err.(*os.SyscallError); ok {
|
||||
err = e.Err
|
||||
}
|
||||
perr = err
|
||||
return
|
||||
}
|
||||
265
vendor/golang.org/x/net/internal/socks/socks.go
generated
vendored
265
vendor/golang.org/x/net/internal/socks/socks.go
generated
vendored
@@ -1,265 +0,0 @@
|
||||
// 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 authetication 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) {
|
||||
switch network {
|
||||
case "tcp", "tcp6", "tcp4":
|
||||
default:
|
||||
proxy, dst, _ := d.pathAddrs(address)
|
||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("network not implemented")}
|
||||
}
|
||||
switch d.cmd {
|
||||
case CmdConnect, cmdBind:
|
||||
default:
|
||||
proxy, dst, _ := d.pathAddrs(address)
|
||||
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("command not implemented")}
|
||||
}
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// Dial connects to the provided address on the provided network.
|
||||
//
|
||||
// Deprecated: Use DialContext instead.
|
||||
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
|
||||
return d.DialContext(context.Background(), network, address)
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
241
vendor/golang.org/x/net/internal/sockstest/server.go
generated
vendored
241
vendor/golang.org/x/net/internal/sockstest/server.go
generated
vendored
@@ -1,241 +0,0 @@
|
||||
// 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 sockstest provides utilities for SOCKS testing.
|
||||
package sockstest
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"golang.org/x/net/internal/nettest"
|
||||
"golang.org/x/net/internal/socks"
|
||||
)
|
||||
|
||||
// An AuthRequest represents an authentication request.
|
||||
type AuthRequest struct {
|
||||
Version int
|
||||
Methods []socks.AuthMethod
|
||||
}
|
||||
|
||||
// ParseAuthRequest parses an authentication request.
|
||||
func ParseAuthRequest(b []byte) (*AuthRequest, error) {
|
||||
if len(b) < 2 {
|
||||
return nil, errors.New("short auth request")
|
||||
}
|
||||
if b[0] != socks.Version5 {
|
||||
return nil, errors.New("unexpected protocol version")
|
||||
}
|
||||
if len(b)-2 < int(b[1]) {
|
||||
return nil, errors.New("short auth request")
|
||||
}
|
||||
req := &AuthRequest{Version: int(b[0])}
|
||||
if b[1] > 0 {
|
||||
req.Methods = make([]socks.AuthMethod, b[1])
|
||||
for i, m := range b[2 : 2+b[1]] {
|
||||
req.Methods[i] = socks.AuthMethod(m)
|
||||
}
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// MarshalAuthReply returns an authentication reply in wire format.
|
||||
func MarshalAuthReply(ver int, m socks.AuthMethod) ([]byte, error) {
|
||||
return []byte{byte(ver), byte(m)}, nil
|
||||
}
|
||||
|
||||
// A CmdRequest repesents a command request.
|
||||
type CmdRequest struct {
|
||||
Version int
|
||||
Cmd socks.Command
|
||||
Addr socks.Addr
|
||||
}
|
||||
|
||||
// ParseCmdRequest parses a command request.
|
||||
func ParseCmdRequest(b []byte) (*CmdRequest, error) {
|
||||
if len(b) < 7 {
|
||||
return nil, errors.New("short cmd request")
|
||||
}
|
||||
if b[0] != socks.Version5 {
|
||||
return nil, errors.New("unexpected protocol version")
|
||||
}
|
||||
if socks.Command(b[1]) != socks.CmdConnect {
|
||||
return nil, errors.New("unexpected command")
|
||||
}
|
||||
if b[2] != 0 {
|
||||
return nil, errors.New("non-zero reserved field")
|
||||
}
|
||||
req := &CmdRequest{Version: int(b[0]), Cmd: socks.Command(b[1])}
|
||||
l := 2
|
||||
off := 4
|
||||
switch b[3] {
|
||||
case socks.AddrTypeIPv4:
|
||||
l += net.IPv4len
|
||||
req.Addr.IP = make(net.IP, net.IPv4len)
|
||||
case socks.AddrTypeIPv6:
|
||||
l += net.IPv6len
|
||||
req.Addr.IP = make(net.IP, net.IPv6len)
|
||||
case socks.AddrTypeFQDN:
|
||||
l += int(b[4])
|
||||
off = 5
|
||||
default:
|
||||
return nil, errors.New("unknown address type")
|
||||
}
|
||||
if len(b[off:]) < l {
|
||||
return nil, errors.New("short cmd request")
|
||||
}
|
||||
if req.Addr.IP != nil {
|
||||
copy(req.Addr.IP, b[off:])
|
||||
} else {
|
||||
req.Addr.Name = string(b[off : off+l-2])
|
||||
}
|
||||
req.Addr.Port = int(b[off+l-2])<<8 | int(b[off+l-1])
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// MarshalCmdReply returns a command reply in wire format.
|
||||
func MarshalCmdReply(ver int, reply socks.Reply, a *socks.Addr) ([]byte, error) {
|
||||
b := make([]byte, 4)
|
||||
b[0] = byte(ver)
|
||||
b[1] = byte(reply)
|
||||
if a.Name != "" {
|
||||
if len(a.Name) > 255 {
|
||||
return nil, errors.New("fqdn too long")
|
||||
}
|
||||
b[3] = socks.AddrTypeFQDN
|
||||
b = append(b, byte(len(a.Name)))
|
||||
b = append(b, a.Name...)
|
||||
} else if ip4 := a.IP.To4(); ip4 != nil {
|
||||
b[3] = socks.AddrTypeIPv4
|
||||
b = append(b, ip4...)
|
||||
} else if ip6 := a.IP.To16(); ip6 != nil {
|
||||
b[3] = socks.AddrTypeIPv6
|
||||
b = append(b, ip6...)
|
||||
} else {
|
||||
return nil, errors.New("unknown address type")
|
||||
}
|
||||
b = append(b, byte(a.Port>>8), byte(a.Port))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// A Server repesents a server for handshake testing.
|
||||
type Server struct {
|
||||
ln net.Listener
|
||||
}
|
||||
|
||||
// Addr rerurns a server address.
|
||||
func (s *Server) Addr() net.Addr {
|
||||
return s.ln.Addr()
|
||||
}
|
||||
|
||||
// TargetAddr returns a fake final destination address.
|
||||
//
|
||||
// The returned address is only valid for testing with Server.
|
||||
func (s *Server) TargetAddr() net.Addr {
|
||||
a := s.ln.Addr()
|
||||
switch a := a.(type) {
|
||||
case *net.TCPAddr:
|
||||
if a.IP.To4() != nil {
|
||||
return &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 5963}
|
||||
}
|
||||
if a.IP.To16() != nil && a.IP.To4() == nil {
|
||||
return &net.TCPAddr{IP: net.IPv6loopback, Port: 5963}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the server.
|
||||
func (s *Server) Close() error {
|
||||
return s.ln.Close()
|
||||
}
|
||||
|
||||
func (s *Server) serve(authFunc, cmdFunc func(io.ReadWriter, []byte) error) {
|
||||
c, err := s.ln.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
go s.serve(authFunc, cmdFunc)
|
||||
b := make([]byte, 512)
|
||||
n, err := c.Read(b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err := authFunc(c, b[:n]); err != nil {
|
||||
return
|
||||
}
|
||||
n, err = c.Read(b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err := cmdFunc(c, b[:n]); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// NewServer returns a new server.
|
||||
//
|
||||
// The provided authFunc and cmdFunc must parse requests and return
|
||||
// appropriate replies to clients.
|
||||
func NewServer(authFunc, cmdFunc func(io.ReadWriter, []byte) error) (*Server, error) {
|
||||
var err error
|
||||
s := new(Server)
|
||||
s.ln, err = nettest.NewLocalListener("tcp")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go s.serve(authFunc, cmdFunc)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// NoAuthRequired handles a no-authentication-required signaling.
|
||||
func NoAuthRequired(rw io.ReadWriter, b []byte) error {
|
||||
req, err := ParseAuthRequest(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err = MarshalAuthReply(req.Version, socks.AuthMethodNotRequired)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := rw.Write(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(b) {
|
||||
return errors.New("short write")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NoProxyRequired handles a command signaling without constructing a
|
||||
// proxy connection to the final destination.
|
||||
func NoProxyRequired(rw io.ReadWriter, b []byte) error {
|
||||
req, err := ParseCmdRequest(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Addr.Port += 1
|
||||
if req.Addr.Name != "" {
|
||||
req.Addr.Name = "boundaddr.doesnotexist"
|
||||
} else if req.Addr.IP.To4() != nil {
|
||||
req.Addr.IP = net.IPv4(127, 0, 0, 1)
|
||||
} else {
|
||||
req.Addr.IP = net.IPv6loopback
|
||||
}
|
||||
b, err = MarshalCmdReply(socks.Version5, socks.StatusSucceeded, &req.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := rw.Write(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(b) {
|
||||
return errors.New("short write")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
103
vendor/golang.org/x/net/internal/sockstest/server_test.go
generated
vendored
103
vendor/golang.org/x/net/internal/sockstest/server_test.go
generated
vendored
@@ -1,103 +0,0 @@
|
||||
// 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 sockstest
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/internal/socks"
|
||||
)
|
||||
|
||||
func TestParseAuthRequest(t *testing.T) {
|
||||
for i, tt := range []struct {
|
||||
wire []byte
|
||||
req *AuthRequest
|
||||
}{
|
||||
{
|
||||
[]byte{0x05, 0x00},
|
||||
&AuthRequest{
|
||||
socks.Version5,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
[]byte{0x05, 0x01, 0xff},
|
||||
&AuthRequest{
|
||||
socks.Version5,
|
||||
[]socks.AuthMethod{
|
||||
socks.AuthMethodNoAcceptableMethods,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
[]byte{0x05, 0x02, 0x00, 0xff},
|
||||
&AuthRequest{
|
||||
socks.Version5,
|
||||
[]socks.AuthMethod{
|
||||
socks.AuthMethodNotRequired,
|
||||
socks.AuthMethodNoAcceptableMethods,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// corrupted requests
|
||||
{nil, nil},
|
||||
{[]byte{0x00, 0x01}, nil},
|
||||
{[]byte{0x06, 0x00}, nil},
|
||||
{[]byte{0x05, 0x02, 0x00}, nil},
|
||||
} {
|
||||
req, err := ParseAuthRequest(tt.wire)
|
||||
if !reflect.DeepEqual(req, tt.req) {
|
||||
t.Errorf("#%d: got %v, %v; want %v", i, req, err, tt.req)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCmdRequest(t *testing.T) {
|
||||
for i, tt := range []struct {
|
||||
wire []byte
|
||||
req *CmdRequest
|
||||
}{
|
||||
{
|
||||
[]byte{0x05, 0x01, 0x00, 0x01, 192, 0, 2, 1, 0x17, 0x4b},
|
||||
&CmdRequest{
|
||||
socks.Version5,
|
||||
socks.CmdConnect,
|
||||
socks.Addr{
|
||||
IP: net.IP{192, 0, 2, 1},
|
||||
Port: 5963,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
[]byte{0x05, 0x01, 0x00, 0x03, 0x04, 'F', 'Q', 'D', 'N', 0x17, 0x4b},
|
||||
&CmdRequest{
|
||||
socks.Version5,
|
||||
socks.CmdConnect,
|
||||
socks.Addr{
|
||||
Name: "FQDN",
|
||||
Port: 5963,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// corrupted requests
|
||||
{nil, nil},
|
||||
{[]byte{0x05}, nil},
|
||||
{[]byte{0x06, 0x01, 0x00, 0x01, 192, 0, 2, 2, 0x17, 0x4b}, nil},
|
||||
{[]byte{0x05, 0x01, 0xff, 0x01, 192, 0, 2, 3}, nil},
|
||||
{[]byte{0x05, 0x01, 0x00, 0x01, 192, 0, 2, 4}, nil},
|
||||
{[]byte{0x05, 0x01, 0x00, 0x03, 0x04, 'F', 'Q', 'D', 'N'}, nil},
|
||||
} {
|
||||
req, err := ParseCmdRequest(tt.wire)
|
||||
if !reflect.DeepEqual(req, tt.req) {
|
||||
t.Errorf("#%d: got %v, %v; want %v", i, req, err, tt.req)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
4
vendor/golang.org/x/net/ipv4/gen.go
generated
vendored
4
vendor/golang.org/x/net/ipv4/gen.go
generated
vendored
@@ -72,7 +72,7 @@ var registries = []struct {
|
||||
parse func(io.Writer, io.Reader) error
|
||||
}{
|
||||
{
|
||||
"https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml",
|
||||
"http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml",
|
||||
parseICMPv4Parameters,
|
||||
},
|
||||
}
|
||||
@@ -80,7 +80,7 @@ var registries = []struct {
|
||||
func geniana() error {
|
||||
var bb bytes.Buffer
|
||||
fmt.Fprintf(&bb, "// go generate gen.go\n")
|
||||
fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
|
||||
fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
|
||||
fmt.Fprintf(&bb, "package ipv4\n\n")
|
||||
for _, r := range registries {
|
||||
resp, err := http.Get(r.url)
|
||||
|
||||
2
vendor/golang.org/x/net/ipv4/header.go
generated
vendored
2
vendor/golang.org/x/net/ipv4/header.go
generated
vendored
@@ -98,7 +98,7 @@ func (h *Header) Marshal() ([]byte, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Parse parses b as an IPv4 header and stores the result in h.
|
||||
// Parse parses b as an IPv4 header and sotres the result in h.
|
||||
func (h *Header) Parse(b []byte) error {
|
||||
if h == nil || len(b) < HeaderLen {
|
||||
return errHeaderTooShort
|
||||
|
||||
10
vendor/golang.org/x/net/ipv4/iana.go
generated
vendored
10
vendor/golang.org/x/net/ipv4/iana.go
generated
vendored
@@ -1,9 +1,9 @@
|
||||
// go generate gen.go
|
||||
// Code generated by the command above; DO NOT EDIT.
|
||||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package ipv4
|
||||
|
||||
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2018-02-26
|
||||
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19
|
||||
const (
|
||||
ICMPTypeEchoReply ICMPType = 0 // Echo Reply
|
||||
ICMPTypeDestinationUnreachable ICMPType = 3 // Destination Unreachable
|
||||
@@ -16,11 +16,9 @@ const (
|
||||
ICMPTypeTimestamp ICMPType = 13 // Timestamp
|
||||
ICMPTypeTimestampReply ICMPType = 14 // Timestamp Reply
|
||||
ICMPTypePhoturis ICMPType = 40 // Photuris
|
||||
ICMPTypeExtendedEchoRequest ICMPType = 42 // Extended Echo Request
|
||||
ICMPTypeExtendedEchoReply ICMPType = 43 // Extended Echo Reply
|
||||
)
|
||||
|
||||
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2018-02-26
|
||||
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19
|
||||
var icmpTypes = map[ICMPType]string{
|
||||
0: "echo reply",
|
||||
3: "destination unreachable",
|
||||
@@ -33,6 +31,4 @@ var icmpTypes = map[ICMPType]string{
|
||||
13: "timestamp",
|
||||
14: "timestamp reply",
|
||||
40: "photuris",
|
||||
42: "extended echo request",
|
||||
43: "extended echo reply",
|
||||
}
|
||||
|
||||
4
vendor/golang.org/x/net/ipv6/gen.go
generated
vendored
4
vendor/golang.org/x/net/ipv6/gen.go
generated
vendored
@@ -72,7 +72,7 @@ var registries = []struct {
|
||||
parse func(io.Writer, io.Reader) error
|
||||
}{
|
||||
{
|
||||
"https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml",
|
||||
"http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml",
|
||||
parseICMPv6Parameters,
|
||||
},
|
||||
}
|
||||
@@ -80,7 +80,7 @@ var registries = []struct {
|
||||
func geniana() error {
|
||||
var bb bytes.Buffer
|
||||
fmt.Fprintf(&bb, "// go generate gen.go\n")
|
||||
fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
|
||||
fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
|
||||
fmt.Fprintf(&bb, "package ipv6\n\n")
|
||||
for _, r := range registries {
|
||||
resp, err := http.Get(r.url)
|
||||
|
||||
10
vendor/golang.org/x/net/ipv6/iana.go
generated
vendored
10
vendor/golang.org/x/net/ipv6/iana.go
generated
vendored
@@ -1,9 +1,9 @@
|
||||
// go generate gen.go
|
||||
// Code generated by the command above; DO NOT EDIT.
|
||||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
package ipv6
|
||||
|
||||
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2018-03-09
|
||||
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2015-07-07
|
||||
const (
|
||||
ICMPTypeDestinationUnreachable ICMPType = 1 // Destination Unreachable
|
||||
ICMPTypePacketTooBig ICMPType = 2 // Packet Too Big
|
||||
@@ -40,11 +40,9 @@ const (
|
||||
ICMPTypeDuplicateAddressRequest ICMPType = 157 // Duplicate Address Request
|
||||
ICMPTypeDuplicateAddressConfirmation ICMPType = 158 // Duplicate Address Confirmation
|
||||
ICMPTypeMPLControl ICMPType = 159 // MPL Control Message
|
||||
ICMPTypeExtendedEchoRequest ICMPType = 160 // Extended Echo Request
|
||||
ICMPTypeExtendedEchoReply ICMPType = 161 // Extended Echo Reply
|
||||
)
|
||||
|
||||
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2018-03-09
|
||||
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2015-07-07
|
||||
var icmpTypes = map[ICMPType]string{
|
||||
1: "destination unreachable",
|
||||
2: "packet too big",
|
||||
@@ -81,6 +79,4 @@ var icmpTypes = map[ICMPType]string{
|
||||
157: "duplicate address request",
|
||||
158: "duplicate address confirmation",
|
||||
159: "mpl control message",
|
||||
160: "extended echo request",
|
||||
161: "extended echo reply",
|
||||
}
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package httpguts
|
||||
// Package httplex contains rules around lexical matters of various
|
||||
// HTTP-related specifications.
|
||||
//
|
||||
// This package is shared by the standard library (which vendors it)
|
||||
// and x/net/http2. It comes with no API stability promise.
|
||||
package httplex
|
||||
|
||||
import (
|
||||
"net"
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package httpguts
|
||||
package httplex
|
||||
|
||||
import (
|
||||
"testing"
|
||||
36
vendor/golang.org/x/net/netutil/listen.go
generated
vendored
36
vendor/golang.org/x/net/netutil/listen.go
generated
vendored
@@ -14,53 +14,27 @@ import (
|
||||
// LimitListener returns a Listener that accepts at most n simultaneous
|
||||
// connections from the provided Listener.
|
||||
func LimitListener(l net.Listener, n int) net.Listener {
|
||||
return &limitListener{
|
||||
Listener: l,
|
||||
sem: make(chan struct{}, n),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
return &limitListener{l, make(chan struct{}, n)}
|
||||
}
|
||||
|
||||
type limitListener struct {
|
||||
net.Listener
|
||||
sem chan struct{}
|
||||
closeOnce sync.Once // ensures the done chan is only closed once
|
||||
done chan struct{} // no values sent; closed when Close is called
|
||||
sem chan struct{}
|
||||
}
|
||||
|
||||
// acquire acquires the limiting semaphore. Returns true if successfully
|
||||
// accquired, false if the listener is closed and the semaphore is not
|
||||
// acquired.
|
||||
func (l *limitListener) acquire() bool {
|
||||
select {
|
||||
case <-l.done:
|
||||
return false
|
||||
case l.sem <- struct{}{}:
|
||||
return true
|
||||
}
|
||||
}
|
||||
func (l *limitListener) acquire() { l.sem <- struct{}{} }
|
||||
func (l *limitListener) release() { <-l.sem }
|
||||
|
||||
func (l *limitListener) Accept() (net.Conn, error) {
|
||||
acquired := l.acquire()
|
||||
// If the semaphore isn't acquired because the listener was closed, expect
|
||||
// that this call to accept won't block, but immediately return an error.
|
||||
l.acquire()
|
||||
c, err := l.Listener.Accept()
|
||||
if err != nil {
|
||||
if acquired {
|
||||
l.release()
|
||||
}
|
||||
l.release()
|
||||
return nil, err
|
||||
}
|
||||
return &limitListenerConn{Conn: c, release: l.release}, nil
|
||||
}
|
||||
|
||||
func (l *limitListener) Close() error {
|
||||
err := l.Listener.Close()
|
||||
l.closeOnce.Do(func() { close(l.done) })
|
||||
return err
|
||||
}
|
||||
|
||||
type limitListenerConn struct {
|
||||
net.Conn
|
||||
releaseOnce sync.Once
|
||||
|
||||
46
vendor/golang.org/x/net/netutil/listen_test.go
generated
vendored
46
vendor/golang.org/x/net/netutil/listen_test.go
generated
vendored
@@ -99,49 +99,3 @@ func TestLimitListenerError(t *testing.T) {
|
||||
t.Fatal("timeout. deadlock?")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimitListenerClose(t *testing.T) {
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
ln = LimitListener(ln, 1)
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
defer close(doneCh)
|
||||
go func() {
|
||||
c, err := net.Dial("tcp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
<-doneCh
|
||||
}()
|
||||
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
acceptDone := make(chan struct{})
|
||||
go func() {
|
||||
c, err := ln.Accept()
|
||||
if err == nil {
|
||||
c.Close()
|
||||
t.Errorf("Unexpected successful Accept()")
|
||||
}
|
||||
close(acceptDone)
|
||||
}()
|
||||
|
||||
// Wait a tiny bit to ensure the Accept() is blocking.
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
ln.Close()
|
||||
|
||||
select {
|
||||
case <-acceptDone:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("Accept() still blocking")
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/net/proxy/per_host.go
generated
vendored
2
vendor/golang.org/x/net/proxy/per_host.go
generated
vendored
@@ -61,7 +61,7 @@ func (p *PerHost) dialerForRequest(host string) Dialer {
|
||||
return p.bypass
|
||||
}
|
||||
if host == zone[1:] {
|
||||
// For a zone ".example.com", we match "example.com"
|
||||
// For a zone "example.com", we match "example.com"
|
||||
// too.
|
||||
return p.bypass
|
||||
}
|
||||
|
||||
132
vendor/golang.org/x/net/proxy/proxy_test.go
generated
vendored
132
vendor/golang.org/x/net/proxy/proxy_test.go
generated
vendored
@@ -7,12 +7,14 @@ package proxy
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/internal/sockstest"
|
||||
)
|
||||
|
||||
type proxyFromEnvTest struct {
|
||||
@@ -71,41 +73,131 @@ func TestFromEnvironment(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFromURL(t *testing.T) {
|
||||
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
|
||||
endSystem, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("net.Listen failed: %v", err)
|
||||
}
|
||||
defer ss.Close()
|
||||
url, err := url.Parse("socks5://user:password@" + ss.Addr().String())
|
||||
defer endSystem.Close()
|
||||
gateway, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("net.Listen failed: %v", err)
|
||||
}
|
||||
proxy, err := FromURL(url, nil)
|
||||
defer gateway.Close()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go socks5Gateway(t, gateway, endSystem, socks5Domain, &wg)
|
||||
|
||||
url, err := url.Parse("socks5://user:password@" + gateway.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("url.Parse failed: %v", err)
|
||||
}
|
||||
c, err := proxy.Dial("tcp", "fqdn.doesnotexist:5963")
|
||||
proxy, err := FromURL(url, Direct)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("FromURL failed: %v", err)
|
||||
}
|
||||
c.Close()
|
||||
_, port, err := net.SplitHostPort(endSystem.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatalf("net.SplitHostPort failed: %v", err)
|
||||
}
|
||||
if c, err := proxy.Dial("tcp", "localhost:"+port); err != nil {
|
||||
t.Fatalf("FromURL.Dial failed: %v", err)
|
||||
} else {
|
||||
c.Close()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestSOCKS5(t *testing.T) {
|
||||
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
|
||||
endSystem, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("net.Listen failed: %v", err)
|
||||
}
|
||||
defer ss.Close()
|
||||
proxy, err := SOCKS5("tcp", ss.Addr().String(), nil, nil)
|
||||
defer endSystem.Close()
|
||||
gateway, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("net.Listen failed: %v", err)
|
||||
}
|
||||
c, err := proxy.Dial("tcp", ss.TargetAddr().String())
|
||||
defer gateway.Close()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go socks5Gateway(t, gateway, endSystem, socks5IP4, &wg)
|
||||
|
||||
proxy, err := SOCKS5("tcp", gateway.Addr().String(), nil, Direct)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("SOCKS5 failed: %v", err)
|
||||
}
|
||||
if c, err := proxy.Dial("tcp", endSystem.Addr().String()); err != nil {
|
||||
t.Fatalf("SOCKS5.Dial failed: %v", err)
|
||||
} else {
|
||||
c.Close()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func socks5Gateway(t *testing.T, gateway, endSystem net.Listener, typ byte, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
c, err := gateway.Accept()
|
||||
if err != nil {
|
||||
t.Errorf("net.Listener.Accept failed: %v", err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b := make([]byte, 32)
|
||||
var n int
|
||||
if typ == socks5Domain {
|
||||
n = 4
|
||||
} else {
|
||||
n = 3
|
||||
}
|
||||
if _, err := io.ReadFull(c, b[:n]); err != nil {
|
||||
t.Errorf("io.ReadFull failed: %v", err)
|
||||
return
|
||||
}
|
||||
if _, err := c.Write([]byte{socks5Version, socks5AuthNone}); err != nil {
|
||||
t.Errorf("net.Conn.Write failed: %v", err)
|
||||
return
|
||||
}
|
||||
if typ == socks5Domain {
|
||||
n = 16
|
||||
} else {
|
||||
n = 10
|
||||
}
|
||||
if _, err := io.ReadFull(c, b[:n]); err != nil {
|
||||
t.Errorf("io.ReadFull failed: %v", err)
|
||||
return
|
||||
}
|
||||
if b[0] != socks5Version || b[1] != socks5Connect || b[2] != 0x00 || b[3] != typ {
|
||||
t.Errorf("got an unexpected packet: %#02x %#02x %#02x %#02x", b[0], b[1], b[2], b[3])
|
||||
return
|
||||
}
|
||||
if typ == socks5Domain {
|
||||
copy(b[:5], []byte{socks5Version, 0x00, 0x00, socks5Domain, 9})
|
||||
b = append(b, []byte("localhost")...)
|
||||
} else {
|
||||
copy(b[:4], []byte{socks5Version, 0x00, 0x00, socks5IP4})
|
||||
}
|
||||
host, port, err := net.SplitHostPort(endSystem.Addr().String())
|
||||
if err != nil {
|
||||
t.Errorf("net.SplitHostPort failed: %v", err)
|
||||
return
|
||||
}
|
||||
b = append(b, []byte(net.ParseIP(host).To4())...)
|
||||
p, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
t.Errorf("strconv.Atoi failed: %v", err)
|
||||
return
|
||||
}
|
||||
b = append(b, []byte{byte(p >> 8), byte(p)}...)
|
||||
if _, err := c.Write(b); err != nil {
|
||||
t.Errorf("net.Conn.Write failed: %v", err)
|
||||
return
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func ResetProxyEnv() {
|
||||
|
||||
221
vendor/golang.org/x/net/proxy/socks5.go
generated
vendored
221
vendor/golang.org/x/net/proxy/socks5.go
generated
vendored
@@ -5,32 +5,209 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"golang.org/x/net/internal/socks"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
d.ProxyDial = func(_ context.Context, network string, address string) (net.Conn, error) {
|
||||
return forward.Dial(network, address)
|
||||
}
|
||||
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
|
||||
// with an optional username and password. See RFC 1928.
|
||||
func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) {
|
||||
s := &socks5{
|
||||
network: network,
|
||||
addr: addr,
|
||||
forward: forward,
|
||||
}
|
||||
if auth != nil {
|
||||
up := socks.UsernamePassword{
|
||||
Username: auth.User,
|
||||
Password: auth.Password,
|
||||
}
|
||||
d.AuthMethods = []socks.AuthMethod{
|
||||
socks.AuthMethodNotRequired,
|
||||
socks.AuthMethodUsernamePassword,
|
||||
}
|
||||
d.Authenticate = up.Authenticate
|
||||
s.user = auth.User
|
||||
s.password = auth.Password
|
||||
}
|
||||
return d, nil
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type socks5 struct {
|
||||
user, password string
|
||||
network, addr string
|
||||
forward Dialer
|
||||
}
|
||||
|
||||
const socks5Version = 5
|
||||
|
||||
const (
|
||||
socks5AuthNone = 0
|
||||
socks5AuthPassword = 2
|
||||
)
|
||||
|
||||
const socks5Connect = 1
|
||||
|
||||
const (
|
||||
socks5IP4 = 1
|
||||
socks5Domain = 3
|
||||
socks5IP6 = 4
|
||||
)
|
||||
|
||||
var socks5Errors = []string{
|
||||
"",
|
||||
"general failure",
|
||||
"connection forbidden",
|
||||
"network unreachable",
|
||||
"host unreachable",
|
||||
"connection refused",
|
||||
"TTL expired",
|
||||
"command not supported",
|
||||
"address type not supported",
|
||||
}
|
||||
|
||||
// Dial connects to the address addr on the network net via the SOCKS5 proxy.
|
||||
func (s *socks5) Dial(network, addr string) (net.Conn, error) {
|
||||
switch network {
|
||||
case "tcp", "tcp6", "tcp4":
|
||||
default:
|
||||
return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
|
||||
}
|
||||
|
||||
conn, err := s.forward.Dial(s.network, s.addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.connect(conn, addr); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// connect takes an existing connection to a socks5 proxy server,
|
||||
// and commands the server to extend that connection to target,
|
||||
// which must be a canonical address with a host and port.
|
||||
func (s *socks5) connect(conn net.Conn, target string) error {
|
||||
host, portStr, err := net.SplitHostPort(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return errors.New("proxy: failed to parse port number: " + portStr)
|
||||
}
|
||||
if port < 1 || port > 0xffff {
|
||||
return errors.New("proxy: port number out of range: " + portStr)
|
||||
}
|
||||
|
||||
// the size here is just an estimate
|
||||
buf := make([]byte, 0, 6+len(host))
|
||||
|
||||
buf = append(buf, socks5Version)
|
||||
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
|
||||
buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
|
||||
} else {
|
||||
buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
|
||||
}
|
||||
|
||||
if _, err := conn.Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
if buf[0] != 5 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
|
||||
}
|
||||
if buf[1] == 0xff {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
|
||||
}
|
||||
|
||||
if buf[1] == socks5AuthPassword {
|
||||
buf = buf[:0]
|
||||
buf = append(buf, 1 /* password protocol version */)
|
||||
buf = append(buf, uint8(len(s.user)))
|
||||
buf = append(buf, s.user...)
|
||||
buf = append(buf, uint8(len(s.password)))
|
||||
buf = append(buf, s.password...)
|
||||
|
||||
if _, err := conn.Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
|
||||
if buf[1] != 0 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
|
||||
}
|
||||
}
|
||||
|
||||
buf = buf[:0]
|
||||
buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
|
||||
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
buf = append(buf, socks5IP4)
|
||||
ip = ip4
|
||||
} else {
|
||||
buf = append(buf, socks5IP6)
|
||||
}
|
||||
buf = append(buf, ip...)
|
||||
} else {
|
||||
if len(host) > 255 {
|
||||
return errors.New("proxy: destination host name too long: " + host)
|
||||
}
|
||||
buf = append(buf, socks5Domain)
|
||||
buf = append(buf, byte(len(host)))
|
||||
buf = append(buf, host...)
|
||||
}
|
||||
buf = append(buf, byte(port>>8), byte(port))
|
||||
|
||||
if _, err := conn.Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(conn, buf[:4]); err != nil {
|
||||
return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
|
||||
failure := "unknown error"
|
||||
if int(buf[1]) < len(socks5Errors) {
|
||||
failure = socks5Errors[buf[1]]
|
||||
}
|
||||
|
||||
if len(failure) > 0 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
|
||||
}
|
||||
|
||||
bytesToDiscard := 0
|
||||
switch buf[3] {
|
||||
case socks5IP4:
|
||||
bytesToDiscard = net.IPv4len
|
||||
case socks5IP6:
|
||||
bytesToDiscard = net.IPv6len
|
||||
case socks5Domain:
|
||||
_, err := io.ReadFull(conn, buf[:1])
|
||||
if err != nil {
|
||||
return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
bytesToDiscard = int(buf[0])
|
||||
default:
|
||||
return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
|
||||
}
|
||||
|
||||
if cap(buf) < bytesToDiscard {
|
||||
buf = make([]byte, bytesToDiscard)
|
||||
} else {
|
||||
buf = buf[:bytesToDiscard]
|
||||
}
|
||||
if _, err := io.ReadFull(conn, buf); err != nil {
|
||||
return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
|
||||
// Also need to discard the port number
|
||||
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user