mirror of
https://github.com/golang/go
synced 2024-09-30 05:24:29 -06:00
[dev.link] all: merge branch 'master' into dev.link
Change-Id: I6545cb431e9e3efa02defca52af7eae502adb157
This commit is contained in:
commit
3dabaa44e8
@ -112,8 +112,6 @@ pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI ideal-int
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX = 14
|
||||
pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX ideal-int
|
||||
pkg go/printer, const StdFormat = 16
|
||||
pkg go/printer, const StdFormat Mode
|
||||
pkg math/big, method (*Int) FillBytes([]uint8) []uint8
|
||||
pkg net, method (*Resolver) LookupIP(context.Context, string, string) ([]IP, error)
|
||||
pkg net/url, method (*URL) EscapedFragment() string
|
||||
|
@ -658,15 +658,18 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
</dd>
|
||||
</dl><!-- fmt -->
|
||||
|
||||
<dl id="go/printer"><dt><a href="/pkg/go/printer/">go/printer</a></dt>
|
||||
<dl id="go/format"><dt><a href="/pkg/go/format/">go/format</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 231461 -->
|
||||
The new <a href="/pkg/go/printer/#Mode"><code>Mode</code></a>
|
||||
value <a href="/pkg/go/printer/#StdFormat"><code>StdFormat</code></a>
|
||||
directs the printer to apply standard formatting changes while
|
||||
printing the output.
|
||||
<p><!-- golang.org/issue/37476, CL 231461, CL 240683 -->
|
||||
The <a href="/pkg/go/format/#Source"><code>Source</code></a> and
|
||||
<a href="/pkg/go/format/#Node"><code>Node</code></a> functions
|
||||
now canonicalize number literal prefixes and exponents as part
|
||||
of formatting Go source code. This matches the behavior of the
|
||||
<a href="/pkg/cmd/gofmt/"><code>gofmt</code></a> command as it
|
||||
was implemented <a href="/doc/go1.13#gofmt">since Go 1.13</a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- go/printer -->
|
||||
</dl><!-- go/format -->
|
||||
|
||||
<dl id="html/template"><dt><a href="/pkg/html/template/">html/template</a></dt>
|
||||
<dd>
|
||||
|
@ -1700,6 +1700,8 @@
|
||||
// GOCACHE
|
||||
// The directory where the go command will store cached
|
||||
// information for reuse in future builds.
|
||||
// GOMODCACHE
|
||||
// The directory where the go command will store downloaded modules.
|
||||
// GODEBUG
|
||||
// Enable various debugging facilities. See 'go doc runtime'
|
||||
// for details.
|
||||
|
@ -493,6 +493,8 @@ General-purpose environment variables:
|
||||
GOCACHE
|
||||
The directory where the go command will store cached
|
||||
information for reuse in future builds.
|
||||
GOMODCACHE
|
||||
The directory where the go command will store downloaded modules.
|
||||
GODEBUG
|
||||
Enable various debugging facilities. See 'go doc runtime'
|
||||
for details.
|
||||
|
@ -40,7 +40,13 @@ var (
|
||||
// Keep these in sync with go/format/format.go.
|
||||
const (
|
||||
tabWidth = 8
|
||||
printerMode = printer.UseSpaces | printer.TabIndent | printer.StdFormat
|
||||
printerMode = printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers
|
||||
|
||||
// printerNormalizeNumbers means to canonicalize number literal prefixes
|
||||
// and exponents while printing. See https://golang.org/doc/go1.13#gofmt.
|
||||
//
|
||||
// This value is defined in go/printer specifically for go/format and cmd/gofmt.
|
||||
printerNormalizeNumbers = 1 << 30
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -512,33 +512,57 @@ func TestWriterReset(t *testing.T) {
|
||||
t.Errorf("level %d Writer not reset after Reset", level)
|
||||
}
|
||||
}
|
||||
testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, NoCompression) })
|
||||
testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, DefaultCompression) })
|
||||
testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriter(w, BestCompression) })
|
||||
dict := []byte("we are the world")
|
||||
testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, NoCompression, dict) })
|
||||
testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, DefaultCompression, dict) })
|
||||
testResetOutput(t, func(w io.Writer) (*Writer, error) { return NewWriterDict(w, BestCompression, dict) })
|
||||
|
||||
levels := []int{0, 1, 2, 5, 9}
|
||||
for _, level := range levels {
|
||||
t.Run(fmt.Sprint(level), func(t *testing.T) {
|
||||
testResetOutput(t, level, nil)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("dict", func(t *testing.T) {
|
||||
for _, level := range levels {
|
||||
t.Run(fmt.Sprint(level), func(t *testing.T) {
|
||||
testResetOutput(t, level, nil)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error)) {
|
||||
func testResetOutput(t *testing.T, level int, dict []byte) {
|
||||
writeData := func(w *Writer) {
|
||||
msg := []byte("now is the time for all good gophers")
|
||||
w.Write(msg)
|
||||
w.Flush()
|
||||
|
||||
hello := []byte("hello world")
|
||||
for i := 0; i < 1024; i++ {
|
||||
w.Write(hello)
|
||||
}
|
||||
|
||||
fill := bytes.Repeat([]byte("x"), 65000)
|
||||
w.Write(fill)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
w, err := newWriter(buf)
|
||||
var w *Writer
|
||||
var err error
|
||||
if dict == nil {
|
||||
w, err = NewWriter(buf, level)
|
||||
} else {
|
||||
w, err = NewWriterDict(buf, level, dict)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("NewWriter: %v", err)
|
||||
}
|
||||
b := []byte("hello world")
|
||||
for i := 0; i < 1024; i++ {
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
writeData(w)
|
||||
w.Close()
|
||||
out1 := buf.Bytes()
|
||||
|
||||
buf2 := new(bytes.Buffer)
|
||||
w.Reset(buf2)
|
||||
for i := 0; i < 1024; i++ {
|
||||
w.Write(b)
|
||||
}
|
||||
writeData(w)
|
||||
w.Close()
|
||||
out2 := buf2.Bytes()
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
package flate
|
||||
|
||||
import "math"
|
||||
|
||||
// This encoding algorithm, which prioritizes speed over output size, is
|
||||
// based on Snappy's LZ77-style encoder: github.com/golang/snappy
|
||||
|
||||
@ -12,6 +14,13 @@ const (
|
||||
tableSize = 1 << tableBits // Size of the table.
|
||||
tableMask = tableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
|
||||
tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32.
|
||||
|
||||
// Reset the buffer offset when reaching this.
|
||||
// Offsets are stored between blocks as int32 values.
|
||||
// Since the offset we are checking against is at the beginning
|
||||
// of the buffer, we need to subtract the current and input
|
||||
// buffer to not risk overflowing the int32.
|
||||
bufferReset = math.MaxInt32 - maxStoreBlockSize*2
|
||||
)
|
||||
|
||||
func load32(b []byte, i int32) uint32 {
|
||||
@ -59,8 +68,8 @@ func newDeflateFast() *deflateFast {
|
||||
// to dst and returns the result.
|
||||
func (e *deflateFast) encode(dst []token, src []byte) []token {
|
||||
// Ensure that e.cur doesn't wrap.
|
||||
if e.cur > 1<<30 {
|
||||
e.resetAll()
|
||||
if e.cur >= bufferReset {
|
||||
e.shiftOffsets()
|
||||
}
|
||||
|
||||
// This check isn't in the Snappy implementation, but there, the caller
|
||||
@ -264,22 +273,32 @@ func (e *deflateFast) reset() {
|
||||
e.cur += maxMatchOffset
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
if e.cur > 1<<30 {
|
||||
e.resetAll()
|
||||
if e.cur >= bufferReset {
|
||||
e.shiftOffsets()
|
||||
}
|
||||
}
|
||||
|
||||
// resetAll resets the deflateFast struct and is only called in rare
|
||||
// situations to prevent integer overflow. It manually resets each field
|
||||
// to avoid causing large stack growth.
|
||||
// shiftOffsets will shift down all match offset.
|
||||
// This is only called in rare situations to prevent integer overflow.
|
||||
//
|
||||
// See https://golang.org/issue/18636.
|
||||
func (e *deflateFast) resetAll() {
|
||||
// This is equivalent to:
|
||||
// *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
|
||||
e.cur = maxStoreBlockSize
|
||||
e.prev = e.prev[:0]
|
||||
for i := range e.table {
|
||||
e.table[i] = tableEntry{}
|
||||
// See https://golang.org/issue/18636 and https://github.com/golang/go/issues/34121.
|
||||
func (e *deflateFast) shiftOffsets() {
|
||||
if len(e.prev) == 0 {
|
||||
// We have no history; just clear the table.
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
}
|
||||
e.cur = maxMatchOffset
|
||||
return
|
||||
}
|
||||
|
||||
// Shift down everything in the table that isn't already too far away.
|
||||
for i := range e.table[:] {
|
||||
v := e.table[i].offset - e.cur + maxMatchOffset
|
||||
if v < 0 {
|
||||
v = 0
|
||||
}
|
||||
e.table[i].offset = v
|
||||
}
|
||||
e.cur = maxMatchOffset
|
||||
}
|
||||
|
@ -634,6 +634,7 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) {
|
||||
w.literalFreq[endBlockMarker] = 1
|
||||
|
||||
const numLiterals = endBlockMarker + 1
|
||||
w.offsetFreq[0] = 1
|
||||
const numOffsets = 1
|
||||
|
||||
w.literalEncoding.generate(w.literalFreq, 15)
|
||||
|
@ -173,3 +173,66 @@ func testDeterministic(i int, t *testing.T) {
|
||||
t.Errorf("level %d did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b))
|
||||
}
|
||||
}
|
||||
|
||||
// TestDeflateFast_Reset will test that encoding is consistent
|
||||
// across a warparound of the table offset.
|
||||
// See https://github.com/golang/go/issues/34121
|
||||
func TestDeflateFast_Reset(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
n := 65536
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
fmt.Fprintf(buf, "asdfasdfasdfasdf%d%dfghfgujyut%dyutyu\n", i, i, i)
|
||||
}
|
||||
// This is specific to level 1.
|
||||
const level = 1
|
||||
in := buf.Bytes()
|
||||
offset := 1
|
||||
if testing.Short() {
|
||||
offset = 256
|
||||
}
|
||||
|
||||
// We do an encode with a clean buffer to compare.
|
||||
var want bytes.Buffer
|
||||
w, err := NewWriter(&want, level)
|
||||
if err != nil {
|
||||
t.Fatalf("NewWriter: level %d: %v", level, err)
|
||||
}
|
||||
|
||||
// Output written 3 times.
|
||||
w.Write(in)
|
||||
w.Write(in)
|
||||
w.Write(in)
|
||||
w.Close()
|
||||
|
||||
for ; offset <= 256; offset *= 2 {
|
||||
w, err := NewWriter(ioutil.Discard, level)
|
||||
if err != nil {
|
||||
t.Fatalf("NewWriter: level %d: %v", level, err)
|
||||
}
|
||||
|
||||
// Reset until we are right before the wraparound.
|
||||
// Each reset adds maxMatchOffset to the offset.
|
||||
for i := 0; i < (bufferReset-len(in)-offset-maxMatchOffset)/maxMatchOffset; i++ {
|
||||
// skip ahead to where we are close to wrap around...
|
||||
w.d.reset(nil)
|
||||
}
|
||||
var got bytes.Buffer
|
||||
w.Reset(&got)
|
||||
|
||||
// Write 3 times, close.
|
||||
for i := 0; i < 3; i++ {
|
||||
_, err = w.Write(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(got.Bytes(), want.Bytes()) {
|
||||
t.Fatalf("output did not match at wraparound, len(want) = %d, len(got) = %d", want.Len(), got.Len())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,9 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
|
||||
switch status {
|
||||
case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
|
||||
return CertificateInvalidError{c, Expired, ""}
|
||||
case syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
|
||||
return CertificateInvalidError{c, IncompatibleUsage, ""}
|
||||
// TODO(filippo): surface more error statuses.
|
||||
default:
|
||||
return UnknownAuthorityError{c, nil, nil}
|
||||
}
|
||||
@ -138,11 +141,19 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
|
||||
return nil
|
||||
}
|
||||
|
||||
// windowsExtKeyUsageOIDs are the C NUL-terminated string representations of the
|
||||
// OIDs for use with the Windows API.
|
||||
var windowsExtKeyUsageOIDs = make(map[ExtKeyUsage][]byte, len(extKeyUsageOIDs))
|
||||
|
||||
func init() {
|
||||
for _, eku := range extKeyUsageOIDs {
|
||||
windowsExtKeyUsageOIDs[eku.extKeyUsage] = []byte(eku.oid.String() + "\x00")
|
||||
}
|
||||
}
|
||||
|
||||
// systemVerify is like Verify, except that it uses CryptoAPI calls
|
||||
// to build certificate chains and verify them.
|
||||
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
hasDNSName := opts != nil && len(opts.DNSName) > 0
|
||||
|
||||
storeCtx, err := createStoreContext(c, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -152,17 +163,26 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
|
||||
para := new(syscall.CertChainPara)
|
||||
para.Size = uint32(unsafe.Sizeof(*para))
|
||||
|
||||
// If there's a DNSName set in opts, assume we're verifying
|
||||
// a certificate from a TLS server.
|
||||
if hasDNSName {
|
||||
oids := []*byte{
|
||||
&syscall.OID_PKIX_KP_SERVER_AUTH[0],
|
||||
// Both IE and Chrome allow certificates with
|
||||
// Server Gated Crypto as well. Some certificates
|
||||
// in the wild require them.
|
||||
&syscall.OID_SERVER_GATED_CRYPTO[0],
|
||||
&syscall.OID_SGC_NETSCAPE[0],
|
||||
keyUsages := opts.KeyUsages
|
||||
if len(keyUsages) == 0 {
|
||||
keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
|
||||
}
|
||||
oids := make([]*byte, 0, len(keyUsages))
|
||||
for _, eku := range keyUsages {
|
||||
if eku == ExtKeyUsageAny {
|
||||
oids = nil
|
||||
break
|
||||
}
|
||||
if oid, ok := windowsExtKeyUsageOIDs[eku]; ok {
|
||||
oids = append(oids, &oid[0])
|
||||
}
|
||||
// Like the standard verifier, accept SGC EKUs as equivalent to ServerAuth.
|
||||
if eku == ExtKeyUsageServerAuth {
|
||||
oids = append(oids, &syscall.OID_SERVER_GATED_CRYPTO[0])
|
||||
oids = append(oids, &syscall.OID_SGC_NETSCAPE[0])
|
||||
}
|
||||
}
|
||||
if oids != nil {
|
||||
para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
|
||||
para.RequestedUsage.Usage.Length = uint32(len(oids))
|
||||
para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
|
||||
@ -208,7 +228,7 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hasDNSName {
|
||||
if opts != nil && len(opts.DNSName) > 0 {
|
||||
err = checkChainSSLServerPolicy(c, chainCtx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -194,7 +194,7 @@ var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificat
|
||||
// VerifyOptions contains parameters for Certificate.Verify.
|
||||
type VerifyOptions struct {
|
||||
// DNSName, if set, is checked against the leaf certificate with
|
||||
// Certificate.VerifyHostname.
|
||||
// Certificate.VerifyHostname or the platform verifier.
|
||||
DNSName string
|
||||
|
||||
// Intermediates is an optional pool of certificates that are not trust
|
||||
@ -209,20 +209,16 @@ type VerifyOptions struct {
|
||||
// chain. If zero, the current time is used.
|
||||
CurrentTime time.Time
|
||||
|
||||
// KeyUsage specifies which Extended Key Usage values are acceptable. A leaf
|
||||
// certificate is accepted if it contains any of the listed values. An empty
|
||||
// list means ExtKeyUsageServerAuth. To accept any key usage, include
|
||||
// ExtKeyUsageAny.
|
||||
//
|
||||
// Certificate chains are required to nest these extended key usage values.
|
||||
// (This matches the Windows CryptoAPI behavior, but not the spec.)
|
||||
// KeyUsages specifies which Extended Key Usage values are acceptable. A
|
||||
// chain is accepted if it allows any of the listed values. An empty list
|
||||
// means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny.
|
||||
KeyUsages []ExtKeyUsage
|
||||
|
||||
// MaxConstraintComparisions is the maximum number of comparisons to
|
||||
// perform when checking a given certificate's name constraints. If
|
||||
// zero, a sensible default is used. This limit prevents pathological
|
||||
// certificates from consuming excessive amounts of CPU time when
|
||||
// validating.
|
||||
// validating. It does not apply to the platform verifier.
|
||||
MaxConstraintComparisions int
|
||||
}
|
||||
|
||||
@ -735,8 +731,9 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
// needed. If successful, it returns one or more chains where the first
|
||||
// element of the chain is c and the last element is from opts.Roots.
|
||||
//
|
||||
// If opts.Roots is nil and system roots are unavailable the returned error
|
||||
// will be of type SystemRootsError.
|
||||
// If opts.Roots is nil, the platform verifier might be used, and
|
||||
// verification details might differ from what is described below. If system
|
||||
// roots are unavailable the returned error will be of type SystemRootsError.
|
||||
//
|
||||
// Name constraints in the intermediates will be applied to all names claimed
|
||||
// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim
|
||||
@ -750,9 +747,10 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
// it indicates that at least one additional label must be prepended to
|
||||
// the constrained name to be considered valid.
|
||||
//
|
||||
// Extended Key Usage values are enforced down a chain, so an intermediate or
|
||||
// root that enumerates EKUs prevents a leaf from asserting an EKU not in that
|
||||
// list.
|
||||
// Extended Key Usage values are enforced nested down a chain, so an intermediate
|
||||
// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that
|
||||
// list. (While this is not specified, it is common practice in order to limit
|
||||
// the types of certificates a CA can issue.)
|
||||
//
|
||||
// WARNING: this function doesn't do any revocation checking.
|
||||
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,13 @@ import (
|
||||
// Keep these in sync with cmd/gofmt/gofmt.go.
|
||||
const (
|
||||
tabWidth = 8
|
||||
printerMode = printer.UseSpaces | printer.TabIndent | printer.StdFormat
|
||||
printerMode = printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers
|
||||
|
||||
// printerNormalizeNumbers means to canonicalize number literal prefixes
|
||||
// and exponents while printing. See https://golang.org/doc/go1.13#gofmt.
|
||||
//
|
||||
// This value is defined in go/printer specifically for go/format and cmd/gofmt.
|
||||
printerNormalizeNumbers = 1 << 30
|
||||
)
|
||||
|
||||
var config = printer.Config{Mode: printerMode, Tabwidth: tabWidth}
|
||||
|
@ -58,8 +58,8 @@ func TestNode(t *testing.T) {
|
||||
diff(t, buf.Bytes(), src)
|
||||
}
|
||||
|
||||
// Node is documented to not modify the AST. Test that it is so, even when
|
||||
// formatting changes are applied due to printer.StdFormat mode being used.
|
||||
// Node is documented to not modify the AST.
|
||||
// Test that it is so even when numbers are normalized.
|
||||
func TestNodeNoModify(t *testing.T) {
|
||||
const (
|
||||
src = "package p\n\nconst _ = 0000000123i\n"
|
||||
|
@ -791,8 +791,8 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
|
||||
}
|
||||
|
||||
case *ast.BasicLit:
|
||||
if p.Config.Mode&StdFormat != 0 {
|
||||
x = normalizeNumbers(x)
|
||||
if p.Config.Mode&normalizeNumbers != 0 {
|
||||
x = normalizedNumber(x)
|
||||
}
|
||||
p.print(x)
|
||||
|
||||
@ -974,11 +974,15 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
|
||||
}
|
||||
}
|
||||
|
||||
// normalizeNumbers rewrites base prefixes and exponents to
|
||||
// use lower-case letters, and removes leading 0's from
|
||||
// integer imaginary literals. It leaves hexadecimal digits
|
||||
// alone.
|
||||
func normalizeNumbers(lit *ast.BasicLit) *ast.BasicLit {
|
||||
// normalizedNumber rewrites base prefixes and exponents
|
||||
// of numbers to use lower-case letters (0X123 to 0x123 and 1.2E3 to 1.2e3),
|
||||
// and removes leading 0's from integer imaginary literals (0765i to 765i).
|
||||
// It leaves hexadecimal digits alone.
|
||||
//
|
||||
// normalizedNumber doesn't modify the ast.BasicLit value lit points to.
|
||||
// If lit is not a number or a number in canonical format already,
|
||||
// lit is returned as is. Otherwise a new ast.BasicLit is created.
|
||||
func normalizedNumber(lit *ast.BasicLit) *ast.BasicLit {
|
||||
if lit.Kind != token.INT && lit.Kind != token.FLOAT && lit.Kind != token.IMAG {
|
||||
return lit // not a number - nothing to do
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
var testfile *ast.File
|
||||
|
||||
func testprint(out io.Writer, file *ast.File) {
|
||||
if err := (&Config{TabIndent | UseSpaces | StdFormat, 8, 0}).Fprint(out, fset, file); err != nil {
|
||||
if err := (&Config{TabIndent | UseSpaces | normalizeNumbers, 8, 0}).Fprint(out, fset, file); err != nil {
|
||||
log.Fatalf("print error: %s", err)
|
||||
}
|
||||
}
|
||||
|
@ -1276,7 +1276,22 @@ const (
|
||||
TabIndent // use tabs for indentation independent of UseSpaces
|
||||
UseSpaces // use spaces instead of tabs for alignment
|
||||
SourcePos // emit //line directives to preserve original source positions
|
||||
StdFormat // apply standard formatting changes (exact byte output may change between versions of Go)
|
||||
)
|
||||
|
||||
// The mode below is not included in printer's public API because
|
||||
// editing code text is deemed out of scope. Because this mode is
|
||||
// unexported, it's also possible to modify or remove it based on
|
||||
// the evolving needs of go/format and cmd/gofmt without breaking
|
||||
// users. See discussion in CL 240683.
|
||||
const (
|
||||
// normalizeNumbers means to canonicalize number
|
||||
// literal prefixes and exponents while printing.
|
||||
//
|
||||
// This value is known in and used by go/format and cmd/gofmt.
|
||||
// It is currently more convenient and performant for those
|
||||
// packages to apply number normalization during printing,
|
||||
// rather than by modifying the AST in advance.
|
||||
normalizeNumbers Mode = 1 << 30
|
||||
)
|
||||
|
||||
// A Config node controls the output of Fprint.
|
||||
|
@ -33,7 +33,7 @@ type checkMode uint
|
||||
const (
|
||||
export checkMode = 1 << iota
|
||||
rawFormat
|
||||
stdFormat
|
||||
normNumber
|
||||
idempotent
|
||||
)
|
||||
|
||||
@ -58,8 +58,8 @@ func format(src []byte, mode checkMode) ([]byte, error) {
|
||||
if mode&rawFormat != 0 {
|
||||
cfg.Mode |= RawFormat
|
||||
}
|
||||
if mode&stdFormat != 0 {
|
||||
cfg.Mode |= StdFormat
|
||||
if mode&normNumber != 0 {
|
||||
cfg.Mode |= normalizeNumbers
|
||||
}
|
||||
|
||||
// print AST
|
||||
@ -205,7 +205,7 @@ var data = []entry{
|
||||
{"slow.input", "slow.golden", idempotent},
|
||||
{"complit.input", "complit.x", export},
|
||||
{"go2numbers.input", "go2numbers.golden", idempotent},
|
||||
{"go2numbers.input", "go2numbers.stdfmt", stdFormat | idempotent},
|
||||
{"go2numbers.input", "go2numbers.norm", normNumber | idempotent},
|
||||
}
|
||||
|
||||
func TestFiles(t *testing.T) {
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"text/template/parse"
|
||||
)
|
||||
|
||||
func TestAddParseTree(t *testing.T) {
|
||||
func TestAddParseTreeHTML(t *testing.T) {
|
||||
root := Must(New("root").Parse(`{{define "a"}} {{.}} {{template "b"}} {{.}} "></a>{{end}}`))
|
||||
tree, err := parse.Parse("t", `{{define "b"}}<a href="{{end}}`, "", "", nil, nil)
|
||||
if err != nil {
|
||||
|
@ -401,11 +401,11 @@ func TestTypedContent(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test that we print using the String method. Was issue 3073.
|
||||
type stringer struct {
|
||||
type myStringer struct {
|
||||
v int
|
||||
}
|
||||
|
||||
func (s *stringer) String() string {
|
||||
func (s *myStringer) String() string {
|
||||
return fmt.Sprintf("string=%d", s.v)
|
||||
}
|
||||
|
||||
@ -418,7 +418,7 @@ func (s *errorer) Error() string {
|
||||
}
|
||||
|
||||
func TestStringer(t *testing.T) {
|
||||
s := &stringer{3}
|
||||
s := &myStringer{3}
|
||||
b := new(bytes.Buffer)
|
||||
tmpl := Must(New("x").Parse("{{.}}"))
|
||||
if err := tmpl.Execute(b, s); err != nil {
|
||||
|
@ -1821,7 +1821,7 @@ func TestIndirectPrint(t *testing.T) {
|
||||
}
|
||||
|
||||
// This is a test for issue 3272.
|
||||
func TestEmptyTemplate(t *testing.T) {
|
||||
func TestEmptyTemplateHTML(t *testing.T) {
|
||||
page := Must(New("page").ParseFiles(os.DevNull))
|
||||
if err := page.ExecuteTemplate(os.Stdout, "page", "nothing"); err == nil {
|
||||
t.Fatal("expected error")
|
||||
|
1708
src/html/template/exec_test.go
Normal file
1708
src/html/template/exec_test.go
Normal file
File diff suppressed because it is too large
Load Diff
246
src/html/template/multi_test.go
Normal file
246
src/html/template/multi_test.go
Normal file
@ -0,0 +1,246 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Tests for multiple-template execution, copied from text/template.
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"text/template/parse"
|
||||
)
|
||||
|
||||
var multiExecTests = []execTest{
|
||||
{"empty", "", "", nil, true},
|
||||
{"text", "some text", "some text", nil, true},
|
||||
{"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
|
||||
{"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
|
||||
{"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
|
||||
{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
|
||||
{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
|
||||
{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
|
||||
{"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
|
||||
|
||||
// User-defined function: test argument evaluator.
|
||||
{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
|
||||
{"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
|
||||
}
|
||||
|
||||
// These strings are also in testdata/*.
|
||||
const multiText1 = `
|
||||
{{define "x"}}TEXT{{end}}
|
||||
{{define "dotV"}}{{.V}}{{end}}
|
||||
`
|
||||
|
||||
const multiText2 = `
|
||||
{{define "dot"}}{{.}}{{end}}
|
||||
{{define "nested"}}{{template "dot" .}}{{end}}
|
||||
`
|
||||
|
||||
func TestMultiExecute(t *testing.T) {
|
||||
// Declare a couple of templates first.
|
||||
template, err := New("root").Parse(multiText1)
|
||||
if err != nil {
|
||||
t.Fatalf("parse error for 1: %s", err)
|
||||
}
|
||||
_, err = template.Parse(multiText2)
|
||||
if err != nil {
|
||||
t.Fatalf("parse error for 2: %s", err)
|
||||
}
|
||||
testExecute(multiExecTests, template, t)
|
||||
}
|
||||
|
||||
func TestParseFiles(t *testing.T) {
|
||||
_, err := ParseFiles("DOES NOT EXIST")
|
||||
if err == nil {
|
||||
t.Error("expected error for non-existent file; got none")
|
||||
}
|
||||
template := New("root")
|
||||
_, err = template.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing files: %v", err)
|
||||
}
|
||||
testExecute(multiExecTests, template, t)
|
||||
}
|
||||
|
||||
func TestParseGlob(t *testing.T) {
|
||||
_, err := ParseGlob("DOES NOT EXIST")
|
||||
if err == nil {
|
||||
t.Error("expected error for non-existent file; got none")
|
||||
}
|
||||
_, err = New("error").ParseGlob("[x")
|
||||
if err == nil {
|
||||
t.Error("expected error for bad pattern; got none")
|
||||
}
|
||||
template := New("root")
|
||||
_, err = template.ParseGlob("testdata/file*.tmpl")
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing files: %v", err)
|
||||
}
|
||||
testExecute(multiExecTests, template, t)
|
||||
}
|
||||
|
||||
// In these tests, actual content (not just template definitions) comes from the parsed files.
|
||||
|
||||
var templateFileExecTests = []execTest{
|
||||
{"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\n\ny\ntemplate2\n\nx\n", 0, true},
|
||||
}
|
||||
|
||||
func TestParseFilesWithData(t *testing.T) {
|
||||
template, err := New("root").ParseFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing files: %v", err)
|
||||
}
|
||||
testExecute(templateFileExecTests, template, t)
|
||||
}
|
||||
|
||||
func TestParseGlobWithData(t *testing.T) {
|
||||
template, err := New("root").ParseGlob("testdata/tmpl*.tmpl")
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing files: %v", err)
|
||||
}
|
||||
testExecute(templateFileExecTests, template, t)
|
||||
}
|
||||
|
||||
const (
|
||||
cloneText1 = `{{define "a"}}{{template "b"}}{{template "c"}}{{end}}`
|
||||
cloneText2 = `{{define "b"}}b{{end}}`
|
||||
cloneText3 = `{{define "c"}}root{{end}}`
|
||||
cloneText4 = `{{define "c"}}clone{{end}}`
|
||||
)
|
||||
|
||||
// Issue 7032
|
||||
func TestAddParseTreeToUnparsedTemplate(t *testing.T) {
|
||||
master := "{{define \"master\"}}{{end}}"
|
||||
tmpl := New("master")
|
||||
tree, err := parse.Parse("master", master, "", "", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected parse err: %v", err)
|
||||
}
|
||||
masterTree := tree["master"]
|
||||
tmpl.AddParseTree("master", masterTree) // used to panic
|
||||
}
|
||||
|
||||
func TestRedefinition(t *testing.T) {
|
||||
var tmpl *Template
|
||||
var err error
|
||||
if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
|
||||
t.Fatalf("parse 1: %v", err)
|
||||
}
|
||||
if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err != nil {
|
||||
t.Fatalf("got error %v, expected nil", err)
|
||||
}
|
||||
if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err != nil {
|
||||
t.Fatalf("got error %v, expected nil", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 10879
|
||||
func TestEmptyTemplateCloneCrash(t *testing.T) {
|
||||
t1 := New("base")
|
||||
t1.Clone() // used to panic
|
||||
}
|
||||
|
||||
// Issue 10910, 10926
|
||||
func TestTemplateLookUp(t *testing.T) {
|
||||
t.Skip("broken on html/template") // TODO
|
||||
t1 := New("foo")
|
||||
if t1.Lookup("foo") != nil {
|
||||
t.Error("Lookup returned non-nil value for undefined template foo")
|
||||
}
|
||||
t1.New("bar")
|
||||
if t1.Lookup("bar") != nil {
|
||||
t.Error("Lookup returned non-nil value for undefined template bar")
|
||||
}
|
||||
t1.Parse(`{{define "foo"}}test{{end}}`)
|
||||
if t1.Lookup("foo") == nil {
|
||||
t.Error("Lookup returned nil value for defined template")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
// In multiple calls to Parse with the same receiver template, only one call
|
||||
// can contain text other than space, comments, and template definitions
|
||||
t1 := New("test")
|
||||
if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil {
|
||||
t.Fatalf("parsing test: %s", err)
|
||||
}
|
||||
if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil {
|
||||
t.Fatalf("parsing test: %s", err)
|
||||
}
|
||||
if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil {
|
||||
t.Fatalf("parsing test: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyTemplate(t *testing.T) {
|
||||
cases := []struct {
|
||||
defn []string
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{[]string{"x", "y"}, "", "y"},
|
||||
{[]string{""}, "once", ""},
|
||||
{[]string{"", ""}, "twice", ""},
|
||||
{[]string{"{{.}}", "{{.}}"}, "twice", "twice"},
|
||||
{[]string{"{{/* a comment */}}", "{{/* a comment */}}"}, "comment", ""},
|
||||
{[]string{"{{.}}", ""}, "twice", "twice"}, // TODO: should want "" not "twice"
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
root := New("root")
|
||||
|
||||
var (
|
||||
m *Template
|
||||
err error
|
||||
)
|
||||
for _, d := range c.defn {
|
||||
m, err = root.New(c.in).Parse(d)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
if err := m.Execute(buf, c.in); err != nil {
|
||||
t.Error(i, err)
|
||||
continue
|
||||
}
|
||||
if buf.String() != c.want {
|
||||
t.Errorf("expected string %q: got %q", c.want, buf.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 19249 was a regression in 1.8 caused by the handling of empty
|
||||
// templates added in that release, which got different answers depending
|
||||
// on the order templates appeared in the internal map.
|
||||
func TestIssue19294(t *testing.T) {
|
||||
// The empty block in "xhtml" should be replaced during execution
|
||||
// by the contents of "stylesheet", but if the internal map associating
|
||||
// names with templates is built in the wrong order, the empty block
|
||||
// looks non-empty and this doesn't happen.
|
||||
var inlined = map[string]string{
|
||||
"stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`,
|
||||
"xhtml": `{{block "stylesheet" .}}{{end}}`,
|
||||
}
|
||||
all := []string{"stylesheet", "xhtml"}
|
||||
for i := 0; i < 100; i++ {
|
||||
res, err := New("title.xhtml").Parse(`{{template "xhtml" .}}`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, name := range all {
|
||||
_, err := res.New(name).Parse(inlined[name])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
res.Execute(&buf, 0)
|
||||
if buf.String() != "stylesheet" {
|
||||
t.Fatalf("iteration %d: got %q; expected %q", i, buf.String(), "stylesheet")
|
||||
}
|
||||
}
|
||||
}
|
2
src/html/template/testdata/file1.tmpl
vendored
Normal file
2
src/html/template/testdata/file1.tmpl
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
{{define "x"}}TEXT{{end}}
|
||||
{{define "dotV"}}{{.V}}{{end}}
|
2
src/html/template/testdata/file2.tmpl
vendored
Normal file
2
src/html/template/testdata/file2.tmpl
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
{{define "dot"}}{{.}}{{end}}
|
||||
{{define "nested"}}{{template "dot" .}}{{end}}
|
3
src/html/template/testdata/tmpl1.tmpl
vendored
Normal file
3
src/html/template/testdata/tmpl1.tmpl
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
template1
|
||||
{{define "x"}}x{{end}}
|
||||
{{template "y"}}
|
3
src/html/template/testdata/tmpl2.tmpl
vendored
Normal file
3
src/html/template/testdata/tmpl2.tmpl
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
template2
|
||||
{{define "y"}}y{{end}}
|
||||
{{template "x"}}
|
@ -425,6 +425,16 @@ type response struct {
|
||||
wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive"
|
||||
wantsClose bool // HTTP request has Connection "close"
|
||||
|
||||
// canWriteContinue is a boolean value accessed as an atomic int32
|
||||
// that says whether or not a 100 Continue header can be written
|
||||
// to the connection.
|
||||
// writeContinueMu must be held while writing the header.
|
||||
// These two fields together synchronize the body reader
|
||||
// (the expectContinueReader, which wants to write 100 Continue)
|
||||
// against the main writer.
|
||||
canWriteContinue atomicBool
|
||||
writeContinueMu sync.Mutex
|
||||
|
||||
w *bufio.Writer // buffers output in chunks to chunkWriter
|
||||
cw chunkWriter
|
||||
|
||||
@ -515,6 +525,7 @@ type atomicBool int32
|
||||
|
||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
||||
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
||||
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
||||
|
||||
// declareTrailer is called for each Trailer header when the
|
||||
// response header is written. It notes that a header will need to be
|
||||
@ -878,21 +889,27 @@ type expectContinueReader struct {
|
||||
resp *response
|
||||
readCloser io.ReadCloser
|
||||
closed bool
|
||||
sawEOF bool
|
||||
sawEOF atomicBool
|
||||
}
|
||||
|
||||
func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
|
||||
if ecr.closed {
|
||||
return 0, ErrBodyReadAfterClose
|
||||
}
|
||||
if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked() {
|
||||
ecr.resp.wroteContinue = true
|
||||
ecr.resp.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
|
||||
ecr.resp.conn.bufw.Flush()
|
||||
w := ecr.resp
|
||||
if !w.wroteContinue && w.canWriteContinue.isSet() && !w.conn.hijacked() {
|
||||
w.wroteContinue = true
|
||||
w.writeContinueMu.Lock()
|
||||
if w.canWriteContinue.isSet() {
|
||||
w.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
|
||||
w.conn.bufw.Flush()
|
||||
w.canWriteContinue.setFalse()
|
||||
}
|
||||
w.writeContinueMu.Unlock()
|
||||
}
|
||||
n, err = ecr.readCloser.Read(p)
|
||||
if err == io.EOF {
|
||||
ecr.sawEOF = true
|
||||
ecr.sawEOF.setTrue()
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -1311,7 +1328,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
||||
// because we don't know if the next bytes on the wire will be
|
||||
// the body-following-the-timer or the subsequent request.
|
||||
// See Issue 11549.
|
||||
if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF {
|
||||
if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF.isSet() {
|
||||
w.closeAfterReply = true
|
||||
}
|
||||
|
||||
@ -1561,6 +1578,17 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er
|
||||
}
|
||||
return 0, ErrHijacked
|
||||
}
|
||||
|
||||
if w.canWriteContinue.isSet() {
|
||||
// Body reader wants to write 100 Continue but hasn't yet.
|
||||
// Tell it not to. The store must be done while holding the lock
|
||||
// because the lock makes sure that there is not an active write
|
||||
// this very moment.
|
||||
w.writeContinueMu.Lock()
|
||||
w.canWriteContinue.setFalse()
|
||||
w.writeContinueMu.Unlock()
|
||||
}
|
||||
|
||||
if !w.wroteHeader {
|
||||
w.WriteHeader(StatusOK)
|
||||
}
|
||||
@ -1872,6 +1900,7 @@ func (c *conn) serve(ctx context.Context) {
|
||||
if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
|
||||
// Wrap the Body reader with one that replies on the connection
|
||||
req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
|
||||
w.canWriteContinue.setTrue()
|
||||
}
|
||||
} else if req.Header.get("Expect") != "" {
|
||||
w.sendExpectationFailed()
|
||||
|
@ -359,6 +359,7 @@ func TestEmptyTemplate(t *testing.T) {
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{[]string{"x", "y"}, "", "y"},
|
||||
{[]string{""}, "once", ""},
|
||||
{[]string{"", ""}, "twice", ""},
|
||||
{[]string{"{{.}}", "{{.}}"}, "twice", "twice"},
|
||||
|
Loading…
Reference in New Issue
Block a user