Merge branch 'el6' into epel7
This commit is contained in:
commit
ebf90baf57
|
@ -1,3 +1,4 @@
|
||||||
|
*.rpm
|
||||||
/go1.1.1.src.tar.gz
|
/go1.1.1.src.tar.gz
|
||||||
/go1.1.2.src.tar.gz
|
/go1.1.2.src.tar.gz
|
||||||
/go1.2.1.src.tar.gz
|
/go1.2.1.src.tar.gz
|
||||||
|
@ -6,8 +7,49 @@
|
||||||
/go1.3.1.src.tar.gz
|
/go1.3.1.src.tar.gz
|
||||||
/go1.3.2.src.tar.gz
|
/go1.3.2.src.tar.gz
|
||||||
/go1.3.3.src.tar.gz
|
/go1.3.3.src.tar.gz
|
||||||
|
/go1.3.src.tar.gz
|
||||||
/go1.3beta2.src.tar.gz
|
/go1.3beta2.src.tar.gz
|
||||||
/go1.3rc1.src.tar.gz
|
/go1.3rc1.src.tar.gz
|
||||||
/go1.3rc2.src.tar.gz
|
/go1.3rc2.src.tar.gz
|
||||||
/go1.3.src.tar.gz
|
/go1.4.1.src.tar.gz
|
||||||
|
/go1.4.2.src.tar.gz
|
||||||
|
/go1.4.src.tar.gz
|
||||||
|
/go1.4beta1.src.tar.gz
|
||||||
|
/go1.4rc1.src.tar.gz
|
||||||
|
/go1.4rc2.src.tar.gz
|
||||||
|
/go1.5beta1.src.tar.gz
|
||||||
/golang-19087:a15f344a9efa-xattrs.tar
|
/golang-19087:a15f344a9efa-xattrs.tar
|
||||||
|
/go1.5beta2.src.tar.gz
|
||||||
|
/go1.5beta3.src.tar.gz
|
||||||
|
/go1.5rc1.src.tar.gz
|
||||||
|
/go1.5.src.tar.gz
|
||||||
|
/go1.5.1.src.tar.gz
|
||||||
|
/go1.5.2.src.tar.gz
|
||||||
|
/Mark.Twain-Tom.Sawyer.txt.bz2
|
||||||
|
/go1.5.3.src.tar.gz
|
||||||
|
/go1.6rc1.src.tar.gz
|
||||||
|
/go1.6.src.tar.gz
|
||||||
|
/go1.6.1.src.tar.gz
|
||||||
|
/go1.6.2.src.tar.gz
|
||||||
|
/go1.7rc2.src.tar.gz
|
||||||
|
/go1.7rc5.src.tar.gz
|
||||||
|
/go1.7.src.tar.gz
|
||||||
|
/go1.7.1.src.tar.gz
|
||||||
|
/go1.7.3.src.tar.gz
|
||||||
|
/go1.7.4.src.tar.gz
|
||||||
|
/go1.7.6.src.tar.gz
|
||||||
|
/go1.8rc3.src.tar.gz
|
||||||
|
/go1.8.src.tar.gz
|
||||||
|
/go1.8.1.src.tar.gz
|
||||||
|
/go1.8.3.src.tar.gz
|
||||||
|
/go1.9beta2.src.tar.gz
|
||||||
|
/go1.9.src.tar.gz
|
||||||
|
/go1.9.1.src.tar.gz
|
||||||
|
/go1.9.2.src.tar.gz
|
||||||
|
/go1.9.3.src.tar.gz
|
||||||
|
/go1.9.4.src.tar.gz
|
||||||
|
/go1.9.5.src.tar.gz
|
||||||
|
/go1.9.6.src.tar.gz
|
||||||
|
/go1.9.7.src.tar.gz
|
||||||
|
/go1.11.1.src.tar.gz
|
||||||
|
/go1.11.2.src.tar.gz
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
From edce31a2904846ae74e3c011f2cf5fddc963459e Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Jakub=20=C4=8Cajka?= <jcajka@redhat.com>
|
||||||
|
Date: Thu, 22 Mar 2018 12:07:32 +0100
|
||||||
|
Subject: [PATCH 1/3] Don't use the bundled tzdata at runtime, except for the
|
||||||
|
internal test suite
|
||||||
|
|
||||||
|
---
|
||||||
|
src/time/internal_test.go | 7 +++++--
|
||||||
|
src/time/zoneinfo_test.go | 3 ++-
|
||||||
|
src/time/zoneinfo_unix.go | 2 --
|
||||||
|
3 files changed, 7 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/time/internal_test.go b/src/time/internal_test.go
|
||||||
|
index 76d5524124..e81ace5f64 100644
|
||||||
|
--- a/src/time/internal_test.go
|
||||||
|
+++ b/src/time/internal_test.go
|
||||||
|
@@ -4,13 +4,15 @@
|
||||||
|
|
||||||
|
package time
|
||||||
|
|
||||||
|
+import "runtime"
|
||||||
|
+
|
||||||
|
func init() {
|
||||||
|
// force US/Pacific for time zone tests
|
||||||
|
ForceUSPacificForTesting()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initTestingZone() {
|
||||||
|
- z, err := loadLocation("America/Los_Angeles", zoneSources[len(zoneSources)-1:])
|
||||||
|
+ z, err := loadLocation("America/Los_Angeles", zoneSources)
|
||||||
|
if err != nil {
|
||||||
|
panic("cannot load America/Los_Angeles for testing: " + err.Error())
|
||||||
|
}
|
||||||
|
@@ -21,8 +23,9 @@ func initTestingZone() {
|
||||||
|
var OrigZoneSources = zoneSources
|
||||||
|
|
||||||
|
func forceZipFileForTesting(zipOnly bool) {
|
||||||
|
- zoneSources = make([]string, len(OrigZoneSources))
|
||||||
|
+ zoneSources = make([]string, len(OrigZoneSources)+1)
|
||||||
|
copy(zoneSources, OrigZoneSources)
|
||||||
|
+ zoneSources = append(zoneSources, runtime.GOROOT()+"/lib/time/zoneinfo.zip")
|
||||||
|
if zipOnly {
|
||||||
|
zoneSources = zoneSources[len(zoneSources)-1:]
|
||||||
|
}
|
||||||
|
diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go
|
||||||
|
index 7a55d4f618..6063ca1195 100644
|
||||||
|
--- a/src/time/zoneinfo_test.go
|
||||||
|
+++ b/src/time/zoneinfo_test.go
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
+ "runtime"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
@@ -128,7 +129,7 @@ func TestLoadLocationFromTZData(t *testing.T) {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
- tzinfo, err := time.LoadTzinfo(locationName, time.OrigZoneSources[len(time.OrigZoneSources)-1])
|
||||||
|
+ tzinfo, err := time.LoadTzinfo(locationName, runtime.GOROOT()+"/lib/time/zoneinfo.zip")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go
|
||||||
|
index 88313aa0ed..d9596115ef 100644
|
||||||
|
--- a/src/time/zoneinfo_unix.go
|
||||||
|
+++ b/src/time/zoneinfo_unix.go
|
||||||
|
@@ -12,7 +12,6 @@
|
||||||
|
package time
|
||||||
|
|
||||||
|
import (
|
||||||
|
- "runtime"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
@@ -22,7 +21,6 @@ var zoneSources = []string{
|
||||||
|
"/usr/share/zoneinfo/",
|
||||||
|
"/usr/share/lib/zoneinfo/",
|
||||||
|
"/usr/lib/locale/TZ/",
|
||||||
|
- runtime.GOROOT() + "/lib/time/zoneinfo.zip",
|
||||||
|
}
|
||||||
|
|
||||||
|
func initLocal() {
|
||||||
|
--
|
||||||
|
2.14.3
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
From 817407fc2d6a861e65086388766f58082d38bc0b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Michael Munday <munday@ca.ibm.com>
|
||||||
|
Date: Tue, 17 Jan 2017 11:33:38 -0500
|
||||||
|
Subject: [PATCH 2/3] syscall: expose IfInfomsg.X__ifi_pad on s390x
|
||||||
|
|
||||||
|
Exposing this field on s390x improves compatibility with the other
|
||||||
|
linux architectures, all of which already expose it.
|
||||||
|
|
||||||
|
Fixes #18628 and updates #18632.
|
||||||
|
|
||||||
|
Change-Id: I08e8e1eb705f898cd8822f8bee0d61ce11d514b5
|
||||||
|
---
|
||||||
|
src/syscall/ztypes_linux_s390x.go | 12 ++++++------
|
||||||
|
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/syscall/ztypes_linux_s390x.go b/src/syscall/ztypes_linux_s390x.go
|
||||||
|
index 63c4a83b19..b5894255df 100644
|
||||||
|
--- a/src/syscall/ztypes_linux_s390x.go
|
||||||
|
+++ b/src/syscall/ztypes_linux_s390x.go
|
||||||
|
@@ -449,12 +449,12 @@ type RtAttr struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type IfInfomsg struct {
|
||||||
|
- Family uint8
|
||||||
|
- _ uint8
|
||||||
|
- Type uint16
|
||||||
|
- Index int32
|
||||||
|
- Flags uint32
|
||||||
|
- Change uint32
|
||||||
|
+ Family uint8
|
||||||
|
+ X__ifi_pad uint8
|
||||||
|
+ Type uint16
|
||||||
|
+ Index int32
|
||||||
|
+ Flags uint32
|
||||||
|
+ Change uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type IfAddrmsg struct {
|
||||||
|
--
|
||||||
|
2.14.3
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
commit 117ddcb83d7f42d6aa72241240af99ded81118e9
|
||||||
|
Author: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
Date: Tue Jun 30 09:22:41 2015 -0700
|
||||||
|
|
||||||
|
net/textproto: don't treat spaces as hyphens in header keys
|
||||||
|
|
||||||
|
This was originally done in https://codereview.appspot.com/5690059
|
||||||
|
(Feb 2012) to deal with bad response headers coming back from webcams,
|
||||||
|
but it presents a potential security problem with HTTP request
|
||||||
|
smuggling for request headers containing "Content Length" instead of
|
||||||
|
"Content-Length".
|
||||||
|
|
||||||
|
Part of overall HTTP hardening for request smuggling. See RFC 7230.
|
||||||
|
|
||||||
|
Thanks to Régis Leroy for the report.
|
||||||
|
|
||||||
|
Change-Id: I92b17fb637c9171c5774ea1437979ae2c17ca88a
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/11772
|
||||||
|
Reviewed-by: Russ Cox <rsc@golang.org>
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
TryBot-Result: Gobot Gobot <gobot@golang.org>
|
||||||
|
|
||||||
|
diff --git a/src/net/http/header.go b/src/net/http/header.go
|
||||||
|
index 153b943..d847b13 100644
|
||||||
|
--- a/src/net/http/header.go
|
||||||
|
+++ b/src/net/http/header.go
|
||||||
|
@@ -168,6 +168,8 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
|
||||||
|
// letter and any letter following a hyphen to upper case;
|
||||||
|
// the rest are converted to lowercase. For example, the
|
||||||
|
// canonical key for "accept-encoding" is "Accept-Encoding".
|
||||||
|
+// If s contains a space or invalid header field bytes, it is
|
||||||
|
+// returned without modifications.
|
||||||
|
func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }
|
||||||
|
|
||||||
|
// hasToken reports whether token appears with v, ASCII
|
||||||
|
diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
|
||||||
|
index e4b8f6b..91303fe 100644
|
||||||
|
--- a/src/net/textproto/reader.go
|
||||||
|
+++ b/src/net/textproto/reader.go
|
||||||
|
@@ -547,11 +547,16 @@ func (r *Reader) upcomingHeaderNewlines() (n int) {
|
||||||
|
// the rest are converted to lowercase. For example, the
|
||||||
|
// canonical key for "accept-encoding" is "Accept-Encoding".
|
||||||
|
// MIME header keys are assumed to be ASCII only.
|
||||||
|
+// If s contains a space or invalid header field bytes, it is
|
||||||
|
+// returned without modifications.
|
||||||
|
func CanonicalMIMEHeaderKey(s string) string {
|
||||||
|
// Quick check for canonical encoding.
|
||||||
|
upper := true
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
c := s[i]
|
||||||
|
+ if !validHeaderFieldByte(c) {
|
||||||
|
+ return s
|
||||||
|
+ }
|
||||||
|
if upper && 'a' <= c && c <= 'z' {
|
||||||
|
return canonicalMIMEHeaderKey([]byte(s))
|
||||||
|
}
|
||||||
|
@@ -565,19 +570,44 @@ func CanonicalMIMEHeaderKey(s string) string {
|
||||||
|
|
||||||
|
const toLower = 'a' - 'A'
|
||||||
|
|
||||||
|
+// validHeaderFieldByte reports whether b is a valid byte in a header
|
||||||
|
+// field key. This is actually stricter than RFC 7230, which says:
|
||||||
|
+// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
||||||
|
+// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
||||||
|
+// token = 1*tchar
|
||||||
|
+// TODO: revisit in Go 1.6+ and possibly expand this. But note that many
|
||||||
|
+// servers have historically dropped '_' to prevent ambiguities when mapping
|
||||||
|
+// to CGI environment variables.
|
||||||
|
+func validHeaderFieldByte(b byte) bool {
|
||||||
|
+ return ('A' <= b && b <= 'Z') ||
|
||||||
|
+ ('a' <= b && b <= 'z') ||
|
||||||
|
+ ('0' <= b && b <= '9') ||
|
||||||
|
+ b == '-'
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
|
||||||
|
// allowed to mutate the provided byte slice before returning the
|
||||||
|
// string.
|
||||||
|
+//
|
||||||
|
+// For invalid inputs (if a contains spaces or non-token bytes), a
|
||||||
|
+// is unchanged and a string copy is returned.
|
||||||
|
func canonicalMIMEHeaderKey(a []byte) string {
|
||||||
|
+ // See if a looks like a header key. If not, return it unchanged.
|
||||||
|
+ for _, c := range a {
|
||||||
|
+ if validHeaderFieldByte(c) {
|
||||||
|
+ continue
|
||||||
|
+ }
|
||||||
|
+ // Don't canonicalize.
|
||||||
|
+ return string(a)
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
upper := true
|
||||||
|
for i, c := range a {
|
||||||
|
// Canonicalize: first letter upper case
|
||||||
|
// and upper case after each dash.
|
||||||
|
// (Host, User-Agent, If-Modified-Since).
|
||||||
|
// MIME headers are ASCII only, so no Unicode issues.
|
||||||
|
- if c == ' ' {
|
||||||
|
- c = '-'
|
||||||
|
- } else if upper && 'a' <= c && c <= 'z' {
|
||||||
|
+ if upper && 'a' <= c && c <= 'z' {
|
||||||
|
c -= toLower
|
||||||
|
} else if !upper && 'A' <= c && c <= 'Z' {
|
||||||
|
c += toLower
|
||||||
|
diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
|
||||||
|
index 6bbd993..8fce7dd 100644
|
||||||
|
--- a/src/net/textproto/reader_test.go
|
||||||
|
+++ b/src/net/textproto/reader_test.go
|
||||||
|
@@ -24,11 +24,14 @@ var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
|
||||||
|
{"uSER-aGENT", "User-Agent"},
|
||||||
|
{"user-agent", "User-Agent"},
|
||||||
|
{"USER-AGENT", "User-Agent"},
|
||||||
|
- {"üser-agenT", "üser-Agent"}, // non-ASCII unchanged
|
||||||
|
+
|
||||||
|
+ // Non-ASCII or anything with spaces or non-token chars is unchanged:
|
||||||
|
+ {"üser-agenT", "üser-agenT"},
|
||||||
|
+ {"a B", "a B"},
|
||||||
|
|
||||||
|
// This caused a panic due to mishandling of a space:
|
||||||
|
- {"C Ontent-Transfer-Encoding", "C-Ontent-Transfer-Encoding"},
|
||||||
|
- {"foo bar", "Foo-Bar"},
|
||||||
|
+ {"C Ontent-Transfer-Encoding", "C Ontent-Transfer-Encoding"},
|
||||||
|
+ {"foo bar", "foo bar"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCanonicalMIMEHeaderKey(t *testing.T) {
|
||||||
|
@@ -194,7 +197,7 @@ func TestReadMIMEHeaderNonCompliant(t *testing.T) {
|
||||||
|
"Foo": {"bar"},
|
||||||
|
"Content-Language": {"en"},
|
||||||
|
"Sid": {"0"},
|
||||||
|
- "Audio-Mode": {"None"},
|
||||||
|
+ "Audio Mode": {"None"},
|
||||||
|
"Privilege": {"127"},
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(m, want) || err != nil {
|
|
@ -0,0 +1,112 @@
|
||||||
|
commit 143822585e32449860e624cace9d2e521deee62e
|
||||||
|
Author: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
Date: Tue Jul 7 13:19:44 2015 -0600
|
||||||
|
|
||||||
|
net/http: revert overly-strict part of earlier smuggling defense
|
||||||
|
|
||||||
|
The recent https://golang.org/cl/11810 is reportedly a bit too
|
||||||
|
aggressive.
|
||||||
|
|
||||||
|
Apparently some HTTP requests in the wild do contain both a
|
||||||
|
Transfer-Encoding along with a bogus Content-Length. Instead of
|
||||||
|
returning a 400 Bad Request error, we should just ignore the
|
||||||
|
Content-Length like we did before.
|
||||||
|
|
||||||
|
Change-Id: I0001be90d09f8293a34f04691f608342875ff5c4
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/11962
|
||||||
|
Reviewed-by: Andrew Gerrand <adg@golang.org>
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
TryBot-Result: Gobot Gobot <gobot@golang.org>
|
||||||
|
|
||||||
|
diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go
|
||||||
|
index 1a3cf91..60e2be4 100644
|
||||||
|
--- a/src/net/http/readrequest_test.go
|
||||||
|
+++ b/src/net/http/readrequest_test.go
|
||||||
|
@@ -178,6 +178,36 @@ var reqTests = []reqTest{
|
||||||
|
noError,
|
||||||
|
},
|
||||||
|
|
||||||
|
+ // Tests chunked body and a bogus Content-Length which should be deleted.
|
||||||
|
+ {
|
||||||
|
+ "POST / HTTP/1.1\r\n" +
|
||||||
|
+ "Host: foo.com\r\n" +
|
||||||
|
+ "Transfer-Encoding: chunked\r\n" +
|
||||||
|
+ "Content-Length: 9999\r\n\r\n" + // to be removed.
|
||||||
|
+ "3\r\nfoo\r\n" +
|
||||||
|
+ "3\r\nbar\r\n" +
|
||||||
|
+ "0\r\n" +
|
||||||
|
+ "\r\n",
|
||||||
|
+ &Request{
|
||||||
|
+ Method: "POST",
|
||||||
|
+ URL: &url.URL{
|
||||||
|
+ Path: "/",
|
||||||
|
+ },
|
||||||
|
+ TransferEncoding: []string{"chunked"},
|
||||||
|
+ Proto: "HTTP/1.1",
|
||||||
|
+ ProtoMajor: 1,
|
||||||
|
+ ProtoMinor: 1,
|
||||||
|
+ Header: Header{},
|
||||||
|
+ ContentLength: -1,
|
||||||
|
+ Host: "foo.com",
|
||||||
|
+ RequestURI: "/",
|
||||||
|
+ },
|
||||||
|
+
|
||||||
|
+ "foobar",
|
||||||
|
+ noTrailer,
|
||||||
|
+ noError,
|
||||||
|
+ },
|
||||||
|
+
|
||||||
|
// CONNECT request with domain name:
|
||||||
|
{
|
||||||
|
"CONNECT www.google.com:443 HTTP/1.1\r\n\r\n",
|
||||||
|
@@ -400,11 +430,6 @@ Content-Length: 3
|
||||||
|
Content-Length: 4
|
||||||
|
|
||||||
|
abc`)},
|
||||||
|
- {"smuggle_chunked_and_len", reqBytes(`POST / HTTP/1.1
|
||||||
|
-Transfer-Encoding: chunked
|
||||||
|
-Content-Length: 3
|
||||||
|
-
|
||||||
|
-abc`)},
|
||||||
|
{"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1
|
||||||
|
Host: foo
|
||||||
|
Content-Length: 5`)},
|
||||||
|
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
|
||||||
|
index 3c868bd..fbbbf24 100644
|
||||||
|
--- a/src/net/http/transfer.go
|
||||||
|
+++ b/src/net/http/transfer.go
|
||||||
|
@@ -430,7 +430,6 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
|
||||||
|
if !present {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
- isRequest := !isResponse
|
||||||
|
delete(header, "Transfer-Encoding")
|
||||||
|
|
||||||
|
encodings := strings.Split(raw[0], ",")
|
||||||
|
@@ -458,12 +457,20 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
|
||||||
|
// RFC 7230 3.3.2 says "A sender MUST NOT send a
|
||||||
|
// Content-Length header field in any message that
|
||||||
|
// contains a Transfer-Encoding header field."
|
||||||
|
- if len(header["Content-Length"]) > 0 {
|
||||||
|
- if isRequest {
|
||||||
|
- return nil, errors.New("http: invalid Content-Length with Transfer-Encoding")
|
||||||
|
- }
|
||||||
|
- delete(header, "Content-Length")
|
||||||
|
- }
|
||||||
|
+ //
|
||||||
|
+ // but also:
|
||||||
|
+ // "If a message is received with both a
|
||||||
|
+ // Transfer-Encoding and a Content-Length header
|
||||||
|
+ // field, the Transfer-Encoding overrides the
|
||||||
|
+ // Content-Length. Such a message might indicate an
|
||||||
|
+ // attempt to perform request smuggling (Section 9.5)
|
||||||
|
+ // or response splitting (Section 9.4) and ought to be
|
||||||
|
+ // handled as an error. A sender MUST remove the
|
||||||
|
+ // received Content-Length field prior to forwarding
|
||||||
|
+ // such a message downstream."
|
||||||
|
+ //
|
||||||
|
+ // Reportedly, these appear in the wild.
|
||||||
|
+ delete(header, "Content-Length")
|
||||||
|
return te, nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
commit 300d9a21583e7cf0149a778a0611e76ff7c6680f
|
||||||
|
Author: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
Date: Tue Jun 30 14:21:15 2015 -0700
|
||||||
|
|
||||||
|
net/http: harden Server against request smuggling
|
||||||
|
|
||||||
|
See RFC 7230.
|
||||||
|
|
||||||
|
Thanks to Régis Leroy for the report.
|
||||||
|
|
||||||
|
Change-Id: Ic1779bc2180900430d4d7a4938cac04ed73c304c
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/11810
|
||||||
|
Reviewed-by: Russ Cox <rsc@golang.org>
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
|
||||||
|
diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go
|
||||||
|
index e930d99..1a3cf91 100644
|
||||||
|
--- a/src/net/http/readrequest_test.go
|
||||||
|
+++ b/src/net/http/readrequest_test.go
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
+ "io/ioutil"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
@@ -323,6 +324,32 @@ var reqTests = []reqTest{
|
||||||
|
noTrailer,
|
||||||
|
noError,
|
||||||
|
},
|
||||||
|
+
|
||||||
|
+ // HEAD with Content-Length 0. Make sure this is permitted,
|
||||||
|
+ // since I think we used to send it.
|
||||||
|
+ {
|
||||||
|
+ "HEAD / HTTP/1.1\r\nHost: issue8261.com\r\nConnection: close\r\nContent-Length: 0\r\n\r\n",
|
||||||
|
+ &Request{
|
||||||
|
+ Method: "HEAD",
|
||||||
|
+ URL: &url.URL{
|
||||||
|
+ Path: "/",
|
||||||
|
+ },
|
||||||
|
+ Header: Header{
|
||||||
|
+ "Connection": []string{"close"},
|
||||||
|
+ "Content-Length": []string{"0"},
|
||||||
|
+ },
|
||||||
|
+ Host: "issue8261.com",
|
||||||
|
+ Proto: "HTTP/1.1",
|
||||||
|
+ ProtoMajor: 1,
|
||||||
|
+ ProtoMinor: 1,
|
||||||
|
+ Close: true,
|
||||||
|
+ RequestURI: "/",
|
||||||
|
+ },
|
||||||
|
+
|
||||||
|
+ noBody,
|
||||||
|
+ noTrailer,
|
||||||
|
+ noError,
|
||||||
|
+ },
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadRequest(t *testing.T) {
|
||||||
|
@@ -356,3 +383,39 @@ func TestReadRequest(t *testing.T) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+// reqBytes treats req as a request (with \n delimiters) and returns it with \r\n delimiters,
|
||||||
|
+// ending in \r\n\r\n
|
||||||
|
+func reqBytes(req string) []byte {
|
||||||
|
+ return []byte(strings.Replace(strings.TrimSpace(req), "\n", "\r\n", -1) + "\r\n\r\n")
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+var badRequestTests = []struct {
|
||||||
|
+ name string
|
||||||
|
+ req []byte
|
||||||
|
+}{
|
||||||
|
+ {"bad_connect_host", reqBytes("CONNECT []%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a HTTP/1.0")},
|
||||||
|
+ {"smuggle_two_contentlen", reqBytes(`POST / HTTP/1.1
|
||||||
|
+Content-Length: 3
|
||||||
|
+Content-Length: 4
|
||||||
|
+
|
||||||
|
+abc`)},
|
||||||
|
+ {"smuggle_chunked_and_len", reqBytes(`POST / HTTP/1.1
|
||||||
|
+Transfer-Encoding: chunked
|
||||||
|
+Content-Length: 3
|
||||||
|
+
|
||||||
|
+abc`)},
|
||||||
|
+ {"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1
|
||||||
|
+Host: foo
|
||||||
|
+Content-Length: 5`)},
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+func TestReadRequest_Bad(t *testing.T) {
|
||||||
|
+ for _, tt := range badRequestTests {
|
||||||
|
+ got, err := ReadRequest(bufio.NewReader(bytes.NewReader(tt.req)))
|
||||||
|
+ if err == nil {
|
||||||
|
+ all, err := ioutil.ReadAll(got.Body)
|
||||||
|
+ t.Errorf("%s: got unexpected request = %#v\n Body = %q, %v", tt.name, got, all, err)
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
|
||||||
|
index 5205003..3887604 100644
|
||||||
|
--- a/src/net/http/transfer.go
|
||||||
|
+++ b/src/net/http/transfer.go
|
||||||
|
@@ -143,6 +143,9 @@ func (t *transferWriter) shouldSendContentLength() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if t.ContentLength == 0 && isIdentity(t.TransferEncoding) {
|
||||||
|
+ if t.Method == "GET" || t.Method == "HEAD" {
|
||||||
|
+ return false
|
||||||
|
+ }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -310,6 +313,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
|
||||||
|
}
|
||||||
|
case *Request:
|
||||||
|
t.Header = rr.Header
|
||||||
|
+ t.RequestMethod = rr.Method
|
||||||
|
t.ProtoMajor = rr.ProtoMajor
|
||||||
|
t.ProtoMinor = rr.ProtoMinor
|
||||||
|
// Transfer semantics for Requests are exactly like those for
|
||||||
|
@@ -325,7 +329,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer encoding, content length
|
||||||
|
- t.TransferEncoding, err = fixTransferEncoding(t.RequestMethod, t.Header)
|
||||||
|
+ t.TransferEncoding, err = fixTransferEncoding(isResponse, t.RequestMethod, t.Header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@@ -413,12 +417,12 @@ func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
|
||||||
|
func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
|
||||||
|
|
||||||
|
// Sanitize transfer encoding
|
||||||
|
-func fixTransferEncoding(requestMethod string, header Header) ([]string, error) {
|
||||||
|
+func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ([]string, error) {
|
||||||
|
raw, present := header["Transfer-Encoding"]
|
||||||
|
if !present {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ isRequest := !isResponse
|
||||||
|
delete(header, "Transfer-Encoding")
|
||||||
|
|
||||||
|
encodings := strings.Split(raw[0], ",")
|
||||||
|
@@ -443,10 +447,15 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, error)
|
||||||
|
return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")}
|
||||||
|
}
|
||||||
|
if len(te) > 0 {
|
||||||
|
- // Chunked encoding trumps Content-Length. See RFC 2616
|
||||||
|
- // Section 4.4. Currently len(te) > 0 implies chunked
|
||||||
|
- // encoding.
|
||||||
|
- delete(header, "Content-Length")
|
||||||
|
+ // RFC 7230 3.3.2 says "A sender MUST NOT send a
|
||||||
|
+ // Content-Length header field in any message that
|
||||||
|
+ // contains a Transfer-Encoding header field."
|
||||||
|
+ if len(header["Content-Length"]) > 0 {
|
||||||
|
+ if isRequest {
|
||||||
|
+ return nil, errors.New("http: invalid Content-Length with Transfer-Encoding")
|
||||||
|
+ }
|
||||||
|
+ delete(header, "Content-Length")
|
||||||
|
+ }
|
||||||
|
return te, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -457,9 +466,17 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, error)
|
||||||
|
// function is not a method, because ultimately it should be shared by
|
||||||
|
// ReadResponse and ReadRequest.
|
||||||
|
func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) {
|
||||||
|
-
|
||||||
|
+ contentLens := header["Content-Length"]
|
||||||
|
+ isRequest := !isResponse
|
||||||
|
// Logic based on response type or status
|
||||||
|
if noBodyExpected(requestMethod) {
|
||||||
|
+ // For HTTP requests, as part of hardening against request
|
||||||
|
+ // smuggling (RFC 7230), don't allow a Content-Length header for
|
||||||
|
+ // methods which don't permit bodies. As an exception, allow
|
||||||
|
+ // exactly one Content-Length header if its value is "0".
|
||||||
|
+ if isRequest && len(contentLens) > 0 && !(len(contentLens) == 1 && contentLens[0] == "0") {
|
||||||
|
+ return 0, fmt.Errorf("http: method cannot contain a Content-Length; got %q", contentLens)
|
||||||
|
+ }
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
if status/100 == 1 {
|
||||||
|
@@ -470,13 +487,21 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if len(contentLens) > 1 {
|
||||||
|
+ // harden against HTTP request smuggling. See RFC 7230.
|
||||||
|
+ return 0, errors.New("http: message cannot contain multiple Content-Length headers")
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// Logic based on Transfer-Encoding
|
||||||
|
if chunked(te) {
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logic based on Content-Length
|
||||||
|
- cl := strings.TrimSpace(header.get("Content-Length"))
|
||||||
|
+ var cl string
|
||||||
|
+ if len(contentLens) == 1 {
|
||||||
|
+ cl = strings.TrimSpace(contentLens[0])
|
||||||
|
+ }
|
||||||
|
if cl != "" {
|
||||||
|
n, err := parseContentLength(cl)
|
||||||
|
if err != nil {
|
||||||
|
@@ -487,11 +512,14 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
|
||||||
|
header.Del("Content-Length")
|
||||||
|
}
|
||||||
|
|
||||||
|
- if !isResponse && requestMethod == "GET" {
|
||||||
|
- // RFC 2616 doesn't explicitly permit nor forbid an
|
||||||
|
+ if !isResponse {
|
||||||
|
+ // RFC 2616 neither explicitly permits nor forbids an
|
||||||
|
// entity-body on a GET request so we permit one if
|
||||||
|
// declared, but we default to 0 here (not -1 below)
|
||||||
|
// if there's no mention of a body.
|
||||||
|
+ // Likewise, all other request methods are assumed to have
|
||||||
|
+ // no body if neither Transfer-Encoding chunked nor a
|
||||||
|
+ // Content-Length are set.
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
diff -up go/src/cmd/go/get.go.cve go/src/cmd/go/get.go
|
||||||
|
--- go/src/cmd/go/get.go.cve 2017-05-23 20:35:22.000000000 +0200
|
||||||
|
+++ go/src/cmd/go/get.go 2017-10-10 10:25:24.485047705 +0200
|
||||||
|
@@ -401,6 +401,11 @@ func downloadPackage(p *Package) error {
|
||||||
|
p.build.PkgRoot = filepath.Join(list[0], "pkg")
|
||||||
|
}
|
||||||
|
root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
|
||||||
|
+
|
||||||
|
+ if err := checkNestedVCS(vcs, root, p.build.SrcRoot); err != nil {
|
||||||
|
+ return err
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// If we've considered this repository already, don't do it again.
|
||||||
|
if downloadRootCache[root] {
|
||||||
|
return nil
|
||||||
|
diff -up go/src/cmd/go/go_test.go.cve go/src/cmd/go/go_test.go
|
||||||
|
--- go/src/cmd/go/go_test.go.cve 2017-05-23 20:35:22.000000000 +0200
|
||||||
|
+++ go/src/cmd/go/go_test.go 2017-10-10 10:25:24.485047705 +0200
|
||||||
|
@@ -1235,6 +1235,25 @@ func TestGetGitDefaultBranch(t *testing.
|
||||||
|
tg.grepStdout(`\* another-branch`, "not on correct default branch")
|
||||||
|
}
|
||||||
|
|
||||||
|
+func TestAccidentalGitCheckout(t *testing.T) {
|
||||||
|
+ testenv.MustHaveExternalNetwork(t)
|
||||||
|
+ if _, err := exec.LookPath("git"); err != nil {
|
||||||
|
+ t.Skip("skipping because git binary not found")
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ tg := testgo(t)
|
||||||
|
+ defer tg.cleanup()
|
||||||
|
+ tg.parallel()
|
||||||
|
+ tg.tempDir("src")
|
||||||
|
+ tg.setenv("GOPATH", tg.path("."))
|
||||||
|
+
|
||||||
|
+ tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git")
|
||||||
|
+ tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
|
||||||
|
+
|
||||||
|
+ tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main")
|
||||||
|
+ tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
|
||||||
|
tg := testgo(t)
|
||||||
|
defer tg.cleanup()
|
||||||
|
diff -up go/src/cmd/go/vcs.go.cve go/src/cmd/go/vcs.go
|
||||||
|
--- go/src/cmd/go/vcs.go.cve 2017-05-23 20:35:22.000000000 +0200
|
||||||
|
+++ go/src/cmd/go/vcs.go 2017-10-10 10:30:52.151621206 +0200
|
||||||
|
@@ -479,11 +479,29 @@ func vcsFromDir(dir, srcRoot string) (vc
|
||||||
|
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
+ var vcsRet *vcsCmd
|
||||||
|
+ var rootRet string
|
||||||
|
+
|
||||||
|
origDir := dir
|
||||||
|
for len(dir) > len(srcRoot) {
|
||||||
|
for _, vcs := range vcsList {
|
||||||
|
if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
|
||||||
|
- return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
|
||||||
|
+ root := filepath.ToSlash(dir[len(srcRoot)+1:])
|
||||||
|
+ // Record first VCS we find, but keep looking,
|
||||||
|
+ // to detect mistakes like one kind of VCS inside another.
|
||||||
|
+ if vcsRet == nil {
|
||||||
|
+ vcsRet = vcs
|
||||||
|
+ rootRet = root
|
||||||
|
+ continue
|
||||||
|
+ }
|
||||||
|
+ // Allow .git inside .git, which can arise due to submodules.
|
||||||
|
+ if vcsRet == vcs && vcs.cmd == "git" {
|
||||||
|
+ continue
|
||||||
|
+ }
|
||||||
|
+ // Otherwise, we have one VCS inside a different VCS.
|
||||||
|
+ return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",
|
||||||
|
+ filepath.Join(srcRoot, rootRet), vcsRet.cmd, filepath.Join(srcRoot, root), vcs.cmd)
|
||||||
|
+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -496,9 +514,48 @@ func vcsFromDir(dir, srcRoot string) (vc
|
||||||
|
dir = ndir
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if vcsRet != nil {
|
||||||
|
+ return vcsRet, rootRet, nil
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
+// checkNestedVCS checks for an incorrectly-nested VCS-inside-VCS
|
||||||
|
+// situation for dir, checking parents up until srcRoot.
|
||||||
|
+func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error {
|
||||||
|
+ if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
|
||||||
|
+ return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ otherDir := dir
|
||||||
|
+ for len(otherDir) > len(srcRoot) {
|
||||||
|
+ for _, otherVCS := range vcsList {
|
||||||
|
+ if _, err := os.Stat(filepath.Join(dir, "."+otherVCS.cmd)); err == nil {
|
||||||
|
+ // Allow expected vcs in original dir.
|
||||||
|
+ if otherDir == dir && otherVCS == vcs {
|
||||||
|
+ continue
|
||||||
|
+ }
|
||||||
|
+ // Allow .git inside .git, which can arise due to submodules.
|
||||||
|
+ if otherVCS == vcs && vcs.cmd == "git" {
|
||||||
|
+ continue
|
||||||
|
+ }
|
||||||
|
+ // Otherwise, we have one VCS inside a different VCS.
|
||||||
|
+ return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.cmd, otherDir, otherVCS.cmd)
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Move to parent.
|
||||||
|
+ newDir := filepath.Dir(otherDir)
|
||||||
|
+ if len(newDir) >= len(otherDir) {
|
||||||
|
+ // Shouldn't happen, but just in case, stop.
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
+ otherDir = newDir
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return nil
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// repoRoot represents a version control system, a repo, and a root of
|
||||||
|
// where to put it on disk.
|
||||||
|
type repoRoot struct {
|
|
@ -0,0 +1,144 @@
|
||||||
|
From 4be3fc33ef512532b916aa14258087e89eb47347 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Russ Cox <rsc@golang.org>
|
||||||
|
Date: Wed, 4 Oct 2017 13:24:49 -0400
|
||||||
|
Subject: [PATCH] [release-branch.go1.8] net/smtp: fix PlainAuth to refuse to
|
||||||
|
send passwords to non-TLS servers
|
||||||
|
|
||||||
|
PlainAuth originally refused to send passwords to non-TLS servers
|
||||||
|
and was documented as such.
|
||||||
|
|
||||||
|
In 2013, issue #5184 was filed objecting to the TLS requirement,
|
||||||
|
despite the fact that it is spelled out clearly in RFC 4954.
|
||||||
|
The only possibly legitimate use case raised was using PLAIN auth
|
||||||
|
for connections to localhost, and the suggested fix was to let the
|
||||||
|
server decide: if it advertises that PLAIN auth is OK, believe it.
|
||||||
|
That approach was adopted in CL 8279043 and released in Go 1.1.
|
||||||
|
|
||||||
|
Unfortunately, this is exactly wrong. The whole point of the TLS
|
||||||
|
requirement is to make sure not to send the password to the wrong
|
||||||
|
server or to a man-in-the-middle. Instead of implementing this rule,
|
||||||
|
CL 8279043 blindly trusts the server, so that if a man-in-the-middle
|
||||||
|
says "it's OK, you can send me your password," PlainAuth does.
|
||||||
|
And the documentation was not updated to reflect any of this.
|
||||||
|
|
||||||
|
This CL restores the original TLS check, as required by RFC 4954
|
||||||
|
and as promised in the documentation for PlainAuth.
|
||||||
|
It then carves out a documented exception for connections made
|
||||||
|
to localhost (defined as "localhost", "127.0.0.1", or "::1").
|
||||||
|
|
||||||
|
Cherry-pick of CL 68170.
|
||||||
|
|
||||||
|
Change-Id: I1d3729bbd33aa2f11a03f4c000e6bb473164957b
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/68023
|
||||||
|
Run-TryBot: Russ Cox <rsc@golang.org>
|
||||||
|
Reviewed-by: Chris Broadfoot <cbro@golang.org>
|
||||||
|
---
|
||||||
|
src/net/smtp/auth.go | 33 ++++++++++++++++++---------------
|
||||||
|
src/net/smtp/smtp_test.go | 32 ++++++++++++++++++++++----------
|
||||||
|
2 files changed, 40 insertions(+), 25 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/net/smtp/auth.go b/src/net/smtp/auth.go
|
||||||
|
index 3f1339ebc56..fd1a472f930 100644
|
||||||
|
--- a/src/net/smtp/auth.go
|
||||||
|
+++ b/src/net/smtp/auth.go
|
||||||
|
@@ -44,26 +44,29 @@ type plainAuth struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlainAuth returns an Auth that implements the PLAIN authentication
|
||||||
|
-// mechanism as defined in RFC 4616.
|
||||||
|
-// The returned Auth uses the given username and password to authenticate
|
||||||
|
-// on TLS connections to host and act as identity. Usually identity will be
|
||||||
|
-// left blank to act as username.
|
||||||
|
+// mechanism as defined in RFC 4616. The returned Auth uses the given
|
||||||
|
+// username and password to authenticate to host and act as identity.
|
||||||
|
+// Usually identity should be the empty string, to act as username.
|
||||||
|
+//
|
||||||
|
+// PlainAuth will only send the credentials if the connection is using TLS
|
||||||
|
+// or is connected to localhost. Otherwise authentication will fail with an
|
||||||
|
+// error, without sending the credentials.
|
||||||
|
func PlainAuth(identity, username, password, host string) Auth {
|
||||||
|
return &plainAuth{identity, username, password, host}
|
||||||
|
}
|
||||||
|
|
||||||
|
+func isLocalhost(name string) bool {
|
||||||
|
+ return name == "localhost" || name == "127.0.0.1" || name == "::1"
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
|
||||||
|
- if !server.TLS {
|
||||||
|
- advertised := false
|
||||||
|
- for _, mechanism := range server.Auth {
|
||||||
|
- if mechanism == "PLAIN" {
|
||||||
|
- advertised = true
|
||||||
|
- break
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- if !advertised {
|
||||||
|
- return "", nil, errors.New("unencrypted connection")
|
||||||
|
- }
|
||||||
|
+ // Must have TLS, or else localhost server.
|
||||||
|
+ // Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo.
|
||||||
|
+ // In particular, it doesn't matter if the server advertises PLAIN auth.
|
||||||
|
+ // That might just be the attacker saying
|
||||||
|
+ // "it's ok, you can trust me with your password."
|
||||||
|
+ if !server.TLS && !isLocalhost(server.Name) {
|
||||||
|
+ return "", nil, errors.New("unencrypted connection")
|
||||||
|
}
|
||||||
|
if server.Name != a.host {
|
||||||
|
return "", nil, errors.New("wrong host name")
|
||||||
|
diff --git a/src/net/smtp/smtp_test.go b/src/net/smtp/smtp_test.go
|
||||||
|
index c48fae6d5ac..15eaca524be 100644
|
||||||
|
--- a/src/net/smtp/smtp_test.go
|
||||||
|
+++ b/src/net/smtp/smtp_test.go
|
||||||
|
@@ -60,29 +60,41 @@ testLoop:
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuthPlain(t *testing.T) {
|
||||||
|
- auth := PlainAuth("foo", "bar", "baz", "servername")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
- server *ServerInfo
|
||||||
|
- err string
|
||||||
|
+ authName string
|
||||||
|
+ server *ServerInfo
|
||||||
|
+ err string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
- server: &ServerInfo{Name: "servername", TLS: true},
|
||||||
|
+ authName: "servername",
|
||||||
|
+ server: &ServerInfo{Name: "servername", TLS: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
- // Okay; explicitly advertised by server.
|
||||||
|
- server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
|
||||||
|
+ // OK to use PlainAuth on localhost without TLS
|
||||||
|
+ authName: "localhost",
|
||||||
|
+ server: &ServerInfo{Name: "localhost", TLS: false},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
- server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
|
||||||
|
- err: "unencrypted connection",
|
||||||
|
+ // NOT OK on non-localhost, even if server says PLAIN is OK.
|
||||||
|
+ // (We don't know that the server is the real server.)
|
||||||
|
+ authName: "servername",
|
||||||
|
+ server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
|
||||||
|
+ err: "unencrypted connection",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
- server: &ServerInfo{Name: "attacker", TLS: true},
|
||||||
|
- err: "wrong host name",
|
||||||
|
+ authName: "servername",
|
||||||
|
+ server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
|
||||||
|
+ err: "unencrypted connection",
|
||||||
|
+ },
|
||||||
|
+ {
|
||||||
|
+ authName: "servername",
|
||||||
|
+ server: &ServerInfo{Name: "attacker", TLS: true},
|
||||||
|
+ err: "wrong host name",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
+ auth := PlainAuth("foo", "bar", "baz", tt.authName)
|
||||||
|
_, _, err := auth.Start(tt.server)
|
||||||
|
got := ""
|
||||||
|
if err != nil {
|
|
@ -0,0 +1,7 @@
|
||||||
|
// +build rpm_crashtraceback
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
setTraceback("crash")
|
||||||
|
}
|
|
@ -1,110 +0,0 @@
|
||||||
# HG changeset patch
|
|
||||||
# User Cristian Staretu <unclejacksons@gmail.com>
|
|
||||||
# Date 1405555229 -36000
|
|
||||||
# Thu Jul 17 10:00:29 2014 +1000
|
|
||||||
# Node ID 1b17b3426e3c281a973d2d7bbf235b936d6a0942
|
|
||||||
# Parent 278365dff593f027db6c6b2c0a89262490d6b676
|
|
||||||
archive/tar: fix writing of pax headers
|
|
||||||
|
|
||||||
"archive/tar: reuse temporary buffer in writeHeader" introduced a
|
|
||||||
change which was supposed to help lower the number of allocations from
|
|
||||||
512 bytes for every call to writeHeader. This change broke the writing
|
|
||||||
of PAX headers.
|
|
||||||
|
|
||||||
writeHeader calls writePAXHeader and writePAXHeader calls writeHeader
|
|
||||||
again. writeHeader will end up writing the PAX header twice.
|
|
||||||
|
|
||||||
example broken header:
|
|
||||||
PaxHeaders.4007/NetLock_Arany_=Class_Gold=_Ftanstvny.crt0000000000000000000000000000007112301216634021512 xustar0000000000000000
|
|
||||||
PaxHeaders.4007/NetLock_Arany_=Class_Gold=_Ftanstvny.crt0000000000000000000000000000007112301216634021512 xustar0000000000000000
|
|
||||||
|
|
||||||
example correct header:
|
|
||||||
PaxHeaders.4290/NetLock_Arany_=Class_Gold=_Ftanstvny.crt0000000000000000000000000000007112301216634021516 xustar0000000000000000
|
|
||||||
0100644000000000000000000000270412301216634007250 0ustar0000000000000000
|
|
||||||
|
|
||||||
This commit adds a dedicated buffer for pax headers to the Writer
|
|
||||||
struct. This change increases the size of the struct by 512 bytes, but
|
|
||||||
allows tar/writer to avoid allocating 512 bytes for all written
|
|
||||||
headers and it avoids allocating 512 more bytes for pax headers.
|
|
||||||
|
|
||||||
LGTM=dsymonds
|
|
||||||
R=dsymonds, dave, iant
|
|
||||||
CC=golang-codereviews
|
|
||||||
https://codereview.appspot.com/110480043
|
|
||||||
|
|
||||||
Committer: David Symonds <dsymonds@golang.org>
|
|
||||||
|
|
||||||
diff -r 278365dff593 -r 1b17b3426e3c src/pkg/archive/tar/writer.go
|
|
||||||
--- a/src/pkg/archive/tar/writer.go Wed Jul 16 16:29:51 2014 -0700
|
|
||||||
+++ b/src/pkg/archive/tar/writer.go Thu Jul 17 10:00:29 2014 +1000
|
|
||||||
@@ -39,7 +39,8 @@
|
|
||||||
closed bool
|
|
||||||
usedBinary bool // whether the binary numeric field extension was used
|
|
||||||
preferPax bool // use pax header instead of binary numeric header
|
|
||||||
- hdrBuff [blockSize]byte // buffer to use in writeHeader
|
|
||||||
+ hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header
|
|
||||||
+ paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWriter creates a new Writer writing to w.
|
|
||||||
@@ -161,7 +162,17 @@
|
|
||||||
// subsecond time resolution, but for now let's just capture
|
|
||||||
// too long fields or non ascii characters
|
|
||||||
|
|
||||||
- header := tw.hdrBuff[:]
|
|
||||||
+ var header []byte
|
|
||||||
+
|
|
||||||
+ // We need to select which scratch buffer to use carefully,
|
|
||||||
+ // since this method is called recursively to write PAX headers.
|
|
||||||
+ // If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
|
|
||||||
+ // If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
|
|
||||||
+ // already being used by the non-recursive call, so we must use paxHdrBuff.
|
|
||||||
+ header = tw.hdrBuff[:]
|
|
||||||
+ if !allowPax {
|
|
||||||
+ header = tw.paxHdrBuff[:]
|
|
||||||
+ }
|
|
||||||
copy(header, zeroBlock)
|
|
||||||
s := slicer(header)
|
|
||||||
|
|
||||||
diff -r 278365dff593 -r 1b17b3426e3c src/pkg/archive/tar/writer_test.go
|
|
||||||
--- a/src/pkg/archive/tar/writer_test.go Wed Jul 16 16:29:51 2014 -0700
|
|
||||||
+++ b/src/pkg/archive/tar/writer_test.go Thu Jul 17 10:00:29 2014 +1000
|
|
||||||
@@ -454,3 +454,38 @@
|
|
||||||
t.Fatal("Couldn't recover long name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+func TestValidTypeflagWithPAXHeader(t *testing.T) {
|
|
||||||
+ var buffer bytes.Buffer
|
|
||||||
+ tw := NewWriter(&buffer)
|
|
||||||
+
|
|
||||||
+ fileName := strings.Repeat("ab", 100)
|
|
||||||
+
|
|
||||||
+ hdr := &Header{
|
|
||||||
+ Name: fileName,
|
|
||||||
+ Size: 4,
|
|
||||||
+ Typeflag: 0,
|
|
||||||
+ }
|
|
||||||
+ if err := tw.WriteHeader(hdr); err != nil {
|
|
||||||
+ t.Fatalf("Failed to write header: %s", err)
|
|
||||||
+ }
|
|
||||||
+ if _, err := tw.Write([]byte("fooo")); err != nil {
|
|
||||||
+ t.Fatalf("Failed to write the file's data: %s", err)
|
|
||||||
+ }
|
|
||||||
+ tw.Close()
|
|
||||||
+
|
|
||||||
+ tr := NewReader(&buffer)
|
|
||||||
+
|
|
||||||
+ for {
|
|
||||||
+ header, err := tr.Next()
|
|
||||||
+ if err == io.EOF {
|
|
||||||
+ break
|
|
||||||
+ }
|
|
||||||
+ if err != nil {
|
|
||||||
+ t.Fatalf("Failed to read header: %s", err)
|
|
||||||
+ }
|
|
||||||
+ if header.Typeflag != 0 {
|
|
||||||
+ t.Fatalf("Typeflag should've been 0, found %d", header.Typeflag)
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
|
@ -1,64 +0,0 @@
|
||||||
# HG changeset patch
|
|
||||||
# User Cristian Staretu <unclejacksons@gmail.com>
|
|
||||||
# Date 1404344479 -36000
|
|
||||||
# Thu Jul 03 09:41:19 2014 +1000
|
|
||||||
# Node ID 17404efd6b02d4b3acd17070e3f89de97a145877
|
|
||||||
# Parent 837348e418f33fc7a242f56dbe2feff829532526
|
|
||||||
archive/tar: reuse temporary buffer in readHeader
|
|
||||||
|
|
||||||
A temporary 512 bytes buffer is allocated for every call to
|
|
||||||
readHeader. This buffer isn't returned to the caller and it could
|
|
||||||
be reused to lower the number of memory allocations.
|
|
||||||
|
|
||||||
This CL improves it by using a pool and zeroing out the buffer before
|
|
||||||
putting it back into the pool.
|
|
||||||
|
|
||||||
benchmark old ns/op new ns/op delta
|
|
||||||
BenchmarkListFiles100k 545249903 538832687 -1.18%
|
|
||||||
|
|
||||||
benchmark old allocs new allocs delta
|
|
||||||
BenchmarkListFiles100k 2105167 2005692 -4.73%
|
|
||||||
|
|
||||||
benchmark old bytes new bytes delta
|
|
||||||
BenchmarkListFiles100k 105903472 54831527 -48.22%
|
|
||||||
|
|
||||||
This improvement is very important if your code has to deal with a lot
|
|
||||||
of tarballs which contain a lot of files.
|
|
||||||
|
|
||||||
LGTM=dsymonds
|
|
||||||
R=golang-codereviews, dave, dsymonds, bradfitz
|
|
||||||
CC=golang-codereviews
|
|
||||||
https://codereview.appspot.com/108240044
|
|
||||||
|
|
||||||
Committer: David Symonds <dsymonds@golang.org>
|
|
||||||
|
|
||||||
diff -r 837348e418f3 -r 17404efd6b02 src/pkg/archive/tar/reader.go
|
|
||||||
--- a/src/pkg/archive/tar/reader.go Thu Jul 03 09:40:53 2014 +1000
|
|
||||||
+++ b/src/pkg/archive/tar/reader.go Thu Jul 03 09:41:19 2014 +1000
|
|
||||||
@@ -29,10 +29,11 @@
|
|
||||||
// The Next method advances to the next file in the archive (including the first),
|
|
||||||
// and then it can be treated as an io.Reader to access the file's data.
|
|
||||||
type Reader struct {
|
|
||||||
- r io.Reader
|
|
||||||
- err error
|
|
||||||
- pad int64 // amount of padding (ignored) after current file entry
|
|
||||||
- curr numBytesReader // reader for current file entry
|
|
||||||
+ r io.Reader
|
|
||||||
+ err error
|
|
||||||
+ pad int64 // amount of padding (ignored) after current file entry
|
|
||||||
+ curr numBytesReader // reader for current file entry
|
|
||||||
+ hdrBuff [blockSize]byte // buffer to use in readHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
// A numBytesReader is an io.Reader with a numBytes method, returning the number
|
|
||||||
@@ -426,7 +427,9 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tr *Reader) readHeader() *Header {
|
|
||||||
- header := make([]byte, blockSize)
|
|
||||||
+ header := tr.hdrBuff[:]
|
|
||||||
+ copy(header, zeroBlock)
|
|
||||||
+
|
|
||||||
if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
# HG changeset patch
|
|
||||||
# User Cristian Staretu <unclejacksons@gmail.com>
|
|
||||||
# Date 1404344453 -36000
|
|
||||||
# Thu Jul 03 09:40:53 2014 +1000
|
|
||||||
# Node ID 837348e418f33fc7a242f56dbe2feff829532526
|
|
||||||
# Parent c5f72a685e256457a0872f6587e2bb9500eac7c4
|
|
||||||
archive/tar: reuse temporary buffer in writeHeader
|
|
||||||
|
|
||||||
A temporary 512 bytes buffer is allocated for every call to
|
|
||||||
writeHeader. This buffer could be reused the lower the number
|
|
||||||
of memory allocations.
|
|
||||||
|
|
||||||
benchmark old ns/op new ns/op delta
|
|
||||||
BenchmarkWriteFiles100k 634622051 583810847 -8.01%
|
|
||||||
|
|
||||||
benchmark old allocs new allocs delta
|
|
||||||
BenchmarkWriteFiles100k 2701920 2602621 -3.68%
|
|
||||||
|
|
||||||
benchmark old bytes new bytes delta
|
|
||||||
BenchmarkWriteFiles100k 115383884 64349922 -44.23%
|
|
||||||
|
|
||||||
This change is very important if your code has to write a lot of
|
|
||||||
tarballs with a lot of files.
|
|
||||||
|
|
||||||
LGTM=dsymonds
|
|
||||||
R=golang-codereviews, dave, dsymonds
|
|
||||||
CC=golang-codereviews
|
|
||||||
https://codereview.appspot.com/107440043
|
|
||||||
|
|
||||||
Committer: David Symonds <dsymonds@golang.org>
|
|
||||||
|
|
||||||
diff -r c5f72a685e25 -r 837348e418f3 src/pkg/archive/tar/writer.go
|
|
||||||
--- a/src/pkg/archive/tar/writer.go Wed Jul 02 15:28:57 2014 -0700
|
|
||||||
+++ b/src/pkg/archive/tar/writer.go Thu Jul 03 09:40:53 2014 +1000
|
|
||||||
@@ -37,8 +37,9 @@
|
|
||||||
nb int64 // number of unwritten bytes for current file entry
|
|
||||||
pad int64 // amount of padding to write after current file entry
|
|
||||||
closed bool
|
|
||||||
- usedBinary bool // whether the binary numeric field extension was used
|
|
||||||
- preferPax bool // use pax header instead of binary numeric header
|
|
||||||
+ usedBinary bool // whether the binary numeric field extension was used
|
|
||||||
+ preferPax bool // use pax header instead of binary numeric header
|
|
||||||
+ hdrBuff [blockSize]byte // buffer to use in writeHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWriter creates a new Writer writing to w.
|
|
||||||
@@ -160,7 +161,8 @@
|
|
||||||
// subsecond time resolution, but for now let's just capture
|
|
||||||
// too long fields or non ascii characters
|
|
||||||
|
|
||||||
- header := make([]byte, blockSize)
|
|
||||||
+ header := tw.hdrBuff[:]
|
|
||||||
+ copy(header, zeroBlock)
|
|
||||||
s := slicer(header)
|
|
||||||
|
|
||||||
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
diff -up go/src/runtime/runtime-gdb_test.go.gdb go/src/runtime/runtime-gdb_test.go
|
||||||
|
--- go/src/runtime/runtime-gdb_test.go.gdb 2016-04-28 10:31:13.005689813 +0200
|
||||||
|
+++ go/src/runtime/runtime-gdb_test.go 2016-04-28 10:32:12.202935125 +0200
|
||||||
|
@@ -72,7 +72,7 @@ func main() {
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
-func TestGdbPython(t *testing.T) {
|
||||||
|
+func testGdbPython(t *testing.T) {
|
||||||
|
checkGdbEnvironment(t)
|
||||||
|
checkGdbVersion(t)
|
||||||
|
checkGdbPython(t)
|
|
@ -1,19 +0,0 @@
|
||||||
Index: go/include/u.h
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/include/u.h
|
|
||||||
+++ go/include/u.h
|
|
||||||
@@ -38,10 +38,13 @@ extern "C" {
|
|
||||||
# define __MAKECONTEXT_V2_SOURCE 1
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
+#if defined __linux__ || defined __GNU__ || defined __GLIBC__
|
|
||||||
+#define _DEFAULT_SOURCE 1
|
|
||||||
+#else
|
|
||||||
#define _BSD_SOURCE 1
|
|
||||||
#define _NETBSD_SOURCE 1 /* NetBSD */
|
|
||||||
-#define _DEFAULT_SOURCE 1 /* glibc > 2.19 */
|
|
||||||
#define _SVID_SOURCE 1
|
|
||||||
+#endif
|
|
||||||
#if !defined(__APPLE__) && !defined(__OpenBSD__)
|
|
||||||
# define _XOPEN_SOURCE 1000
|
|
||||||
# define _XOPEN_SOURCE_EXTENDED 1
|
|
|
@ -1,197 +0,0 @@
|
||||||
# HG changeset patch
|
|
||||||
# User Alexander Larsson <alexander.larsson@gmail.com>
|
|
||||||
# Date 1392282510 -39600
|
|
||||||
# Node ID a15f344a9efa35ef168c8feaa92a15a1cdc93db5
|
|
||||||
# Parent 1a32fe60e0798d82bbff6c945001c7f0ba8de5ea
|
|
||||||
archive/tar: support extended attributes
|
|
||||||
|
|
||||||
This adds support for archives with the SCHILY.xattr field in the
|
|
||||||
pax header. This is what gnu tar and star generate.
|
|
||||||
Fixes issue 7154.
|
|
||||||
|
|
||||||
LGTM=dsymonds
|
|
||||||
R=golang-codereviews, gobot, dsymonds
|
|
||||||
CC=golang-codereviews
|
|
||||||
https://codereview.appspot.com/54570043
|
|
||||||
|
|
||||||
Committer: David Symonds <dsymonds@golang.org>
|
|
||||||
|
|
||||||
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/common.go
|
|
||||||
--- a/src/pkg/archive/tar/common.go Thu Feb 13 03:09:03 2014 -0500
|
|
||||||
+++ b/src/pkg/archive/tar/common.go Thu Feb 13 20:08:30 2014 +1100
|
|
||||||
@@ -57,6 +57,7 @@
|
|
||||||
Devminor int64 // minor number of character or block device
|
|
||||||
AccessTime time.Time // access time
|
|
||||||
ChangeTime time.Time // status change time
|
|
||||||
+ Xattrs map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// File name constants from the tar spec.
|
|
||||||
@@ -189,6 +190,7 @@
|
|
||||||
paxSize = "size"
|
|
||||||
paxUid = "uid"
|
|
||||||
paxUname = "uname"
|
|
||||||
+ paxXattr = "SCHILY.xattr."
|
|
||||||
paxNone = ""
|
|
||||||
)
|
|
||||||
|
|
||||||
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/reader.go
|
|
||||||
--- a/src/pkg/archive/tar/reader.go Thu Feb 13 03:09:03 2014 -0500
|
|
||||||
+++ b/src/pkg/archive/tar/reader.go Thu Feb 13 20:08:30 2014 +1100
|
|
||||||
@@ -139,8 +139,14 @@
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hdr.Size = int64(size)
|
|
||||||
+ default:
|
|
||||||
+ if strings.HasPrefix(k, paxXattr) {
|
|
||||||
+ if hdr.Xattrs == nil {
|
|
||||||
+ hdr.Xattrs = make(map[string]string)
|
|
||||||
+ }
|
|
||||||
+ hdr.Xattrs[k[len(paxXattr):]] = v
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
-
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/reader_test.go
|
|
||||||
--- a/src/pkg/archive/tar/reader_test.go Thu Feb 13 03:09:03 2014 -0500
|
|
||||||
+++ b/src/pkg/archive/tar/reader_test.go Thu Feb 13 20:08:30 2014 +1100
|
|
||||||
@@ -161,6 +161,46 @@
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
+ {
|
|
||||||
+ file: "testdata/xattrs.tar",
|
|
||||||
+ headers: []*Header{
|
|
||||||
+ {
|
|
||||||
+ Name: "small.txt",
|
|
||||||
+ Mode: 0644,
|
|
||||||
+ Uid: 1000,
|
|
||||||
+ Gid: 10,
|
|
||||||
+ Size: 5,
|
|
||||||
+ ModTime: time.Unix(1386065770, 448252320),
|
|
||||||
+ Typeflag: '0',
|
|
||||||
+ Uname: "alex",
|
|
||||||
+ Gname: "wheel",
|
|
||||||
+ AccessTime: time.Unix(1389782991, 419875220),
|
|
||||||
+ ChangeTime: time.Unix(1389782956, 794414986),
|
|
||||||
+ Xattrs: map[string]string{
|
|
||||||
+ "user.key": "value",
|
|
||||||
+ "user.key2": "value2",
|
|
||||||
+ // Interestingly, selinux encodes the terminating null inside the xattr
|
|
||||||
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
|
|
||||||
+ },
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ Name: "small2.txt",
|
|
||||||
+ Mode: 0644,
|
|
||||||
+ Uid: 1000,
|
|
||||||
+ Gid: 10,
|
|
||||||
+ Size: 11,
|
|
||||||
+ ModTime: time.Unix(1386065770, 449252304),
|
|
||||||
+ Typeflag: '0',
|
|
||||||
+ Uname: "alex",
|
|
||||||
+ Gname: "wheel",
|
|
||||||
+ AccessTime: time.Unix(1389782991, 419875220),
|
|
||||||
+ ChangeTime: time.Unix(1386065770, 449252304),
|
|
||||||
+ Xattrs: map[string]string{
|
|
||||||
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
|
|
||||||
+ },
|
|
||||||
+ },
|
|
||||||
+ },
|
|
||||||
+ },
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReader(t *testing.T) {
|
|
||||||
@@ -180,7 +220,7 @@
|
|
||||||
f.Close()
|
|
||||||
continue testLoop
|
|
||||||
}
|
|
||||||
- if *hdr != *header {
|
|
||||||
+ if !reflect.DeepEqual(*hdr, *header) {
|
|
||||||
t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
|
|
||||||
i, j, *hdr, *header)
|
|
||||||
}
|
|
||||||
@@ -253,7 +293,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the header
|
|
||||||
- if *hdr != *headers[nread] {
|
|
||||||
+ if !reflect.DeepEqual(*hdr, *headers[nread]) {
|
|
||||||
t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
|
|
||||||
*hdr, headers[nread])
|
|
||||||
}
|
|
||||||
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/writer.go
|
|
||||||
--- a/src/pkg/archive/tar/writer.go Thu Feb 13 03:09:03 2014 -0500
|
|
||||||
+++ b/src/pkg/archive/tar/writer.go Thu Feb 13 20:08:30 2014 +1100
|
|
||||||
@@ -236,6 +236,12 @@
|
|
||||||
return tw.err
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if allowPax {
|
|
||||||
+ for k, v := range hdr.Xattrs {
|
|
||||||
+ paxHeaders[paxXattr+k] = v
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if len(paxHeaders) > 0 {
|
|
||||||
if !allowPax {
|
|
||||||
return errInvalidHeader
|
|
||||||
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/writer_test.go
|
|
||||||
--- a/src/pkg/archive/tar/writer_test.go Thu Feb 13 03:09:03 2014 -0500
|
|
||||||
+++ b/src/pkg/archive/tar/writer_test.go Thu Feb 13 20:08:30 2014 +1100
|
|
||||||
@@ -10,6 +10,7 @@
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
+ "reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"testing/iotest"
|
|
||||||
@@ -338,6 +339,45 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+func TestPaxXattrs(t *testing.T) {
|
|
||||||
+ xattrs := map[string]string{
|
|
||||||
+ "user.key": "value",
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // Create an archive with an xattr
|
|
||||||
+ fileinfo, err := os.Stat("testdata/small.txt")
|
|
||||||
+ if err != nil {
|
|
||||||
+ t.Fatal(err)
|
|
||||||
+ }
|
|
||||||
+ hdr, err := FileInfoHeader(fileinfo, "")
|
|
||||||
+ if err != nil {
|
|
||||||
+ t.Fatalf("os.Stat: %v", err)
|
|
||||||
+ }
|
|
||||||
+ contents := "Kilts"
|
|
||||||
+ hdr.Xattrs = xattrs
|
|
||||||
+ var buf bytes.Buffer
|
|
||||||
+ writer := NewWriter(&buf)
|
|
||||||
+ if err := writer.WriteHeader(hdr); err != nil {
|
|
||||||
+ t.Fatal(err)
|
|
||||||
+ }
|
|
||||||
+ if _, err = writer.Write([]byte(contents)); err != nil {
|
|
||||||
+ t.Fatal(err)
|
|
||||||
+ }
|
|
||||||
+ if err := writer.Close(); err != nil {
|
|
||||||
+ t.Fatal(err)
|
|
||||||
+ }
|
|
||||||
+ // Test that we can get the xattrs back out of the archive.
|
|
||||||
+ reader := NewReader(&buf)
|
|
||||||
+ hdr, err = reader.Next()
|
|
||||||
+ if err != nil {
|
|
||||||
+ t.Fatal(err)
|
|
||||||
+ }
|
|
||||||
+ if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
|
|
||||||
+ t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
|
|
||||||
+ hdr.Xattrs, xattrs)
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
func TestPAXHeader(t *testing.T) {
|
|
||||||
medName := strings.Repeat("CD", 50)
|
|
||||||
longName := strings.Repeat("AB", 100)
|
|
|
@ -1,172 +0,0 @@
|
||||||
Index: go/api/go1.txt
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/api/go1.txt
|
|
||||||
+++ go/api/go1.txt
|
|
||||||
@@ -412,7 +412,6 @@ pkg crypto/ecdsa, type PublicKey struct,
|
|
||||||
pkg crypto/ecdsa, type PublicKey struct, embedded elliptic.Curve
|
|
||||||
pkg crypto/elliptic, func GenerateKey(Curve, io.Reader) ([]uint8, *big.Int, *big.Int, error)
|
|
||||||
pkg crypto/elliptic, func Marshal(Curve, *big.Int, *big.Int) []uint8
|
|
||||||
-pkg crypto/elliptic, func P224() Curve
|
|
||||||
pkg crypto/elliptic, func P256() Curve
|
|
||||||
pkg crypto/elliptic, func P384() Curve
|
|
||||||
pkg crypto/elliptic, func P521() Curve
|
|
||||||
Index: go/src/pkg/crypto/ecdsa/ecdsa_test.go
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/src/pkg/crypto/ecdsa/ecdsa_test.go
|
|
||||||
+++ go/src/pkg/crypto/ecdsa/ecdsa_test.go
|
|
||||||
@@ -33,7 +33,6 @@ func testKeyGeneration(t *testing.T, c e
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeyGeneration(t *testing.T) {
|
|
||||||
- testKeyGeneration(t, elliptic.P224(), "p224")
|
|
||||||
if testing.Short() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -63,7 +62,6 @@ func testSignAndVerify(t *testing.T, c e
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSignAndVerify(t *testing.T) {
|
|
||||||
- testSignAndVerify(t, elliptic.P224(), "p224")
|
|
||||||
if testing.Short() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -129,8 +127,6 @@ func TestVectors(t *testing.T) {
|
|
||||||
parts := strings.SplitN(line, ",", 2)
|
|
||||||
|
|
||||||
switch parts[0] {
|
|
||||||
- case "P-224":
|
|
||||||
- pub.Curve = elliptic.P224()
|
|
||||||
case "P-256":
|
|
||||||
pub.Curve = elliptic.P256()
|
|
||||||
case "P-384":
|
|
||||||
Index: go/src/pkg/crypto/elliptic/bottombits.go
|
|
||||||
===================================================================
|
|
||||||
--- /dev/null
|
|
||||||
+++ go/src/pkg/crypto/elliptic/bottombits.go
|
|
||||||
@@ -0,0 +1,14 @@
|
|
||||||
+
|
|
||||||
+// Copyright 2012 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 elliptic
|
|
||||||
+
|
|
||||||
+const bottom12Bits = 0xfff
|
|
||||||
+const bottom28Bits = 0xfffffff
|
|
||||||
+
|
|
||||||
+const two31p3 = 1<<31 + 1<<3
|
|
||||||
+const two31m3 = 1<<31 - 1<<3
|
|
||||||
+const two31m15m3 = 1<<31 - 1<<15 - 1<<3
|
|
||||||
+
|
|
||||||
Index: go/src/pkg/crypto/elliptic/elliptic.go
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/src/pkg/crypto/elliptic/elliptic.go
|
|
||||||
+++ go/src/pkg/crypto/elliptic/elliptic.go
|
|
||||||
@@ -326,7 +326,6 @@ var p384 *CurveParams
|
|
||||||
var p521 *CurveParams
|
|
||||||
|
|
||||||
func initAll() {
|
|
||||||
- initP224()
|
|
||||||
initP256()
|
|
||||||
initP384()
|
|
||||||
initP521()
|
|
||||||
Index: go/src/pkg/crypto/elliptic/elliptic_test.go
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/src/pkg/crypto/elliptic/elliptic_test.go
|
|
||||||
+++ go/src/pkg/crypto/elliptic/elliptic_test.go
|
|
||||||
@@ -1,3 +1,5 @@
|
|
||||||
+// +build ignore
|
|
||||||
+
|
|
||||||
// Copyright 2010 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.
|
|
||||||
Index: go/src/pkg/crypto/elliptic/p224.go
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/src/pkg/crypto/elliptic/p224.go
|
|
||||||
+++ go/src/pkg/crypto/elliptic/p224.go
|
|
||||||
@@ -1,3 +1,5 @@
|
|
||||||
+// +build ignore
|
|
||||||
+
|
|
||||||
// Copyright 2012 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.
|
|
||||||
@@ -183,10 +185,6 @@ func p224Add(out, a, b *p224FieldElement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-const two31p3 = 1<<31 + 1<<3
|
|
||||||
-const two31m3 = 1<<31 - 1<<3
|
|
||||||
-const two31m15m3 = 1<<31 - 1<<15 - 1<<3
|
|
||||||
-
|
|
||||||
// p224ZeroModP31 is 0 mod p where bit 31 is set in all limbs so that we can
|
|
||||||
// subtract smaller amounts without underflow. See the section "Subtraction" in
|
|
||||||
// [1] for reasoning.
|
|
||||||
@@ -215,9 +213,6 @@ const two63m35m19 = 1<<63 - 1<<35 - 1<<1
|
|
||||||
// "Subtraction" in [1] for why.
|
|
||||||
var p224ZeroModP63 = [8]uint64{two63p35, two63m35, two63m35, two63m35, two63m35m19, two63m35, two63m35, two63m35}
|
|
||||||
|
|
||||||
-const bottom12Bits = 0xfff
|
|
||||||
-const bottom28Bits = 0xfffffff
|
|
||||||
-
|
|
||||||
// p224Mul computes *out = a*b
|
|
||||||
//
|
|
||||||
// a[i] < 2**29, b[i] < 2**30 (or vice versa)
|
|
||||||
Index: go/src/pkg/crypto/elliptic/p224_test.go
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/src/pkg/crypto/elliptic/p224_test.go
|
|
||||||
+++ go/src/pkg/crypto/elliptic/p224_test.go
|
|
||||||
@@ -1,3 +1,5 @@
|
|
||||||
+// +build ignore
|
|
||||||
+
|
|
||||||
// Copyright 2012 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.
|
|
||||||
Index: go/src/pkg/crypto/x509/x509.go
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/src/pkg/crypto/x509/x509.go
|
|
||||||
+++ go/src/pkg/crypto/x509/x509.go
|
|
||||||
@@ -306,9 +306,6 @@ func getPublicKeyAlgorithmFromOID(oid as
|
|
||||||
|
|
||||||
// RFC 5480, 2.1.1.1. Named Curve
|
|
||||||
//
|
|
||||||
-// secp224r1 OBJECT IDENTIFIER ::= {
|
|
||||||
-// iso(1) identified-organization(3) certicom(132) curve(0) 33 }
|
|
||||||
-//
|
|
||||||
// secp256r1 OBJECT IDENTIFIER ::= {
|
|
||||||
// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
|
|
||||||
// prime(1) 7 }
|
|
||||||
@@ -321,7 +318,6 @@ func getPublicKeyAlgorithmFromOID(oid as
|
|
||||||
//
|
|
||||||
// NB: secp256r1 is equivalent to prime256v1
|
|
||||||
var (
|
|
||||||
- oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
|
|
||||||
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
|
|
||||||
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
|
|
||||||
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
|
|
||||||
@@ -329,8 +325,6 @@ var (
|
|
||||||
|
|
||||||
func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
|
|
||||||
switch {
|
|
||||||
- case oid.Equal(oidNamedCurveP224):
|
|
||||||
- return elliptic.P224()
|
|
||||||
case oid.Equal(oidNamedCurveP256):
|
|
||||||
return elliptic.P256()
|
|
||||||
case oid.Equal(oidNamedCurveP384):
|
|
||||||
@@ -343,8 +337,6 @@ func namedCurveFromOID(oid asn1.ObjectId
|
|
||||||
|
|
||||||
func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
|
|
||||||
switch curve {
|
|
||||||
- case elliptic.P224():
|
|
||||||
- return oidNamedCurveP224, true
|
|
||||||
case elliptic.P256():
|
|
||||||
return oidNamedCurveP256, true
|
|
||||||
case elliptic.P384():
|
|
||||||
@@ -1371,7 +1363,7 @@ func signingParamsForPrivateKey(priv int
|
|
||||||
pubType = ECDSA
|
|
||||||
|
|
||||||
switch priv.Curve {
|
|
||||||
- case elliptic.P224(), elliptic.P256():
|
|
||||||
+ case elliptic.P256():
|
|
||||||
hashFunc = crypto.SHA256
|
|
||||||
sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
|
|
||||||
case elliptic.P384():
|
|
|
@ -1,12 +0,0 @@
|
||||||
diff -r 87dea3f5ebe7 src/pkg/runtime/pprof/pprof_test.go
|
|
||||||
--- a/src/pkg/runtime/pprof/pprof_test.go Fri Nov 29 08:32:31 2013 +1100
|
|
||||||
+++ b/src/pkg/runtime/pprof/pprof_test.go Fri Jan 24 13:47:42 2014 -0500
|
|
||||||
@@ -32,7 +32,7 @@
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
-func TestCPUProfileMultithreaded(t *testing.T) {
|
|
||||||
+func testCPUProfileMultithreaded(t *testing.T) {
|
|
||||||
buf := make([]byte, 100000)
|
|
||||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
|
|
||||||
testCPUProfile(t, []string{"crc32.ChecksumIEEE", "crc32.Update"}, func() {
|
|
|
@ -1,19 +0,0 @@
|
||||||
Index: go/src/make.bash
|
|
||||||
===================================================================
|
|
||||||
--- go.orig/src/make.bash
|
|
||||||
+++ go/src/make.bash
|
|
||||||
@@ -161,12 +161,12 @@ if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOH
|
|
||||||
# CC_FOR_TARGET is recorded as the default compiler for the go tool. When building for the host, however,
|
|
||||||
# use the host compiler, CC, from `cmd/dist/dist env` instead.
|
|
||||||
CC=$CC GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
|
|
||||||
- "$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
|
|
||||||
+ "$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v -x std
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "# Building packages and commands for $GOOS/$GOARCH."
|
|
||||||
-CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
|
|
||||||
+CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v -x std
|
|
||||||
echo
|
|
||||||
|
|
||||||
rm -f "$GOTOOLDIR"/go_bootstrap
|
|
|
@ -0,0 +1,309 @@
|
||||||
|
commit a3156aaa121446c4136927f8c2139fefe05ba82c
|
||||||
|
Author: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
Date: Tue Sep 29 14:26:48 2015 -0700
|
||||||
|
|
||||||
|
net/http/httptest: change Server to use http.Server.ConnState for accounting
|
||||||
|
|
||||||
|
With this CL, httptest.Server now uses connection-level accounting of
|
||||||
|
outstanding requests instead of ServeHTTP-level accounting. This is
|
||||||
|
more robust and results in a non-racy shutdown.
|
||||||
|
|
||||||
|
This is much easier now that net/http.Server has the ConnState hook.
|
||||||
|
|
||||||
|
Fixes #12789
|
||||||
|
Fixes #12781
|
||||||
|
|
||||||
|
Change-Id: I098cf334a6494316acb66cd07df90766df41764b
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/15151
|
||||||
|
Reviewed-by: Andrew Gerrand <adg@golang.org>
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
TryBot-Result: Gobot Gobot <gobot@golang.org>
|
||||||
|
|
||||||
|
diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go
|
||||||
|
index 96eb0ef..e4f680f 100644
|
||||||
|
--- a/src/net/http/httptest/server.go
|
||||||
|
+++ b/src/net/http/httptest/server.go
|
||||||
|
@@ -7,13 +7,17 @@
|
||||||
|
package httptest
|
||||||
|
|
||||||
|
import (
|
||||||
|
+ "bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
+ "log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
+ "runtime"
|
||||||
|
"sync"
|
||||||
|
+ "time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Server is an HTTP server listening on a system-chosen port on the
|
||||||
|
@@ -34,24 +38,10 @@ type Server struct {
|
||||||
|
// wg counts the number of outstanding HTTP requests on this server.
|
||||||
|
// Close blocks until all requests are finished.
|
||||||
|
wg sync.WaitGroup
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-// historyListener keeps track of all connections that it's ever
|
||||||
|
-// accepted.
|
||||||
|
-type historyListener struct {
|
||||||
|
- net.Listener
|
||||||
|
- sync.Mutex // protects history
|
||||||
|
- history []net.Conn
|
||||||
|
-}
|
||||||
|
|
||||||
|
-func (hs *historyListener) Accept() (c net.Conn, err error) {
|
||||||
|
- c, err = hs.Listener.Accept()
|
||||||
|
- if err == nil {
|
||||||
|
- hs.Lock()
|
||||||
|
- hs.history = append(hs.history, c)
|
||||||
|
- hs.Unlock()
|
||||||
|
- }
|
||||||
|
- return
|
||||||
|
+ mu sync.Mutex // guards closed and conns
|
||||||
|
+ closed bool
|
||||||
|
+ conns map[net.Conn]http.ConnState // except terminal states
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLocalListener() net.Listener {
|
||||||
|
@@ -103,10 +93,9 @@ func (s *Server) Start() {
|
||||||
|
if s.URL != "" {
|
||||||
|
panic("Server already started")
|
||||||
|
}
|
||||||
|
- s.Listener = &historyListener{Listener: s.Listener}
|
||||||
|
s.URL = "http://" + s.Listener.Addr().String()
|
||||||
|
- s.wrapHandler()
|
||||||
|
- go s.Config.Serve(s.Listener)
|
||||||
|
+ s.wrap()
|
||||||
|
+ s.goServe()
|
||||||
|
if *serve != "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL)
|
||||||
|
select {}
|
||||||
|
@@ -134,23 +123,10 @@ func (s *Server) StartTLS() {
|
||||||
|
if len(s.TLS.Certificates) == 0 {
|
||||||
|
s.TLS.Certificates = []tls.Certificate{cert}
|
||||||
|
}
|
||||||
|
- tlsListener := tls.NewListener(s.Listener, s.TLS)
|
||||||
|
-
|
||||||
|
- s.Listener = &historyListener{Listener: tlsListener}
|
||||||
|
+ s.Listener = tls.NewListener(s.Listener, s.TLS)
|
||||||
|
s.URL = "https://" + s.Listener.Addr().String()
|
||||||
|
- s.wrapHandler()
|
||||||
|
- go s.Config.Serve(s.Listener)
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-func (s *Server) wrapHandler() {
|
||||||
|
- h := s.Config.Handler
|
||||||
|
- if h == nil {
|
||||||
|
- h = http.DefaultServeMux
|
||||||
|
- }
|
||||||
|
- s.Config.Handler = &waitGroupHandler{
|
||||||
|
- s: s,
|
||||||
|
- h: h,
|
||||||
|
- }
|
||||||
|
+ s.wrap()
|
||||||
|
+ s.goServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTLSServer starts and returns a new Server using TLS.
|
||||||
|
@@ -161,43 +137,139 @@ func NewTLSServer(handler http.Handler) *Server {
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
+type closeIdleTransport interface {
|
||||||
|
+ CloseIdleConnections()
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
// Close shuts down the server and blocks until all outstanding
|
||||||
|
// requests on this server have completed.
|
||||||
|
func (s *Server) Close() {
|
||||||
|
- s.Listener.Close()
|
||||||
|
- s.wg.Wait()
|
||||||
|
- s.CloseClientConnections()
|
||||||
|
- if t, ok := http.DefaultTransport.(*http.Transport); ok {
|
||||||
|
+ s.mu.Lock()
|
||||||
|
+ if !s.closed {
|
||||||
|
+ s.closed = true
|
||||||
|
+ s.Listener.Close()
|
||||||
|
+ s.Config.SetKeepAlivesEnabled(false)
|
||||||
|
+ for c, st := range s.conns {
|
||||||
|
+ if st == http.StateIdle {
|
||||||
|
+ s.closeConn(c)
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // If this server doesn't shut down in 5 seconds, tell the user why.
|
||||||
|
+ t := time.AfterFunc(5*time.Second, s.logCloseHangDebugInfo)
|
||||||
|
+ defer t.Stop()
|
||||||
|
+ }
|
||||||
|
+ s.mu.Unlock()
|
||||||
|
+
|
||||||
|
+ // Not part of httptest.Server's correctness, but assume most
|
||||||
|
+ // users of httptest.Server will be using the standard
|
||||||
|
+ // transport, so help them out and close any idle connections for them.
|
||||||
|
+ if t, ok := http.DefaultTransport.(closeIdleTransport); ok {
|
||||||
|
t.CloseIdleConnections()
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ s.wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
-// CloseClientConnections closes any currently open HTTP connections
|
||||||
|
-// to the test Server.
|
||||||
|
+func (s *Server) logCloseHangDebugInfo() {
|
||||||
|
+ s.mu.Lock()
|
||||||
|
+ defer s.mu.Unlock()
|
||||||
|
+ var buf bytes.Buffer
|
||||||
|
+ buf.WriteString("httptest.Server blocked in Close after 5 seconds, waiting for connections:\n")
|
||||||
|
+ for c, st := range s.conns {
|
||||||
|
+ fmt.Fprintf(&buf, " %T %p %v in state %v\n", c, c, c.RemoteAddr(), st)
|
||||||
|
+ }
|
||||||
|
+ log.Print(buf.String())
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// CloseClientConnections closes any open HTTP connections to the test Server.
|
||||||
|
func (s *Server) CloseClientConnections() {
|
||||||
|
- hl, ok := s.Listener.(*historyListener)
|
||||||
|
- if !ok {
|
||||||
|
- return
|
||||||
|
+ s.mu.Lock()
|
||||||
|
+ defer s.mu.Unlock()
|
||||||
|
+ for c := range s.conns {
|
||||||
|
+ s.closeConn(c)
|
||||||
|
}
|
||||||
|
- hl.Lock()
|
||||||
|
- for _, conn := range hl.history {
|
||||||
|
- conn.Close()
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+func (s *Server) goServe() {
|
||||||
|
+ s.wg.Add(1)
|
||||||
|
+ go func() {
|
||||||
|
+ defer s.wg.Done()
|
||||||
|
+ s.Config.Serve(s.Listener)
|
||||||
|
+ }()
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// wrap installs the connection state-tracking hook to know which
|
||||||
|
+// connections are idle.
|
||||||
|
+func (s *Server) wrap() {
|
||||||
|
+ oldHook := s.Config.ConnState
|
||||||
|
+ s.Config.ConnState = func(c net.Conn, cs http.ConnState) {
|
||||||
|
+ s.mu.Lock()
|
||||||
|
+ defer s.mu.Unlock()
|
||||||
|
+ switch cs {
|
||||||
|
+ case http.StateNew:
|
||||||
|
+ s.wg.Add(1)
|
||||||
|
+ if _, exists := s.conns[c]; exists {
|
||||||
|
+ panic("invalid state transition")
|
||||||
|
+ }
|
||||||
|
+ if s.conns == nil {
|
||||||
|
+ s.conns = make(map[net.Conn]http.ConnState)
|
||||||
|
+ }
|
||||||
|
+ s.conns[c] = cs
|
||||||
|
+ if s.closed {
|
||||||
|
+ // Probably just a socket-late-binding dial from
|
||||||
|
+ // the default transport that lost the race (and
|
||||||
|
+ // thus this connection is now idle and will
|
||||||
|
+ // never be used).
|
||||||
|
+ s.closeConn(c)
|
||||||
|
+ }
|
||||||
|
+ case http.StateActive:
|
||||||
|
+ if oldState, ok := s.conns[c]; ok {
|
||||||
|
+ if oldState != http.StateNew && oldState != http.StateIdle {
|
||||||
|
+ panic("invalid state transition")
|
||||||
|
+ }
|
||||||
|
+ s.conns[c] = cs
|
||||||
|
+ }
|
||||||
|
+ case http.StateIdle:
|
||||||
|
+ if oldState, ok := s.conns[c]; ok {
|
||||||
|
+ if oldState != http.StateActive {
|
||||||
|
+ panic("invalid state transition")
|
||||||
|
+ }
|
||||||
|
+ s.conns[c] = cs
|
||||||
|
+ }
|
||||||
|
+ if s.closed {
|
||||||
|
+ s.closeConn(c)
|
||||||
|
+ }
|
||||||
|
+ case http.StateHijacked, http.StateClosed:
|
||||||
|
+ s.forgetConn(c)
|
||||||
|
+ }
|
||||||
|
+ if oldHook != nil {
|
||||||
|
+ oldHook(c, cs)
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
- hl.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
-// waitGroupHandler wraps a handler, incrementing and decrementing a
|
||||||
|
-// sync.WaitGroup on each request, to enable Server.Close to block
|
||||||
|
-// until outstanding requests are finished.
|
||||||
|
-type waitGroupHandler struct {
|
||||||
|
- s *Server
|
||||||
|
- h http.Handler // non-nil
|
||||||
|
+// closeConn closes c. Except on plan9, which is special. See comment below.
|
||||||
|
+// s.mu must be held.
|
||||||
|
+func (s *Server) closeConn(c net.Conn) {
|
||||||
|
+ if runtime.GOOS == "plan9" {
|
||||||
|
+ // Go's Plan 9 net package isn't great at unblocking reads when
|
||||||
|
+ // their underlying TCP connections are closed. Don't trust
|
||||||
|
+ // that that the ConnState state machine will get to
|
||||||
|
+ // StateClosed. Instead, just go there directly. Plan 9 may leak
|
||||||
|
+ // resources if the syscall doesn't end up returning. Oh well.
|
||||||
|
+ s.forgetConn(c)
|
||||||
|
+ }
|
||||||
|
+ go c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
-func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
- h.s.wg.Add(1)
|
||||||
|
- defer h.s.wg.Done() // a defer, in case ServeHTTP below panics
|
||||||
|
- h.h.ServeHTTP(w, r)
|
||||||
|
+// forgetConn removes c from the set of tracked conns and decrements it from the
|
||||||
|
+// waitgroup, unless it was previously removed.
|
||||||
|
+// s.mu must be held.
|
||||||
|
+func (s *Server) forgetConn(c net.Conn) {
|
||||||
|
+ if _, ok := s.conns[c]; ok {
|
||||||
|
+ delete(s.conns, c)
|
||||||
|
+ s.wg.Done()
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
// localhostCert is a PEM-encoded TLS cert with SAN IPs
|
||||||
|
diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go
|
||||||
|
index 500a9f0..90901ce 100644
|
||||||
|
--- a/src/net/http/httptest/server_test.go
|
||||||
|
+++ b/src/net/http/httptest/server_test.go
|
||||||
|
@@ -27,3 +27,30 @@ func TestServer(t *testing.T) {
|
||||||
|
t.Errorf("got %q, want hello", string(got))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+// Issue 12781
|
||||||
|
+func TestGetAfterClose(t *testing.T) {
|
||||||
|
+ ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
+ w.Write([]byte("hello"))
|
||||||
|
+ }))
|
||||||
|
+
|
||||||
|
+ res, err := http.Get(ts.URL)
|
||||||
|
+ if err != nil {
|
||||||
|
+ t.Fatal(err)
|
||||||
|
+ }
|
||||||
|
+ got, err := ioutil.ReadAll(res.Body)
|
||||||
|
+ if err != nil {
|
||||||
|
+ t.Fatal(err)
|
||||||
|
+ }
|
||||||
|
+ if string(got) != "hello" {
|
||||||
|
+ t.Fatalf("got %q, want hello", string(got))
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ts.Close()
|
||||||
|
+
|
||||||
|
+ res, err = http.Get(ts.URL)
|
||||||
|
+ if err == nil {
|
||||||
|
+ body, _ := ioutil.ReadAll(res.Body)
|
||||||
|
+ t.Fatalf("Unexected response after close: %v, %v, %s", res.Status, res.Header, body)
|
||||||
|
+ }
|
||||||
|
+}
|
|
@ -1,11 +0,0 @@
|
||||||
--- src/pkg/os/os_test.go.orig 2014-02-20 13:14:45.543644182 -0600
|
|
||||||
+++ src/pkg/os/os_test.go 2014-02-20 13:14:55.934813622 -0600
|
|
||||||
@@ -854,7 +854,7 @@
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer r.Close()
|
|
||||||
- p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
|
|
||||||
+ p, err := StartProcess("/usr/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
|
@ -1 +1 @@
|
||||||
add-auto-load-safe-path /usr/lib/golang/src/pkg/runtime/runtime-gdb.py
|
add-auto-load-safe-path /usr/lib/golang/src/runtime/runtime-gdb.py
|
||||||
|
|
1300
golang.spec
1300
golang.spec
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,457 @@
|
||||||
|
From d6beea7f9ea1aa2ae5abca7fccb252767820aa13 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lynn Boger <laboger@linux.vnet.ibm.com>
|
||||||
|
Date: Tue, 26 Jul 2016 08:51:10 -0500
|
||||||
|
Subject: [PATCH] cmd/link: split large elf text sections for ppc64x
|
||||||
|
|
||||||
|
Some applications built with Go on ppc64x with
|
||||||
|
external linking can fail to link with relocation
|
||||||
|
truncation errors, due to the way that the golang
|
||||||
|
compiler generates a single go.o file containing
|
||||||
|
a single large text section to send to the GNU
|
||||||
|
linker. If the size of the single text section is
|
||||||
|
greater than 2^26, this can lead to link errors
|
||||||
|
due to 24 bit offset field in the bl (call)
|
||||||
|
instruction.
|
||||||
|
|
||||||
|
This fix solves the problem by splitting into
|
||||||
|
multiple text sections when this limit is reached.
|
||||||
|
When this is done then the GNU linker can fix the
|
||||||
|
long calls and insert jump tables where needed.
|
||||||
|
---
|
||||||
|
src/cmd/link/internal/ld/data.go | 52 +++++++++++++++++++++++++++++--
|
||||||
|
src/cmd/link/internal/ld/elf.go | 60 ++++++++++++++++++++++++++++++++---
|
||||||
|
src/cmd/link/internal/ld/lib.go | 20 ++++++++++++
|
||||||
|
src/cmd/link/internal/ld/symtab.go | 64 ++++++++++++++++++++++++++++++++++++++
|
||||||
|
src/cmd/link/internal/ppc64/asm.go | 12 ++++---
|
||||||
|
src/runtime/symtab.go | 34 +++++++++++++++-----
|
||||||
|
src/runtime/type.go | 16 +++++++++-
|
||||||
|
7 files changed, 237 insertions(+), 21 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
|
||||||
|
index 57a0dad..58ce18c 100644
|
||||||
|
--- a/src/cmd/link/internal/ld/data.go
|
||||||
|
+++ b/src/cmd/link/internal/ld/data.go
|
||||||
|
@@ -527,7 +527,15 @@ func relocsym(s *LSym) {
|
||||||
|
o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
|
||||||
|
|
||||||
|
case obj.R_ADDROFF:
|
||||||
|
- o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
|
||||||
|
+
|
||||||
|
+ // The method offset tables using this relocation expect the offset to be relative
|
||||||
|
+ // to the start of the first text section, even if there are multiple.
|
||||||
|
+
|
||||||
|
+ if Linkmode == LinkExternal && r.Sym.Sect.Name == ".text" && r.Sym.Sect.Vaddr != Segtext.Vaddr {
|
||||||
|
+ o = Symaddr(r.Sym) - int64(Segtext.Vaddr) + r.Add
|
||||||
|
+ } else {
|
||||||
|
+ o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
|
||||||
|
+ }
|
||||||
|
|
||||||
|
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
|
||||||
|
case obj.R_CALL, obj.R_GOTPCREL, obj.R_PCREL:
|
||||||
|
@@ -1926,6 +1934,7 @@ func textaddress() {
|
||||||
|
}
|
||||||
|
va := uint64(INITTEXT)
|
||||||
|
sect.Vaddr = va
|
||||||
|
+ n := 1
|
||||||
|
for _, sym := range Ctxt.Textp {
|
||||||
|
sym.Sect = sect
|
||||||
|
if sym.Type&obj.SSUB != 0 {
|
||||||
|
@@ -1948,9 +1957,30 @@ func textaddress() {
|
||||||
|
} else {
|
||||||
|
va += uint64(sym.Size)
|
||||||
|
}
|
||||||
|
+ // On ppc64x a text section should not be larger than 2^26 bytes due to the size of
|
||||||
|
+ // call target offset field in the bl instruction. Splitting into text
|
||||||
|
+ // sections smaller than this limit allows the GNU linker to modify the long calls
|
||||||
|
+ // appropriately. The limit allows for the space for linker tables.
|
||||||
|
+
|
||||||
|
+ // Only break at outermost syms.
|
||||||
|
+
|
||||||
|
+ if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > uint64(0x1c00000) {
|
||||||
|
+
|
||||||
|
+ // Set the length for the previous text section
|
||||||
|
+ sect.Length = va - sect.Vaddr
|
||||||
|
+
|
||||||
|
+ // Create new section, set the starting Vaddr
|
||||||
|
+ sect = addsection(&Segtext, ".text", 05)
|
||||||
|
+ sect.Vaddr = va
|
||||||
|
+
|
||||||
|
+ // Create a symbol for the start and end of the secondary text section
|
||||||
|
+ Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
|
||||||
|
+ n++
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
sect.Length = va - sect.Vaddr
|
||||||
|
+ Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign addresses
|
||||||
|
@@ -2057,11 +2087,27 @@ func address() {
|
||||||
|
Segdwarf.Filelen = va - Segdwarf.Vaddr
|
||||||
|
|
||||||
|
text := Segtext.Sect
|
||||||
|
+ lasttext := text
|
||||||
|
var rodata *Section
|
||||||
|
if Segrodata.Sect != nil {
|
||||||
|
rodata = Segrodata.Sect
|
||||||
|
} else {
|
||||||
|
- rodata = text.Next
|
||||||
|
+ // Could be multiple .text sections
|
||||||
|
+ n := 1
|
||||||
|
+ for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
+ if sect.Name != ".text" {
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
+ lasttext = sect
|
||||||
|
+ symname := fmt.Sprintf("runtime.text.%d", n)
|
||||||
|
+ xdefine(symname, obj.STEXT, int64(sect.Vaddr))
|
||||||
|
+ n++
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ rodata = lasttext.Next
|
||||||
|
+ if rodata != nil && rodata.Name != ".rodata" {
|
||||||
|
+ Diag("Unexpected section order in text segment")
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
var relrodata *Section
|
||||||
|
typelink := rodata.Next
|
||||||
|
@@ -2108,7 +2154,7 @@ func address() {
|
||||||
|
}
|
||||||
|
|
||||||
|
xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
|
||||||
|
- xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
|
||||||
|
+ xdefine("runtime.etext", obj.STEXT, int64(lasttext.Vaddr+lasttext.Length))
|
||||||
|
if HEADTYPE == obj.Hwindows {
|
||||||
|
xdefine(".text", obj.STEXT, int64(text.Vaddr))
|
||||||
|
}
|
||||||
|
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
|
||||||
|
index 39d3609..ecb00c2 100644
|
||||||
|
--- a/src/cmd/link/internal/ld/elf.go
|
||||||
|
+++ b/src/cmd/link/internal/ld/elf.go
|
||||||
|
@@ -1623,6 +1623,25 @@ func elfshname(name string) *ElfShdr {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
+// Create an ElfShdr for the section with name.
|
||||||
|
+// A new one is created even if one already exists with
|
||||||
|
+// the same name.
|
||||||
|
+func elfshnamedup(name string) *ElfShdr {
|
||||||
|
+ var off int
|
||||||
|
+ var sh *ElfShdr
|
||||||
|
+
|
||||||
|
+ for i := 0; i < nelfstr; i++ {
|
||||||
|
+ if name == elfstr[i].s {
|
||||||
|
+ off = elfstr[i].off
|
||||||
|
+ sh = newElfShdr(int64(off))
|
||||||
|
+ return sh
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ Diag("cannot find elf name %s", name)
|
||||||
|
+ errorexit()
|
||||||
|
+ return nil
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
func elfshalloc(sect *Section) *ElfShdr {
|
||||||
|
sh := elfshname(sect.Name)
|
||||||
|
sect.Elfsect = sh
|
||||||
|
@@ -1630,7 +1649,17 @@ func elfshalloc(sect *Section) *ElfShdr {
|
||||||
|
}
|
||||||
|
|
||||||
|
func elfshbits(sect *Section) *ElfShdr {
|
||||||
|
- sh := elfshalloc(sect)
|
||||||
|
+ var sh *ElfShdr
|
||||||
|
+
|
||||||
|
+ if sect.Name == ".text" {
|
||||||
|
+ if sect.Elfsect == nil {
|
||||||
|
+ sect.Elfsect = elfshnamedup(sect.Name)
|
||||||
|
+ }
|
||||||
|
+ sh = sect.Elfsect
|
||||||
|
+ } else {
|
||||||
|
+ sh = elfshalloc(sect)
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// If this section has already been set up as a note, we assume type_ and
|
||||||
|
// flags are already correct, but the other fields still need filling in.
|
||||||
|
if sh.type_ == SHT_NOTE {
|
||||||
|
@@ -1706,6 +1735,15 @@ func elfshreloc(sect *Section) *ElfShdr {
|
||||||
|
}
|
||||||
|
|
||||||
|
sh := elfshname(elfRelType + sect.Name)
|
||||||
|
+
|
||||||
|
+ // There could be multiple text sections but each needs
|
||||||
|
+ // its own .rela.text.
|
||||||
|
+ if sect.Name == ".text" {
|
||||||
|
+ if sh.info != 0 && sh.info != uint32(sect.Elfsect.shnum) {
|
||||||
|
+ sh = elfshnamedup(elfRelType + sect.Name)
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
sh.type_ = uint32(typ)
|
||||||
|
sh.entsize = uint64(SysArch.RegSize) * 2
|
||||||
|
if typ == SHT_RELA {
|
||||||
|
@@ -1776,9 +1814,12 @@ func Elfemitreloc() {
|
||||||
|
Cput(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
- elfrelocsect(Segtext.Sect, Ctxt.Textp)
|
||||||
|
- for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
- elfrelocsect(sect, datap)
|
||||||
|
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||||
|
+ if sect.Name == ".text" {
|
||||||
|
+ elfrelocsect(sect, Ctxt.Textp)
|
||||||
|
+ } else {
|
||||||
|
+ elfrelocsect(sect, datap)
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
|
||||||
|
elfrelocsect(sect, datap)
|
||||||
|
@@ -2109,7 +2150,16 @@ func Asmbelfsetup() {
|
||||||
|
elfshname("")
|
||||||
|
|
||||||
|
for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||||
|
- elfshalloc(sect)
|
||||||
|
+
|
||||||
|
+ // There could be multiple .text sections. Instead check the Elfsect
|
||||||
|
+ // field to determine if already has an ElfShdr and if not, create one.
|
||||||
|
+ if sect.Name == ".text" {
|
||||||
|
+ if sect.Elfsect == nil {
|
||||||
|
+ sect.Elfsect = elfshnamedup(sect.Name)
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ elfshalloc(sect)
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
|
||||||
|
elfshalloc(sect)
|
||||||
|
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
|
||||||
|
index 14f4fa9..709e7ca 100644
|
||||||
|
--- a/src/cmd/link/internal/ld/lib.go
|
||||||
|
+++ b/src/cmd/link/internal/ld/lib.go
|
||||||
|
@@ -1956,6 +1956,26 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
|
||||||
|
if s.Type == obj.STEXT {
|
||||||
|
put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
|
||||||
|
}
|
||||||
|
+ n := 0
|
||||||
|
+
|
||||||
|
+ // Generate base addresses for all text sections if there are multiple
|
||||||
|
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||||
|
+ if n == 0 {
|
||||||
|
+ n++
|
||||||
|
+ continue
|
||||||
|
+ }
|
||||||
|
+ if sect.Name != ".text" {
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
+ s = Linkrlookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0)
|
||||||
|
+ if s == nil {
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
+ if s.Type == obj.STEXT {
|
||||||
|
+ put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
|
||||||
|
+ }
|
||||||
|
+ n++
|
||||||
|
+ }
|
||||||
|
s = Linklookup(Ctxt, "runtime.etext", 0)
|
||||||
|
if s.Type == obj.STEXT {
|
||||||
|
put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
|
||||||
|
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
|
||||||
|
index 06d7792..80eb33d 100644
|
||||||
|
--- a/src/cmd/link/internal/ld/symtab.go
|
||||||
|
+++ b/src/cmd/link/internal/ld/symtab.go
|
||||||
|
@@ -315,6 +315,62 @@ func (libs byPkg) Swap(a, b int) {
|
||||||
|
libs[a], libs[b] = libs[b], libs[a]
|
||||||
|
}
|
||||||
|
|
||||||
|
+// Create a table with information on the text sections.
|
||||||
|
+
|
||||||
|
+func textsectionmap() uint32 {
|
||||||
|
+
|
||||||
|
+ t := Linklookup(Ctxt, "runtime.textsectionmap", 0)
|
||||||
|
+ t.Type = obj.SRODATA
|
||||||
|
+ t.Attr |= AttrReachable
|
||||||
|
+ nsections := int64(0)
|
||||||
|
+
|
||||||
|
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||||
|
+ if sect.Name == ".text" {
|
||||||
|
+ nsections++
|
||||||
|
+ } else {
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ Symgrow(Ctxt, t, nsections*3*8)
|
||||||
|
+
|
||||||
|
+ off := int64(0)
|
||||||
|
+ n := 0
|
||||||
|
+
|
||||||
|
+ // The vaddr for each text section is the difference between the section's
|
||||||
|
+ // Vaddr and the Vaddr for the first text section as determined at compile
|
||||||
|
+ // time.
|
||||||
|
+
|
||||||
|
+ // The symbol name for the start address of the first text section is
|
||||||
|
+ // runtime.text. Additional text sections are named runtime.text.n where n is the
|
||||||
|
+ // order of creation starting with 1. These symbols provide the section's
|
||||||
|
+ // start address after relocation by the linker.
|
||||||
|
+
|
||||||
|
+ textbase := Segtext.Sect.Vaddr
|
||||||
|
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||||
|
+ if sect.Name != ".text" {
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
+ off = setuintxx(Ctxt, t, off, sect.Vaddr-textbase, int64(SysArch.IntSize))
|
||||||
|
+ off = setuintxx(Ctxt, t, off, sect.Length, int64(SysArch.IntSize))
|
||||||
|
+ if n == 0 {
|
||||||
|
+ s := Linkrlookup(Ctxt, "runtime.text", 0)
|
||||||
|
+ if s == nil {
|
||||||
|
+ Diag("Unable to find symbol runtime.text\n")
|
||||||
|
+ }
|
||||||
|
+ off = setaddr(Ctxt, t, off, s)
|
||||||
|
+
|
||||||
|
+ } else {
|
||||||
|
+ s := Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0)
|
||||||
|
+ if s == nil {
|
||||||
|
+ Diag("Unable to find symbol runtime.text.%d\n", n)
|
||||||
|
+ }
|
||||||
|
+ off = setaddr(Ctxt, t, off, s)
|
||||||
|
+ }
|
||||||
|
+ n++
|
||||||
|
+ }
|
||||||
|
+ return uint32(n)
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
func symtab() {
|
||||||
|
dosymtype()
|
||||||
|
|
||||||
|
@@ -489,6 +545,8 @@ func symtab() {
|
||||||
|
adduint(Ctxt, abihashgostr, uint64(hashsym.Size))
|
||||||
|
}
|
||||||
|
|
||||||
|
+ nsections := textsectionmap()
|
||||||
|
+
|
||||||
|
// Information about the layout of the executable image for the
|
||||||
|
// runtime to use. Any changes here must be matched by changes to
|
||||||
|
// the definition of moduledata in runtime/symtab.go.
|
||||||
|
@@ -527,6 +585,12 @@ func symtab() {
|
||||||
|
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0))
|
||||||
|
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.types", 0))
|
||||||
|
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypes", 0))
|
||||||
|
+
|
||||||
|
+ // text section information
|
||||||
|
+ Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.textsectionmap", 0))
|
||||||
|
+ adduint(Ctxt, moduledata, uint64(nsections))
|
||||||
|
+ adduint(Ctxt, moduledata, uint64(nsections))
|
||||||
|
+
|
||||||
|
// The typelinks slice
|
||||||
|
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
|
||||||
|
adduint(Ctxt, moduledata, uint64(ntypelinks))
|
||||||
|
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
|
||||||
|
index bd2e23f..ab59fa8 100644
|
||||||
|
--- a/src/cmd/link/internal/ppc64/asm.go
|
||||||
|
+++ b/src/cmd/link/internal/ppc64/asm.go
|
||||||
|
@@ -813,12 +813,14 @@ func asmb() {
|
||||||
|
ld.Asmbelfsetup()
|
||||||
|
}
|
||||||
|
|
||||||
|
- sect := ld.Segtext.Sect
|
||||||
|
- ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
- ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
- for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
+ for sect := ld.Segtext.Sect; sect != nil; sect = sect.Next {
|
||||||
|
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||||
|
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
+ // Might have multiple text sections
|
||||||
|
+ if sect.Name == ".text" {
|
||||||
|
+ ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
+ } else {
|
||||||
|
+ ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Segrodata.Filelen > 0 {
|
||||||
|
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
|
||||||
|
index 4f6fae2..23e80ce 100644
|
||||||
|
--- a/src/runtime/symtab.go
|
||||||
|
+++ b/src/runtime/symtab.go
|
||||||
|
@@ -195,8 +195,9 @@ type moduledata struct {
|
||||||
|
end, gcdata, gcbss uintptr
|
||||||
|
types, etypes uintptr
|
||||||
|
|
||||||
|
- typelinks []int32 // offsets from types
|
||||||
|
- itablinks []*itab
|
||||||
|
+ textsectmap []textsect
|
||||||
|
+ typelinks []int32 // offsets from types
|
||||||
|
+ itablinks []*itab
|
||||||
|
|
||||||
|
modulename string
|
||||||
|
modulehashes []modulehash
|
||||||
|
@@ -226,6 +227,14 @@ type functab struct {
|
||||||
|
funcoff uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
+// Mapping information for secondary text sections
|
||||||
|
+
|
||||||
|
+type textsect struct {
|
||||||
|
+ vaddr uint64 // prelinked section vaddr
|
||||||
|
+ length uint64 // section length
|
||||||
|
+ baseaddr uintptr // relocated section address
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
const minfunc = 16 // minimum function size
|
||||||
|
const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
|
||||||
|
|
||||||
|
@@ -368,12 +377,23 @@ func findfunc(pc uintptr) *_func {
|
||||||
|
ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
|
||||||
|
idx := ffb.idx + uint32(ffb.subbuckets[i])
|
||||||
|
if pc < datap.ftab[idx].entry {
|
||||||
|
- throw("findfunc: bad findfunctab entry")
|
||||||
|
- }
|
||||||
|
|
||||||
|
- // linear search to find func with pc >= entry.
|
||||||
|
- for datap.ftab[idx+1].entry <= pc {
|
||||||
|
- idx++
|
||||||
|
+ // If there are multiple text sections then the buckets for the secondary
|
||||||
|
+ // text sections will be off because the addresses in those text sections
|
||||||
|
+ // were relocated to higher addresses. Search back to find it.
|
||||||
|
+
|
||||||
|
+ for datap.ftab[idx].entry > pc && idx > 0 {
|
||||||
|
+ idx--
|
||||||
|
+ }
|
||||||
|
+ if idx == 0 {
|
||||||
|
+ throw("findfunc: bad findfunctab entry idx")
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+
|
||||||
|
+ // linear search to find func with pc >= entry.
|
||||||
|
+ for datap.ftab[idx+1].entry <= pc {
|
||||||
|
+ idx++
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
|
||||||
|
}
|
||||||
|
diff --git a/src/runtime/type.go b/src/runtime/type.go
|
||||||
|
index 5ef11a4..f641adc 100644
|
||||||
|
--- a/src/runtime/type.go
|
||||||
|
+++ b/src/runtime/type.go
|
||||||
|
@@ -257,7 +257,21 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
- res := md.text + uintptr(off)
|
||||||
|
+ res := uintptr(0)
|
||||||
|
+
|
||||||
|
+ // Find the text section range that contains the offset to determine the section's base
|
||||||
|
+ // address. In cases where there are multiple text sections, the base address might be
|
||||||
|
+ // relocated by the linker.
|
||||||
|
+
|
||||||
|
+ for i := 0; i < len(md.textsectmap); i++ {
|
||||||
|
+ sectaddr := md.textsectmap[i].vaddr
|
||||||
|
+ sectlen := md.textsectmap[i].length
|
||||||
|
+ if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen {
|
||||||
|
+ res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if res > md.etext {
|
||||||
|
println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext))
|
||||||
|
throw("runtime: text offset out of range")
|
|
@ -0,0 +1,150 @@
|
||||||
|
From a5b97a846d70cd8db7f33c24f2b9159f935ce318 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lynn Boger <laboger@linux.vnet.ibm.com>
|
||||||
|
Date: Tue, 13 Sep 2016 15:13:08 -0500
|
||||||
|
Subject: [PATCH] cmd/compile: large text sections on ppc64le
|
||||||
|
|
||||||
|
Additional fixes as submitted upstream.
|
||||||
|
---
|
||||||
|
src/cmd/link/internal/ld/data.go | 24 ++++++++++++------------
|
||||||
|
src/cmd/link/internal/ld/lib.go | 2 +-
|
||||||
|
src/cmd/link/internal/ld/symtab.go | 2 +-
|
||||||
|
src/runtime/type.go | 28 ++++++++++++++++++----------
|
||||||
|
4 files changed, 32 insertions(+), 24 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
|
||||||
|
index 58ce18c..d8e43ff 100644
|
||||||
|
--- a/src/cmd/link/internal/ld/data.go
|
||||||
|
+++ b/src/cmd/link/internal/ld/data.go
|
||||||
|
@@ -531,7 +531,7 @@ func relocsym(s *LSym) {
|
||||||
|
// The method offset tables using this relocation expect the offset to be relative
|
||||||
|
// to the start of the first text section, even if there are multiple.
|
||||||
|
|
||||||
|
- if Linkmode == LinkExternal && r.Sym.Sect.Name == ".text" && r.Sym.Sect.Vaddr != Segtext.Vaddr {
|
||||||
|
+ if r.Sym.Sect.Name == ".text" {
|
||||||
|
o = Symaddr(r.Sym) - int64(Segtext.Vaddr) + r.Add
|
||||||
|
} else {
|
||||||
|
o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
|
||||||
|
@@ -1928,7 +1928,6 @@ func textaddress() {
|
||||||
|
|
||||||
|
sect.Align = int32(Funcalign)
|
||||||
|
Linklookup(Ctxt, "runtime.text", 0).Sect = sect
|
||||||
|
- Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
|
||||||
|
if HEADTYPE == obj.Hwindows {
|
||||||
|
Linklookup(Ctxt, ".text", 0).Sect = sect
|
||||||
|
}
|
||||||
|
@@ -1964,7 +1963,7 @@ func textaddress() {
|
||||||
|
|
||||||
|
// Only break at outermost syms.
|
||||||
|
|
||||||
|
- if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > uint64(0x1c00000) {
|
||||||
|
+ if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > 0x1c00000 {
|
||||||
|
|
||||||
|
// Set the length for the previous text section
|
||||||
|
sect.Length = va - sect.Vaddr
|
||||||
|
@@ -1973,7 +1972,7 @@ func textaddress() {
|
||||||
|
sect = addsection(&Segtext, ".text", 05)
|
||||||
|
sect.Vaddr = va
|
||||||
|
|
||||||
|
- // Create a symbol for the start and end of the secondary text section
|
||||||
|
+ // Create a symbol for the start of the secondary text section
|
||||||
|
Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
@@ -2093,15 +2092,8 @@ func address() {
|
||||||
|
rodata = Segrodata.Sect
|
||||||
|
} else {
|
||||||
|
// Could be multiple .text sections
|
||||||
|
- n := 1
|
||||||
|
- for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
|
||||||
|
- if sect.Name != ".text" {
|
||||||
|
- break
|
||||||
|
- }
|
||||||
|
+ for sect := Segtext.Sect.Next; sect != nil && sect.Name == ".text"; sect = sect.Next {
|
||||||
|
lasttext = sect
|
||||||
|
- symname := fmt.Sprintf("runtime.text.%d", n)
|
||||||
|
- xdefine(symname, obj.STEXT, int64(sect.Vaddr))
|
||||||
|
- n++
|
||||||
|
}
|
||||||
|
|
||||||
|
rodata = lasttext.Next
|
||||||
|
@@ -2155,6 +2147,14 @@ func address() {
|
||||||
|
|
||||||
|
xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
|
||||||
|
xdefine("runtime.etext", obj.STEXT, int64(lasttext.Vaddr+lasttext.Length))
|
||||||
|
+
|
||||||
|
+ n := 1
|
||||||
|
+ for sect := Segtext.Sect.Next; sect != nil && sect.Name == ".text"; sect = sect.Next {
|
||||||
|
+ symname := fmt.Sprintf("runtime.text.%d", n)
|
||||||
|
+ xdefine(symname, obj.STEXT, int64(sect.Vaddr))
|
||||||
|
+ n++
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if HEADTYPE == obj.Hwindows {
|
||||||
|
xdefine(".text", obj.STEXT, int64(text.Vaddr))
|
||||||
|
}
|
||||||
|
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
|
||||||
|
index 709e7ca..c37ef92 100644
|
||||||
|
--- a/src/cmd/link/internal/ld/lib.go
|
||||||
|
+++ b/src/cmd/link/internal/ld/lib.go
|
||||||
|
@@ -1958,7 +1958,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
|
||||||
|
}
|
||||||
|
n := 0
|
||||||
|
|
||||||
|
- // Generate base addresses for all text sections if there are multiple
|
||||||
|
+ // Generate base addresses for all text sections if there are multiple.
|
||||||
|
for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||||
|
if n == 0 {
|
||||||
|
n++
|
||||||
|
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
|
||||||
|
index 80eb33d..ec26f88 100644
|
||||||
|
--- a/src/cmd/link/internal/ld/symtab.go
|
||||||
|
+++ b/src/cmd/link/internal/ld/symtab.go
|
||||||
|
@@ -331,7 +331,7 @@ func textsectionmap() uint32 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- Symgrow(Ctxt, t, nsections*3*8)
|
||||||
|
+ Symgrow(Ctxt, t, nsections*(2*int64(SysArch.IntSize)+int64(SysArch.PtrSize)))
|
||||||
|
|
||||||
|
off := int64(0)
|
||||||
|
n := 0
|
||||||
|
diff --git a/src/runtime/type.go b/src/runtime/type.go
|
||||||
|
index f641adc..d4df5a9 100644
|
||||||
|
--- a/src/runtime/type.go
|
||||||
|
+++ b/src/runtime/type.go
|
||||||
|
@@ -259,17 +259,25 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
|
||||||
|
}
|
||||||
|
res := uintptr(0)
|
||||||
|
|
||||||
|
- // Find the text section range that contains the offset to determine the section's base
|
||||||
|
- // address. In cases where there are multiple text sections, the base address might be
|
||||||
|
- // relocated by the linker.
|
||||||
|
-
|
||||||
|
- for i := 0; i < len(md.textsectmap); i++ {
|
||||||
|
- sectaddr := md.textsectmap[i].vaddr
|
||||||
|
- sectlen := md.textsectmap[i].length
|
||||||
|
- if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen {
|
||||||
|
- res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
|
||||||
|
- break
|
||||||
|
+ // The text, or instruction stream is generated as one large buffer. The off (offset) for a method is
|
||||||
|
+ // its offset within this buffer. If the total text size gets too large, there can be issues on platforms like ppc64 if
|
||||||
|
+ // the target of calls are too far for the call instruction. To resolve the large text issue, the text is split
|
||||||
|
+ // into multiple text sections to allow the linker to generate long calls when necessary. When this happens, the vaddr
|
||||||
|
+ // for each text section is set to its offset within the text. Each method's offset is compared against the section
|
||||||
|
+ // vaddrs and sizes to determine the containing section. Then the section relative offset is added to the section's
|
||||||
|
+ // relocated baseaddr to compute the method addess.
|
||||||
|
+
|
||||||
|
+ if len(md.textsectmap) > 1 {
|
||||||
|
+ for i := 0; i < len(md.textsectmap); i++ {
|
||||||
|
+ sectaddr := md.textsectmap[i].vaddr
|
||||||
|
+ sectlen := md.textsectmap[i].length
|
||||||
|
+ if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen {
|
||||||
|
+ res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
|
||||||
|
+ break
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
+ } else {
|
||||||
|
+ res = md.text + uintptr(off)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res > md.etext {
|
3
sources
3
sources
|
@ -1,2 +1 @@
|
||||||
d76dc07e475b2905b5fec1cf319b6356 golang-19087:a15f344a9efa-xattrs.tar
|
SHA512 (go1.11.2.src.tar.gz) = 3d9b182718c7615975a4b47cecb9ff2a8ce62156461e4112452c14617ea226121e7ab736a469050f14c89861cc4934ddd2df295b80fffff0a2dd6c155eaf0aee
|
||||||
2cdbad6baefcf1007f3cf54a5bc878b7 go1.3.3.src.tar.gz
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
From 8890527476e25747f063377d637b106db0008329 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alberto Donizetti <alb.donizetti@gmail.com>
|
||||||
|
Date: Thu, 9 Mar 2017 13:20:54 +0100
|
||||||
|
Subject: [PATCH] [release-branch.go1.8] time: make the ParseInLocation test
|
||||||
|
more robust
|
||||||
|
|
||||||
|
The tzdata 2017a update (2017-02-28) changed the abbreviation of the
|
||||||
|
Asia/Baghdad time zone (used in TestParseInLocation) from 'AST' to the
|
||||||
|
numeric '+03'.
|
||||||
|
|
||||||
|
Update the test so that it skips the checks if we're using a recent
|
||||||
|
tzdata release.
|
||||||
|
|
||||||
|
Fixes #19457
|
||||||
|
|
||||||
|
Change-Id: I45d705a5520743a611bdd194dc8f8d618679980c
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/37964
|
||||||
|
Reviewed-by: Ian Lance Taylor <iant@golang.org>
|
||||||
|
Run-TryBot: Ian Lance Taylor <iant@golang.org>
|
||||||
|
TryBot-Result: Gobot Gobot <gobot@golang.org>
|
||||||
|
(cherry picked from commit 91563ced5897faf729a34be7081568efcfedda31)
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/37991
|
||||||
|
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
---
|
||||||
|
src/time/format_test.go | 41 +++++++++++++++++++++++++++++++----------
|
||||||
|
1 file changed, 31 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/time/format_test.go b/src/time/format_test.go
|
||||||
|
index 219c2ca..d0013bc 100644
|
||||||
|
--- a/src/time/format_test.go
|
||||||
|
+++ b/src/time/format_test.go
|
||||||
|
@@ -245,27 +245,45 @@ func TestParseDayOutOfRange(t *testing.T) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+// TestParseInLocation checks that the Parse and ParseInLocation
|
||||||
|
+// functions do not get confused by the fact that AST (Arabia Standard
|
||||||
|
+// Time) and AST (Atlantic Standard Time) are different time zones,
|
||||||
|
+// even though they have the same abbreviation.
|
||||||
|
+//
|
||||||
|
+// ICANN has been slowly phasing out invented abbreviation in favor of
|
||||||
|
+// numeric time zones (for example, the Asia/Baghdad time zone
|
||||||
|
+// abbreviation got changed from AST to +03 in the 2017a tzdata
|
||||||
|
+// release); but we still want to make sure that the time package does
|
||||||
|
+// not get confused on systems with slightly older tzdata packages.
|
||||||
|
func TestParseInLocation(t *testing.T) {
|
||||||
|
- // Check that Parse (and ParseInLocation) understand that
|
||||||
|
- // Feb 01 AST (Arabia Standard Time) and Feb 01 AST (Atlantic Standard Time)
|
||||||
|
- // are in different time zones even though both are called AST
|
||||||
|
|
||||||
|
baghdad, err := LoadLocation("Asia/Baghdad")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
- t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad)
|
||||||
|
+ var t1, t2 Time
|
||||||
|
+
|
||||||
|
+ t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
- t2 := Date(2013, February, 1, 00, 00, 00, 0, baghdad)
|
||||||
|
- if t1 != t2 {
|
||||||
|
- t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2)
|
||||||
|
- }
|
||||||
|
+
|
||||||
|
_, offset := t1.Zone()
|
||||||
|
- if offset != 3*60*60 {
|
||||||
|
- t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60)
|
||||||
|
+
|
||||||
|
+ // A zero offset means that ParseInLocation did not recognize the
|
||||||
|
+ // 'AST' abbreviation as matching the current location (Baghdad,
|
||||||
|
+ // where we'd expect a +03 hrs offset); likely because we're using
|
||||||
|
+ // a recent tzdata release (2017a or newer).
|
||||||
|
+ // If it happens, skip the Baghdad test.
|
||||||
|
+ if offset != 0 {
|
||||||
|
+ t2 = Date(2013, February, 1, 00, 00, 00, 0, baghdad)
|
||||||
|
+ if t1 != t2 {
|
||||||
|
+ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2)
|
||||||
|
+ }
|
||||||
|
+ if offset != 3*60*60 {
|
||||||
|
+ t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60)
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
blancSablon, err := LoadLocation("America/Blanc-Sablon")
|
||||||
|
@@ -273,6 +291,9 @@ func TestParseInLocation(t *testing.T) {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // In this case 'AST' means 'Atlantic Standard Time', and we
|
||||||
|
+ // expect the abbreviation to correctly match the american
|
||||||
|
+ // location.
|
||||||
|
t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
Loading…
Reference in New Issue