Commit 33e337e3 by Ian Lance Taylor

libgo: Update to Go 1.0.1 release.

From-SVN: r187163
parent 1eae36f0
dc5e410f0b4c 2ccfd4b451d3
The first line of this file holds the Mercurial revision number of the The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources. last merge done from the master library sources.
...@@ -23,8 +23,8 @@ type keyAgreement interface { ...@@ -23,8 +23,8 @@ type keyAgreement interface {
// In the case that the key agreement protocol doesn't use a // In the case that the key agreement protocol doesn't use a
// ServerKeyExchange message, generateServerKeyExchange can return nil, // ServerKeyExchange message, generateServerKeyExchange can return nil,
// nil. // nil.
generateServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error) generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
processClientKeyExchange(*Config, *clientKeyExchangeMsg, uint16) ([]byte, error) processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
// On the client side, the next two methods are called in order. // On the client side, the next two methods are called in order.
......
...@@ -112,37 +112,38 @@ FindCipherSuite: ...@@ -112,37 +112,38 @@ FindCipherSuite:
hello.nextProtoNeg = true hello.nextProtoNeg = true
hello.nextProtos = config.NextProtos hello.nextProtos = config.NextProtos
} }
if clientHello.ocspStapling && len(config.Certificates[0].OCSPStaple) > 0 {
hello.ocspStapling = true
}
finishedHash.Write(hello.marshal())
c.writeRecord(recordTypeHandshake, hello.marshal())
if len(config.Certificates) == 0 { if len(config.Certificates) == 0 {
return c.sendAlert(alertInternalError) return c.sendAlert(alertInternalError)
} }
cert := &config.Certificates[0]
certMsg := new(certificateMsg)
if len(clientHello.serverName) > 0 { if len(clientHello.serverName) > 0 {
c.serverName = clientHello.serverName c.serverName = clientHello.serverName
certMsg.certificates = config.getCertificateForName(clientHello.serverName).Certificate cert = config.getCertificateForName(clientHello.serverName)
} else {
certMsg.certificates = config.Certificates[0].Certificate
} }
if clientHello.ocspStapling && len(cert.OCSPStaple) > 0 {
hello.ocspStapling = true
}
finishedHash.Write(hello.marshal())
c.writeRecord(recordTypeHandshake, hello.marshal())
certMsg := new(certificateMsg)
certMsg.certificates = cert.Certificate
finishedHash.Write(certMsg.marshal()) finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal())
if hello.ocspStapling { if hello.ocspStapling {
certStatus := new(certificateStatusMsg) certStatus := new(certificateStatusMsg)
certStatus.statusType = statusTypeOCSP certStatus.statusType = statusTypeOCSP
certStatus.response = config.Certificates[0].OCSPStaple certStatus.response = cert.OCSPStaple
finishedHash.Write(certStatus.marshal()) finishedHash.Write(certStatus.marshal())
c.writeRecord(recordTypeHandshake, certStatus.marshal()) c.writeRecord(recordTypeHandshake, certStatus.marshal())
} }
keyAgreement := suite.ka() keyAgreement := suite.ka()
skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello) skx, err := keyAgreement.generateServerKeyExchange(config, cert, clientHello, hello)
if err != nil { if err != nil {
c.sendAlert(alertHandshakeFailure) c.sendAlert(alertHandshakeFailure)
return err return err
...@@ -288,7 +289,7 @@ FindCipherSuite: ...@@ -288,7 +289,7 @@ FindCipherSuite:
finishedHash.Write(certVerify.marshal()) finishedHash.Write(certVerify.marshal())
} }
preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx, c.vers) preMasterSecret, err := keyAgreement.processClientKeyExchange(config, cert, ckx, c.vers)
if err != nil { if err != nil {
c.sendAlert(alertHandshakeFailure) c.sendAlert(alertHandshakeFailure)
return err return err
......
...@@ -20,11 +20,11 @@ import ( ...@@ -20,11 +20,11 @@ import (
// encrypts the pre-master secret to the server's public key. // encrypts the pre-master secret to the server's public key.
type rsaKeyAgreement struct{} type rsaKeyAgreement struct{}
func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
return nil, nil return nil, nil
} }
func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
preMasterSecret := make([]byte, 48) preMasterSecret := make([]byte, 48)
_, err := io.ReadFull(config.rand(), preMasterSecret[2:]) _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
if err != nil { if err != nil {
...@@ -44,7 +44,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe ...@@ -44,7 +44,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
ciphertext = ckx.ciphertext[2:] ciphertext = ckx.ciphertext[2:]
} }
err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret) err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -109,7 +109,7 @@ type ecdheRSAKeyAgreement struct { ...@@ -109,7 +109,7 @@ type ecdheRSAKeyAgreement struct {
x, y *big.Int x, y *big.Int
} }
func (ka *ecdheRSAKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { func (ka *ecdheRSAKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
var curveid uint16 var curveid uint16
Curve: Curve:
...@@ -151,7 +151,7 @@ Curve: ...@@ -151,7 +151,7 @@ Curve:
copy(serverECDHParams[4:], ecdhePublic) copy(serverECDHParams[4:], ecdhePublic)
md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams) md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, md5sha1) sig, err := rsa.SignPKCS1v15(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, md5sha1)
if err != nil { if err != nil {
return nil, errors.New("failed to sign ECDHE parameters: " + err.Error()) return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
} }
...@@ -167,7 +167,7 @@ Curve: ...@@ -167,7 +167,7 @@ Curve:
return skx, nil return skx, nil
} }
func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
return nil, errors.New("bad ClientKeyExchange") return nil, errors.New("bad ClientKeyExchange")
} }
......
...@@ -327,6 +327,9 @@ func (db *DB) prepare(query string) (stmt *Stmt, err error) { ...@@ -327,6 +327,9 @@ func (db *DB) prepare(query string) (stmt *Stmt, err error) {
// Exec executes a query without returning any rows. // Exec executes a query without returning any rows.
func (db *DB) Exec(query string, args ...interface{}) (Result, error) { func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
sargs, err := subsetTypeArgs(args) sargs, err := subsetTypeArgs(args)
if err != nil {
return nil, err
}
var res Result var res Result
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
res, err = db.exec(query, sargs) res, err = db.exec(query, sargs)
......
...@@ -57,6 +57,7 @@ func Encode(dst, src []byte) int { ...@@ -57,6 +57,7 @@ func Encode(dst, src []byte) int {
if v == 0 && len(src) >= 4 { if v == 0 && len(src) >= 4 {
dst[0] = 'z' dst[0] = 'z'
dst = dst[1:] dst = dst[1:]
src = src[4:]
n++ n++
continue continue
} }
......
...@@ -28,6 +28,11 @@ var pairs = []testpair{ ...@@ -28,6 +28,11 @@ var pairs = []testpair{
"l(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G\n" + "l(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G\n" +
">uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c\n", ">uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c\n",
}, },
// Special case when shortening !!!!! to z.
{
"\000\000\000\000",
"z",
},
} }
var bigtest = pairs[len(pairs)-1] var bigtest = pairs[len(pairs)-1]
......
...@@ -377,11 +377,6 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i ...@@ -377,11 +377,6 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
} else { } else {
// Bottom 7 bits give the number of length bytes to follow. // Bottom 7 bits give the number of length bytes to follow.
numBytes := int(b & 0x7f) numBytes := int(b & 0x7f)
// We risk overflowing a signed 32-bit number if we accept more than 3 bytes.
if numBytes > 3 {
err = StructuralError{"length too large"}
return
}
if numBytes == 0 { if numBytes == 0 {
err = SyntaxError{"indefinite length found (not DER)"} err = SyntaxError{"indefinite length found (not DER)"}
return return
...@@ -394,8 +389,19 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i ...@@ -394,8 +389,19 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
} }
b = bytes[offset] b = bytes[offset]
offset++ offset++
if ret.length >= 1<<23 {
// We can't shift ret.length up without
// overflowing.
err = StructuralError{"length too large"}
return
}
ret.length <<= 8 ret.length <<= 8
ret.length |= int(b) ret.length |= int(b)
if ret.length == 0 {
// DER requires that lengths be minimal.
err = StructuralError{"superfluous leading zeros in length"}
return
}
} }
} }
......
...@@ -283,6 +283,12 @@ var tagAndLengthData = []tagAndLengthTest{ ...@@ -283,6 +283,12 @@ var tagAndLengthData = []tagAndLengthTest{
{[]byte{0x00, 0x83, 0x01, 0x00}, false, tagAndLength{}}, {[]byte{0x00, 0x83, 0x01, 0x00}, false, tagAndLength{}},
{[]byte{0x1f, 0x85}, false, tagAndLength{}}, {[]byte{0x1f, 0x85}, false, tagAndLength{}},
{[]byte{0x30, 0x80}, false, tagAndLength{}}, {[]byte{0x30, 0x80}, false, tagAndLength{}},
// Superfluous zeros in the length should be an error.
{[]byte{0xa0, 0x82, 0x00, 0x01}, false, tagAndLength{}},
// Lengths up to the maximum size of an int should work.
{[]byte{0xa0, 0x84, 0x7f, 0xff, 0xff, 0xff}, true, tagAndLength{2, 0, 0x7fffffff, true}},
// Lengths that would overflow an int should be rejected.
{[]byte{0xa0, 0x84, 0x80, 0x00, 0x00, 0x00}, false, tagAndLength{}},
} }
func TestParseTagAndLength(t *testing.T) { func TestParseTagAndLength(t *testing.T) {
......
...@@ -230,7 +230,12 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { ...@@ -230,7 +230,12 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
if in == '=' && j >= 2 && len(src) < 4 { if in == '=' && j >= 2 && len(src) < 4 {
// We've reached the end and there's // We've reached the end and there's
// padding // padding
if len(src) == 0 && j == 2 {
// not enough padding
return n, false, CorruptInputError(len(osrc))
}
if len(src) > 0 && src[0] != '=' { if len(src) > 0 && src[0] != '=' {
// incorrect padding
return n, false, CorruptInputError(len(osrc) - len(src) - 1) return n, false, CorruptInputError(len(osrc) - len(src) - 1)
} }
dlen = j dlen = j
......
...@@ -151,6 +151,9 @@ func TestDecodeCorrupt(t *testing.T) { ...@@ -151,6 +151,9 @@ func TestDecodeCorrupt(t *testing.T) {
{"AAA=AAAA", 3}, {"AAA=AAAA", 3},
{"AAAAA", 4}, {"AAAAA", 4},
{"AAAAAA", 4}, {"AAAAAA", 4},
{"A=", 1},
{"AA=", 3},
{"AAAAAA=", 7},
} }
for _, e := range examples { for _, e := range examples {
......
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
"runtime" "runtime"
"sort" "sort"
"strconv" "strconv"
"strings"
"sync" "sync"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
...@@ -415,9 +416,11 @@ func isValidTag(s string) bool { ...@@ -415,9 +416,11 @@ func isValidTag(s string) bool {
return false return false
} }
for _, c := range s { for _, c := range s {
switch c { switch {
case '$', '-', '_', '/', '%': case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~", c):
// Acceptable // Backslash and quote chars are reserved, but
// otherwise any punctuation chars are allowed
// in a tag name.
default: default:
if !unicode.IsLetter(c) && !unicode.IsDigit(c) { if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
return false return false
......
...@@ -40,6 +40,10 @@ type percentSlashTag struct { ...@@ -40,6 +40,10 @@ type percentSlashTag struct {
V string `json:"text/html%"` // http://golang.org/issue/2718 V string `json:"text/html%"` // http://golang.org/issue/2718
} }
type punctuationTag struct {
V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // http://golang.org/issue/3546
}
type emptyTag struct { type emptyTag struct {
W string W string
} }
...@@ -73,6 +77,7 @@ var structTagObjectKeyTests = []struct { ...@@ -73,6 +77,7 @@ var structTagObjectKeyTests = []struct {
{badFormatTag{"Orfevre"}, "Orfevre", "Y"}, {badFormatTag{"Orfevre"}, "Orfevre", "Y"},
{badCodeTag{"Reliable Man"}, "Reliable Man", "Z"}, {badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
{percentSlashTag{"brut"}, "brut", "text/html%"}, {percentSlashTag{"brut"}, "brut", "text/html%"},
{punctuationTag{"Union Rags"}, "Union Rags", "!#$%&()*+-./:<=>?@[]^_{|}~"},
} }
func TestStructTagObjectKey(t *testing.T) { func TestStructTagObjectKey(t *testing.T) {
......
...@@ -28,9 +28,10 @@ type Block struct { ...@@ -28,9 +28,10 @@ type Block struct {
} }
// getLine results the first \r\n or \n delineated line from the given byte // getLine results the first \r\n or \n delineated line from the given byte
// array. The line does not include the \r\n or \n. The remainder of the byte // array. The line does not include trailing whitespace or the trailing new
// array (also not including the new line bytes) is also returned and this will // line bytes. The remainder of the byte array (also not including the new line
// always be smaller than the original argument. // bytes) is also returned and this will always be smaller than the original
// argument.
func getLine(data []byte) (line, rest []byte) { func getLine(data []byte) (line, rest []byte) {
i := bytes.Index(data, []byte{'\n'}) i := bytes.Index(data, []byte{'\n'})
var j int var j int
...@@ -43,7 +44,7 @@ func getLine(data []byte) (line, rest []byte) { ...@@ -43,7 +44,7 @@ func getLine(data []byte) (line, rest []byte) {
i-- i--
} }
} }
return data[0:i], data[j:] return bytes.TrimRight(data[0:i], " \t"), data[j:]
} }
// removeWhitespace returns a copy of its input with all spaces, tab and // removeWhitespace returns a copy of its input with all spaces, tab and
......
...@@ -127,13 +127,13 @@ Certificate chain ...@@ -127,13 +127,13 @@ Certificate chain
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
testing testing
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIID6TCCA1ICAQEwDQYJKoZIhvcNAQEFBQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYD MIID6TCCA1ICAQEwDQYJKoZIhvcNAQEFBQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYD
VQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQK VQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQK
EwtHb29nbGUgSW5jLjEMMAoGA1UECxMDRW5nMQwwCgYDVQQDEwNhZ2wxHTAbBgkq EwtHb29nbGUgSW5jLjEMMAoGA1UECxMDRW5nMQwwCgYDVQQDEwNhZ2wxHTAbBgkq
hkiG9w0BCQEWDmFnbEBnb29nbGUuY29tMB4XDTA5MDkwOTIyMDU0M1oXDTEwMDkw hkiG9w0BCQEWDmFnbEBnb29nbGUuY29tMB4XDTA5MDkwOTIyMDU0M1oXDTEwMDkw
OTIyMDU0M1owajELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAf OTIyMDU0M1owajELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAf
BgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEjMCEGA1UEAxMaZXVyb3Bh BgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEjMCEGA1UEAxMaZXVyb3Bh
LnNmby5jb3JwLmdvb2dsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK LnNmby5jb3JwLmdvb2dsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQC6pgYt7/EibBDumASF+S0qvqdL/f+nouJw2T1Qc8GmXF/iiUcrsgzh/Fd8 AoICAQC6pgYt7/EibBDumASF+S0qvqdL/f+nouJw2T1Qc8GmXF/iiUcrsgzh/Fd8
pDhz/T96Qg9IyR4ztuc2MXrmPra+zAuSf5bevFReSqvpIt8Duv0HbDbcqs/XKPfB pDhz/T96Qg9IyR4ztuc2MXrmPra+zAuSf5bevFReSqvpIt8Duv0HbDbcqs/XKPfB
...@@ -149,15 +149,15 @@ Pomjn71GNTtDeWAXibjCgdL6iHACCF6Htbl0zGlG0OAK+bdn0QIDAQABMA0GCSqG ...@@ -149,15 +149,15 @@ Pomjn71GNTtDeWAXibjCgdL6iHACCF6Htbl0zGlG0OAK+bdn0QIDAQABMA0GCSqG
SIb3DQEBBQUAA4GBAOKnQDtqBV24vVqvesL5dnmyFpFPXBn3WdFfwD6DzEb21UVG SIb3DQEBBQUAA4GBAOKnQDtqBV24vVqvesL5dnmyFpFPXBn3WdFfwD6DzEb21UVG
5krmJiu+ViipORJPGMkgoL6BjU21XI95VQbun5P8vvg8Z+FnFsvRFY3e1CCzAVQY 5krmJiu+ViipORJPGMkgoL6BjU21XI95VQbun5P8vvg8Z+FnFsvRFY3e1CCzAVQY
ZsUkLw2I7zI/dNlWdB8Xp7v+3w9sX5N3J/WuJ1KOO5m26kRlHQo7EzT3974g ZsUkLw2I7zI/dNlWdB8Xp7v+3w9sX5N3J/WuJ1KOO5m26kRlHQo7EzT3974g
-----END CERTIFICATE----- -----END CERTIFICATE-----
1 s:/C=ZA/O=Ca Inc./CN=CA Inc 1 s:/C=ZA/O=Ca Inc./CN=CA Inc
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,80C7C7A09690757A DEK-Info: DES-EDE3-CBC,80C7C7A09690757A
eQp5ZkH6CyHBz7BZfUPxyLCCmftsBJ7HlqGb8Ld21cSwnzWZ4/SIlhyrUtsfw7VR eQp5ZkH6CyHBz7BZfUPxyLCCmftsBJ7HlqGb8Ld21cSwnzWZ4/SIlhyrUtsfw7VR
2TTwA+odo9ex7GdxOTaH8oZFumIRoiEjHsk8U7Bhntp+ekkPP79xunnN7hb7hkhr 2TTwA+odo9ex7GdxOTaH8oZFumIRoiEjHsk8U7Bhntp+ekkPP79xunnN7hb7hkhr
yGDQZgA7s2cQHQ71v3gwT2BACAft26jCjbM1wgNzBnJ8M0Rzn68YWqaPtdBu8qb/ yGDQZgA7s2cQHQ71v3gwT2BACAft26jCjbM1wgNzBnJ8M0Rzn68YWqaPtdBu8qb/
zVR5JB1mnqvTSbFsfF5yMc6o2WQ9jJCl6KypnMl+BpL+dlvdjYVK4l9lYsB1Hs3d zVR5JB1mnqvTSbFsfF5yMc6o2WQ9jJCl6KypnMl+BpL+dlvdjYVK4l9lYsB1Hs3d
+zDBbWxos818zzhS8/y6eIfiSG27cqrbhURbmgiSfDXjncK4m/pLcQ7mmBL6mFOr +zDBbWxos818zzhS8/y6eIfiSG27cqrbhURbmgiSfDXjncK4m/pLcQ7mmBL6mFOr
......
...@@ -7,9 +7,11 @@ ...@@ -7,9 +7,11 @@
Usage: Usage:
Define flags using flag.String(), Bool(), Int(), etc. Example: Define flags using flag.String(), Bool(), Int(), etc.
This declares an integer flag, -flagname, stored in the pointer ip, with type *int.
import "flag" import "flag"
var ip *int = flag.Int("flagname", 1234, "help message for flagname") var ip = flag.Int("flagname", 1234, "help message for flagname")
If you like, you can bind the flag to a variable using the Var() functions. If you like, you can bind the flag to a variable using the Var() functions.
var flagvar int var flagvar int
func init() { func init() {
...@@ -26,8 +28,8 @@ ...@@ -26,8 +28,8 @@
Flags may then be used directly. If you're using the flags themselves, Flags may then be used directly. If you're using the flags themselves,
they are all pointers; if you bind to variables, they're values. they are all pointers; if you bind to variables, they're values.
fmt.Println("ip has value ", *ip); fmt.Println("ip has value ", *ip)
fmt.Println("flagvar has value ", flagvar); fmt.Println("flagvar has value ", flagvar)
After parsing, the arguments after the flag are available as the After parsing, the arguments after the flag are available as the
slice flag.Args() or individually as flag.Arg(i). slice flag.Args() or individually as flag.Arg(i).
......
...@@ -461,6 +461,9 @@ var fmttests = []struct { ...@@ -461,6 +461,9 @@ var fmttests = []struct {
// zero reflect.Value, which formats as <nil>. // zero reflect.Value, which formats as <nil>.
// This test is just to check that it shows the two NaNs at all. // This test is just to check that it shows the two NaNs at all.
{"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"}, {"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
// Used to crash because nByte didn't allow for a sign.
{"%b", int64(-1 << 63), "-1000000000000000000000000000000000000000000000000000000000000000"},
} }
func TestSprintf(t *testing.T) { func TestSprintf(t *testing.T) {
......
...@@ -10,7 +10,7 @@ import ( ...@@ -10,7 +10,7 @@ import (
) )
const ( const (
nByte = 64 nByte = 65 // %b of an int64, plus a sign.
ldigits = "0123456789abcdef" ldigits = "0123456789abcdef"
udigits = "0123456789ABCDEF" udigits = "0123456789ABCDEF"
......
...@@ -210,13 +210,15 @@ func escape(w writer, s string) error { ...@@ -210,13 +210,15 @@ func escape(w writer, s string) error {
case '&': case '&':
esc = "&amp;" esc = "&amp;"
case '\'': case '\'':
esc = "&apos;" // "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
esc = "&#39;"
case '<': case '<':
esc = "&lt;" esc = "&lt;"
case '>': case '>':
esc = "&gt;" esc = "&gt;"
case '"': case '"':
esc = "&quot;" // "&#34;" is shorter than "&quot;".
esc = "&#34;"
default: default:
panic("unrecognized escape character") panic("unrecognized escape character")
} }
...@@ -231,7 +233,7 @@ func escape(w writer, s string) error { ...@@ -231,7 +233,7 @@ func escape(w writer, s string) error {
} }
// EscapeString escapes special characters like "<" to become "&lt;". It // EscapeString escapes special characters like "<" to become "&lt;". It
// escapes only five such characters: amp, apos, lt, gt and quot. // escapes only five such characters: <, >, &, ' and ".
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
// always true. // always true.
func EscapeString(s string) string { func EscapeString(s string) string {
......
...@@ -99,7 +99,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e ...@@ -99,7 +99,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e
err = checkMediaTypeDisposition(mediatype) err = checkMediaTypeDisposition(mediatype)
if err != nil { if err != nil {
return return "", nil, err
} }
params = make(map[string]string) params = make(map[string]string)
......
...@@ -244,13 +244,33 @@ func TestParseMediaType(t *testing.T) { ...@@ -244,13 +244,33 @@ func TestParseMediaType(t *testing.T) {
} }
} }
type badMediaTypeTest struct {
in string
err string
}
var badMediaTypeTests = []badMediaTypeTest{
{"bogus ;=========", "mime: invalid media parameter"},
{"bogus/<script>alert</script>", "mime: expected token after slash"},
{"bogus/bogus<script>alert</script>", "mime: unexpected content after media subtype"},
}
func TestParseMediaTypeBogus(t *testing.T) { func TestParseMediaTypeBogus(t *testing.T) {
mt, params, err := ParseMediaType("bogus ;=========") for _, tt := range badMediaTypeTests {
if err == nil { mt, params, err := ParseMediaType(tt.in)
t.Fatalf("expected an error parsing invalid media type; got type %q, params %#v", mt, params) if err == nil {
} t.Errorf("ParseMediaType(%q) = nil error; want parse error", tt.in)
if err.Error() != "mime: invalid media parameter" { continue
t.Errorf("expected invalid media parameter; got error %q", err) }
if err.Error() != tt.err {
t.Errorf("ParseMediaType(%q) = err %q; want %q", tt.in, err.Error(), tt.err)
}
if params != nil {
t.Errorf("ParseMediaType(%q): got non-nil params on error", tt.in)
}
if mt != "" {
t.Errorf("ParseMediaType(%q): got non-empty media type string on error", tt.in)
}
} }
} }
......
...@@ -185,6 +185,14 @@ func (r *Reader) NextPart() (*Part, error) { ...@@ -185,6 +185,14 @@ func (r *Reader) NextPart() (*Part, error) {
expectNewPart := false expectNewPart := false
for { for {
line, err := r.bufReader.ReadSlice('\n') line, err := r.bufReader.ReadSlice('\n')
if err == io.EOF && bytes.Equal(line, r.dashBoundaryDash) {
// If the buffer ends in "--boundary--" without the
// trailing "\r\n", ReadSlice will return an error
// (since it's missing the '\n'), but this is a valid
// multipart EOF so we need to return io.EOF instead of
// a fmt-wrapped one.
return nil, io.EOF
}
if err != nil { if err != nil {
return nil, fmt.Errorf("multipart: NextPart: %v", err) return nil, fmt.Errorf("multipart: NextPart: %v", err)
} }
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os"
"strings" "strings"
"testing" "testing"
) )
...@@ -377,3 +378,52 @@ func TestLineContinuation(t *testing.T) { ...@@ -377,3 +378,52 @@ func TestLineContinuation(t *testing.T) {
} }
} }
} }
// Test parsing an image attachment from gmail, which previously failed.
func TestNested(t *testing.T) {
// nested-mime is the body part of a multipart/mixed email
// with boundary e89a8ff1c1e83553e304be640612
f, err := os.Open("testdata/nested-mime")
if err != nil {
t.Fatal(err)
}
defer f.Close()
mr := NewReader(f, "e89a8ff1c1e83553e304be640612")
p, err := mr.NextPart()
if err != nil {
t.Fatalf("error reading first section (alternative): %v", err)
}
// Read the inner text/plain and text/html sections of the multipart/alternative.
mr2 := NewReader(p, "e89a8ff1c1e83553e004be640610")
p, err = mr2.NextPart()
if err != nil {
t.Fatalf("reading text/plain part: %v", err)
}
if b, err := ioutil.ReadAll(p); string(b) != "*body*\r\n" || err != nil {
t.Fatalf("reading text/plain part: got %q, %v", b, err)
}
p, err = mr2.NextPart()
if err != nil {
t.Fatalf("reading text/html part: %v", err)
}
if b, err := ioutil.ReadAll(p); string(b) != "<b>body</b>\r\n" || err != nil {
t.Fatalf("reading text/html part: got %q, %v", b, err)
}
p, err = mr2.NextPart()
if err != io.EOF {
t.Fatalf("final inner NextPart = %v; want io.EOF", err)
}
// Back to the outer multipart/mixed, reading the image attachment.
_, err = mr.NextPart()
if err != nil {
t.Fatalf("error reading the image attachment at the end: %v", err)
}
_, err = mr.NextPart()
if err != io.EOF {
t.Fatalf("final outer NextPart = %v; want io.EOF", err)
}
}
--e89a8ff1c1e83553e304be640612
Content-Type: multipart/alternative; boundary=e89a8ff1c1e83553e004be640610
--e89a8ff1c1e83553e004be640610
Content-Type: text/plain; charset=UTF-8
*body*
--e89a8ff1c1e83553e004be640610
Content-Type: text/html; charset=UTF-8
<b>body</b>
--e89a8ff1c1e83553e004be640610--
--e89a8ff1c1e83553e304be640612
Content-Type: image/png; name="x.png"
Content-Disposition: attachment;
filename="x.png"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_h1edgigu0
iVBORw0KGgoAAAANSUhEUgAAAagAAADrCAIAAACza5XhAAAKMWlDQ1BJQ0MgUHJvZmlsZQAASImd
lndUU9kWh8+9N71QkhCKlNBraFICSA29SJEuKjEJEErAkAAiNkRUcERRkaYIMijggKNDkbEiioUB
8b2kqeGaj4aTNftesu5mob4pr07ecMywRwLBvDCJOksqlUyldAZD7g9fxIZRWWPMvXRNJROJRBIG
Y7Vx0mva1HAwYqibdKONXye3dW4iUonhWFJnqK7OaanU1gGkErFYEgaj0cg8wK+zVPh2ziwnHy07
U8lYTNapezSzOuevRwLB7CFkqQQCwaJDiBQIBIJFhwh8AoFg0SHUqQUCASRJKkwkhMy/JfODWPEJ
BIJFhwh8AoFg0TFnQqQ55GtPFopcJsN97e1nYtNuIBYeGBgYCmYrmE3jZ05iaGAoMX0xzxkWz6Hv
yO7WvrlwzA0uLzrD+VkKqViwl9IfTBVNFMyc/x9alloiPPlqhQAAAABJRU5ErkJggg==
--e89a8ff1c1e83553e304be640612--
...@@ -49,3 +49,8 @@ func ExampleGet() { ...@@ -49,3 +49,8 @@ func ExampleGet() {
res.Body.Close() res.Body.Close()
fmt.Printf("%s", robots) fmt.Printf("%s", robots)
} }
func ExampleFileServer() {
// we use StripPrefix so that /tmpfiles/somefile will access /tmp/somefile
http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))
}
...@@ -785,8 +785,10 @@ var htmlReplacer = strings.NewReplacer( ...@@ -785,8 +785,10 @@ var htmlReplacer = strings.NewReplacer(
"&", "&amp;", "&", "&amp;",
"<", "&lt;", "<", "&lt;",
">", "&gt;", ">", "&gt;",
`"`, "&quot;", // "&#34;" is shorter than "&quot;".
"'", "&apos;", `"`, "&#34;",
// "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
"'", "&#39;",
) )
func htmlEscape(s string) string { func htmlEscape(s string) string {
......
...@@ -83,9 +83,7 @@ func (c *IPConn) Close() error { ...@@ -83,9 +83,7 @@ func (c *IPConn) Close() error {
if !c.ok() { if !c.ok() {
return syscall.EINVAL return syscall.EINVAL
} }
err := c.fd.Close() return c.fd.Close()
c.fd = nil
return err
} }
// LocalAddr returns the local network address. // LocalAddr returns the local network address.
......
...@@ -108,9 +108,7 @@ func (c *TCPConn) Close() error { ...@@ -108,9 +108,7 @@ func (c *TCPConn) Close() error {
if !c.ok() { if !c.ok() {
return syscall.EINVAL return syscall.EINVAL
} }
err := c.fd.Close() return c.fd.Close()
c.fd = nil
return err
} }
// CloseRead shuts down the reading side of the TCP connection. // CloseRead shuts down the reading side of the TCP connection.
...@@ -359,5 +357,5 @@ func (l *TCPListener) SetDeadline(t time.Time) error { ...@@ -359,5 +357,5 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
// File returns a copy of the underlying os.File, set to blocking mode. // File returns a copy of the underlying os.File, set to blocking mode.
// It is the caller's responsibility to close f when finished. // It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c. // Closing l does not affect f, and closing f does not affect l.
func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() } func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() }
...@@ -88,9 +88,7 @@ func (c *UDPConn) Close() error { ...@@ -88,9 +88,7 @@ func (c *UDPConn) Close() error {
if !c.ok() { if !c.ok() {
return syscall.EINVAL return syscall.EINVAL
} }
err := c.fd.Close() return c.fd.Close()
c.fd = nil
return err
} }
// LocalAddr returns the local network address. // LocalAddr returns the local network address.
......
...@@ -141,9 +141,7 @@ func (c *UnixConn) Close() error { ...@@ -141,9 +141,7 @@ func (c *UnixConn) Close() error {
if !c.ok() { if !c.ok() {
return syscall.EINVAL return syscall.EINVAL
} }
err := c.fd.Close() return c.fd.Close()
c.fd = nil
return err
} }
// LocalAddr returns the local network address, a *UnixAddr. // LocalAddr returns the local network address, a *UnixAddr.
...@@ -406,7 +404,7 @@ func (l *UnixListener) SetDeadline(t time.Time) (err error) { ...@@ -406,7 +404,7 @@ func (l *UnixListener) SetDeadline(t time.Time) (err error) {
// File returns a copy of the underlying os.File, set to blocking mode. // File returns a copy of the underlying os.File, set to blocking mode.
// It is the caller's responsibility to close f when finished. // It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c. // Closing l does not affect f, and closing f does not affect l.
func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() } func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() }
// ListenUnixgram listens for incoming Unix datagram packets addressed to the // ListenUnixgram listens for incoming Unix datagram packets addressed to the
......
...@@ -61,16 +61,16 @@ func (e EscapeError) Error() string { ...@@ -61,16 +61,16 @@ func (e EscapeError) Error() string {
} }
// Return true if the specified character should be escaped when // Return true if the specified character should be escaped when
// appearing in a URL string, according to RFC 2396. // appearing in a URL string, according to RFC 3986.
// When 'all' is true the full range of reserved characters are matched. // When 'all' is true the full range of reserved characters are matched.
func shouldEscape(c byte, mode encoding) bool { func shouldEscape(c byte, mode encoding) bool {
// RFC 2396 §2.3 Unreserved characters (alphanum) // §2.3 Unreserved characters (alphanum)
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' { if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
return false return false
} }
// TODO: Update the character sets after RFC 3986.
switch c { switch c {
case '-', '_', '.', '!', '~', '*', '\'', '(', ')': // §2.3 Unreserved characters (mark) case '-', '_', '.', '~': // §2.3 Unreserved characters (mark)
return false return false
case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved) case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
......
...@@ -394,8 +394,8 @@ var escapeTests = []EscapeTest{ ...@@ -394,8 +394,8 @@ var escapeTests = []EscapeTest{
nil, nil,
}, },
{ {
" ?&=#+%!<>#\"{}|\\^[]`☺\t", " ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;",
"+%3F%26%3D%23%2B%25!%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09", "+%3F%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A%2F%40%24%27%28%29%2A%2C%3B",
nil, nil,
}, },
} }
......
...@@ -26,5 +26,5 @@ func isPermission(err error) bool { ...@@ -26,5 +26,5 @@ func isPermission(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }
return err == ErrPermission return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission
} }
...@@ -30,6 +30,9 @@ const ( ...@@ -30,6 +30,9 @@ const (
// that is, replace "/.." by "/" at the beginning of a path, // that is, replace "/.." by "/" at the beginning of a path,
// assuming Separator is '/'. // assuming Separator is '/'.
// //
// The returned path ends in a slash only if it represents a root directory,
// such as "/" on Unix or `C:\` on Windows.
//
// If the result of this process is an empty string, Clean // If the result of this process is an empty string, Clean
// returns the string ".". // returns the string ".".
// //
......
...@@ -21,6 +21,8 @@ import ( ...@@ -21,6 +21,8 @@ import (
// 4. Eliminate .. elements that begin a rooted path: // 4. Eliminate .. elements that begin a rooted path:
// that is, replace "/.." by "/" at the beginning of a path. // that is, replace "/.." by "/" at the beginning of a path.
// //
// The returned path ends in a slash only if it is the root "/".
//
// If the result of this process is an empty string, Clean // If the result of this process is an empty string, Clean
// returns the string ".". // returns the string ".".
// //
......
...@@ -638,6 +638,7 @@ var ( ...@@ -638,6 +638,7 @@ var (
var deepEqualTests = []DeepEqualTest{ var deepEqualTests = []DeepEqualTest{
// Equalities // Equalities
{nil, nil, true},
{1, 1, true}, {1, 1, true},
{int32(1), int32(1), true}, {int32(1), int32(1), true},
{0.5, 0.5, true}, {0.5, 0.5, true},
...@@ -696,6 +697,10 @@ func TestDeepEqual(t *testing.T) { ...@@ -696,6 +697,10 @@ func TestDeepEqual(t *testing.T) {
} }
func TestTypeOf(t *testing.T) { func TestTypeOf(t *testing.T) {
// Special case for nil
if typ := TypeOf(nil); typ != nil {
t.Errorf("expected nil type for nil value; got %v", typ)
}
for _, test := range deepEqualTests { for _, test := range deepEqualTests {
v := ValueOf(test.a) v := ValueOf(test.a)
if !v.IsValid() { if !v.IsValid() {
......
...@@ -970,6 +970,7 @@ func toType(p *runtimeType) Type { ...@@ -970,6 +970,7 @@ func toType(p *runtimeType) Type {
} }
// TypeOf returns the reflection Type of the value in the interface{}. // TypeOf returns the reflection Type of the value in the interface{}.
// TypeOf(nil) returns nil.
func TypeOf(i interface{}) Type { func TypeOf(i interface{}) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i)) eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.typ) return toType(eface.typ)
......
...@@ -20,7 +20,8 @@ func Goexit() ...@@ -20,7 +20,8 @@ func Goexit()
// Caller reports file and line number information about function invocations on // Caller reports file and line number information about function invocations on
// the calling goroutine's stack. The argument skip is the number of stack frames // the calling goroutine's stack. The argument skip is the number of stack frames
// to ascend, with 0 identifying the caller of Caller. The return values report the // to ascend, with 1 identifying the caller of Caller. (For historical reasons the
// meaning of skip differs between Caller and Callers.) The return values report the
// program counter, file name, and line number within the file of the corresponding // program counter, file name, and line number within the file of the corresponding
// call. The boolean ok is false if it was not possible to recover the information. // call. The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool) func Caller(skip int) (pc uintptr, file string, line int, ok bool)
......
...@@ -491,7 +491,11 @@ func (s *state) evalCall(dot, fun reflect.Value, name string, args []parse.Node, ...@@ -491,7 +491,11 @@ func (s *state) evalCall(dot, fun reflect.Value, name string, args []parse.Node,
} }
// Add final value if necessary. // Add final value if necessary.
if final.IsValid() { if final.IsValid() {
argv[i] = final t := typ.In(typ.NumIn() - 1)
if typ.IsVariadic() {
t = t.Elem()
}
argv[i] = s.validateType(final, t)
} }
result := fun.Call(argv) result := fun.Call(argv)
// If we have an error that is not nil, stop execution and return that error to the caller. // If we have an error that is not nil, stop execution and return that error to the caller.
...@@ -507,6 +511,7 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu ...@@ -507,6 +511,7 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
switch typ.Kind() { switch typ.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Chan, reflect.Map, reflect.Slice, reflect.Func: case reflect.Interface, reflect.Ptr, reflect.Chan, reflect.Map, reflect.Slice, reflect.Func:
// An untyped nil interface{}. Accept as a proper nil value. // An untyped nil interface{}. Accept as a proper nil value.
// TODO: Can we delete the other types in this list? Should we?
value = reflect.Zero(typ) value = reflect.Zero(typ)
default: default:
s.errorf("invalid value; expected %s", typ) s.errorf("invalid value; expected %s", typ)
......
...@@ -470,6 +470,9 @@ var execTests = []execTest{ ...@@ -470,6 +470,9 @@ var execTests = []execTest{
{"bug7a", "{{3 2}}", "", tVal, false}, {"bug7a", "{{3 2}}", "", tVal, false},
{"bug7b", "{{$x := 1}}{{$x 2}}", "", tVal, false}, {"bug7b", "{{$x := 1}}{{$x 2}}", "", tVal, false},
{"bug7c", "{{$x := 1}}{{3 | $x}}", "", tVal, false}, {"bug7c", "{{$x := 1}}{{3 | $x}}", "", tVal, false},
// Pipelined arg was not being type-checked.
{"bug8a", "{{3|oneArg}}", "", tVal, false},
{"bug8b", "{{4|dddArg 3}}", "", tVal, false},
} }
func zeroArgs() string { func zeroArgs() string {
...@@ -480,6 +483,10 @@ func oneArg(a string) string { ...@@ -480,6 +483,10 @@ func oneArg(a string) string {
return "oneArg=" + a return "oneArg=" + a
} }
func dddArg(a int, b ...string) string {
return fmt.Sprintln(a, b)
}
// count returns a channel that will deliver n sequential 1-letter strings starting at "a" // count returns a channel that will deliver n sequential 1-letter strings starting at "a"
func count(n int) chan string { func count(n int) chan string {
if n == 0 { if n == 0 {
...@@ -504,6 +511,7 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) { ...@@ -504,6 +511,7 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
funcs := FuncMap{ funcs := FuncMap{
"count": count, "count": count,
"dddArg": dddArg,
"oneArg": oneArg, "oneArg": oneArg,
"typeOf": typeOf, "typeOf": typeOf,
"vfunc": vfunc, "vfunc": vfunc,
......
...@@ -246,7 +246,7 @@ func not(arg interface{}) (truth bool) { ...@@ -246,7 +246,7 @@ func not(arg interface{}) (truth bool) {
var ( var (
htmlQuot = []byte("&#34;") // shorter than "&quot;" htmlQuot = []byte("&#34;") // shorter than "&quot;"
htmlApos = []byte("&#39;") // shorter than "&apos;" htmlApos = []byte("&#39;") // shorter than "&apos;" and apos was not in HTML until HTML5
htmlAmp = []byte("&amp;") htmlAmp = []byte("&amp;")
htmlLt = []byte("&lt;") htmlLt = []byte("&lt;")
htmlGt = []byte("&gt;") htmlGt = []byte("&gt;")
......
...@@ -41,8 +41,8 @@ const ( ...@@ -41,8 +41,8 @@ const (
ANSIC = "Mon Jan _2 15:04:05 2006" ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006" RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 1504 MST" RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 1504 -0700" // RFC822 with numeric zone RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
RFC850 = "Monday, 02-Jan-06 15:04:05 MST" RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
...@@ -714,7 +714,7 @@ func Parse(layout, value string) (Time, error) { ...@@ -714,7 +714,7 @@ func Parse(layout, value string) (Time, error) {
} }
// Special case: do we have a fractional second but no // Special case: do we have a fractional second but no
// fractional second in the format? // fractional second in the format?
if len(value) > 2 && value[0] == '.' && isDigit(value, 1) { if len(value) >= 2 && value[0] == '.' && isDigit(value, 1) {
_, std, _ := nextStdChunk(layout) _, std, _ := nextStdChunk(layout)
if len(std) > 0 && std[0] == '.' && isDigit(std, 1) { if len(std) > 0 && std[0] == '.' && isDigit(std, 1) {
// Fractional second in the layout; proceed normally // Fractional second in the layout; proceed normally
......
...@@ -403,7 +403,7 @@ const ( ...@@ -403,7 +403,7 @@ const (
Hour = 60 * Minute Hour = 60 * Minute
) )
// Duration returns a string representing the duration in the form "72h3m0.5s". // String returns a string representing the duration in the form "72h3m0.5s".
// Leading zero units are omitted. As a special case, durations less than one // Leading zero units are omitted. As a special case, durations less than one
// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure // second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure
// that the leading digit is non-zero. The zero duration formats as 0, // that the leading digit is non-zero. The zero duration formats as 0,
...@@ -763,7 +763,9 @@ func (t Time) Unix() int64 { ...@@ -763,7 +763,9 @@ func (t Time) Unix() int64 {
} }
// UnixNano returns t as a Unix time, the number of nanoseconds elapsed // UnixNano returns t as a Unix time, the number of nanoseconds elapsed
// since January 1, 1970 UTC. // since January 1, 1970 UTC. The result is undefined if the Unix time
// in nanoseconds cannot be represented by an int64. Note that this
// means the result of calling UnixNano on the zero Time is undefined.
func (t Time) UnixNano() int64 { func (t Time) UnixNano() int64 {
return (t.sec+internalToUnix)*1e9 + int64(t.nsec) return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
} }
......
...@@ -223,7 +223,7 @@ var formatTests = []FormatTest{ ...@@ -223,7 +223,7 @@ var formatTests = []FormatTest{
{"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"}, {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"},
{"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"}, {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"},
{"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"}, {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
{"RFC822", RFC822, "04 Feb 09 2100 PST"}, {"RFC822", RFC822, "04 Feb 09 21:00 PST"},
{"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"}, {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
{"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"}, {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
{"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"}, {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
...@@ -310,6 +310,7 @@ var parseTests = []ParseTest{ ...@@ -310,6 +310,7 @@ var parseTests = []ParseTest{
{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5}, {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5}, {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
{"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9}, {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
{"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
// Amount of white space should not matter. // Amount of white space should not matter.
{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0}, {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0}, {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
......
...@@ -83,6 +83,9 @@ func initLocalFromTZI(i *syscall.Timezoneinformation) { ...@@ -83,6 +83,9 @@ func initLocalFromTZI(i *syscall.Timezoneinformation) {
l.cacheStart = -1 << 63 l.cacheStart = -1 << 63
l.cacheEnd = 1<<63 - 1 l.cacheEnd = 1<<63 - 1
l.cacheZone = std l.cacheZone = std
l.tx = make([]zoneTrans, 1)
l.tx[0].when = l.cacheStart
l.tx[0].index = 0
return return
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment