1
0
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:
Cherry Zhang 2020-07-17 14:56:36 -04:00
commit 3dabaa44e8
30 changed files with 2627 additions and 622 deletions

View File

@ -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

View File

@ -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>

View File

@ -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.

View File

@ -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.

View File

@ -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 (

View File

@ -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()

View File

@ -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
}

View File

@ -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)

View File

@ -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())
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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}

View File

@ -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"

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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.

View File

@ -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) {

View File

@ -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 {

View File

@ -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 {

View File

@ -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")

File diff suppressed because it is too large Load Diff

View 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
View File

@ -0,0 +1,2 @@
{{define "x"}}TEXT{{end}}
{{define "dotV"}}{{.V}}{{end}}

2
src/html/template/testdata/file2.tmpl vendored Normal file
View File

@ -0,0 +1,2 @@
{{define "dot"}}{{.}}{{end}}
{{define "nested"}}{{template "dot" .}}{{end}}

3
src/html/template/testdata/tmpl1.tmpl vendored Normal file
View File

@ -0,0 +1,3 @@
template1
{{define "x"}}x{{end}}
{{template "y"}}

3
src/html/template/testdata/tmpl2.tmpl vendored Normal file
View File

@ -0,0 +1,3 @@
template2
{{define "y"}}y{{end}}
{{template "x"}}

View File

@ -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()

View File

@ -359,6 +359,7 @@ func TestEmptyTemplate(t *testing.T) {
in string
want string
}{
{[]string{"x", "y"}, "", "y"},
{[]string{""}, "once", ""},
{[]string{"", ""}, "twice", ""},
{[]string{"{{.}}", "{{.}}"}, "twice", "twice"},