mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
go1.8: Changes to support golang 1.8 (#4759)
QuirkConn is added to replace net.Conn as a workaround to a golang bug: https://github.com/golang/go/issues/21133
This commit is contained in:
parent
218049300c
commit
b4dc6df35c
@ -39,4 +39,4 @@ after_success:
|
|||||||
- bash <(curl -s https://codecov.io/bash)
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.7.5
|
- 1.8.3
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.5
|
FROM alpine:3.6
|
||||||
|
|
||||||
MAINTAINER Minio Inc <dev@minio.io>
|
MAINTAINER Minio Inc <dev@minio.io>
|
||||||
|
|
||||||
|
@ -11,12 +11,12 @@ clone_folder: c:\gopath\src\github.com\minio\minio
|
|||||||
|
|
||||||
# Environment variables
|
# Environment variables
|
||||||
environment:
|
environment:
|
||||||
GOROOT: c:\go17
|
GOVERSION: 1.8.3
|
||||||
GOPATH: c:\gopath
|
GOPATH: c:\gopath
|
||||||
|
|
||||||
# scripts that run after cloning repository
|
# scripts that run after cloning repository
|
||||||
install:
|
install:
|
||||||
- set PATH=%GOPATH%\bin;c:\go17\bin;%PATH%
|
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
|
||||||
- go version
|
- go version
|
||||||
- go env
|
- go env
|
||||||
- python --version
|
- python --version
|
||||||
|
@ -21,7 +21,7 @@ _init() {
|
|||||||
|
|
||||||
## Minimum required versions for build dependencies
|
## Minimum required versions for build dependencies
|
||||||
GIT_VERSION="1.0"
|
GIT_VERSION="1.0"
|
||||||
GO_VERSION="1.7.1"
|
GO_VERSION="1.8.3"
|
||||||
OSX_VERSION="10.8"
|
OSX_VERSION="10.8"
|
||||||
KNAME=$(uname -s)
|
KNAME=$(uname -s)
|
||||||
ARCH=$(uname -m)
|
ARCH=$(uname -m)
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -33,9 +32,6 @@ func TestNewEndpoint(t *testing.T) {
|
|||||||
u4, _ := url.Parse("http://192.168.253.200/path")
|
u4, _ := url.Parse("http://192.168.253.200/path")
|
||||||
|
|
||||||
errMsg := ": no such host"
|
errMsg := ": no such host"
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
errMsg = ": No such host is known."
|
|
||||||
}
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
arg string
|
arg string
|
||||||
@ -232,7 +228,7 @@ func TestCreateEndpoints(t *testing.T) {
|
|||||||
expectedSetupType SetupType
|
expectedSetupType SetupType
|
||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{"localhost", []string{}, "", EndpointList{}, -1, fmt.Errorf("missing port in address localhost")},
|
{"localhost", []string{}, "", EndpointList{}, -1, fmt.Errorf("address localhost: missing port in address")},
|
||||||
|
|
||||||
// FS Setup
|
// FS Setup
|
||||||
{"localhost:9000", []string{"http://localhost/d1"}, "", EndpointList{}, -1, fmt.Errorf("use path style endpoint for FS setup")},
|
{"localhost:9000", []string{"http://localhost/d1"}, "", EndpointList{}, -1, fmt.Errorf("use path style endpoint for FS setup")},
|
||||||
|
10
cmd/net.go
10
cmd/net.go
@ -198,17 +198,19 @@ func extractHostPort(hostAddr string) (string, string, error) {
|
|||||||
return "", "", errors.New("unable to process empty address")
|
return "", "", errors.New("unable to process empty address")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simplify the work of url.Parse() and always send a url with
|
||||||
|
if !strings.HasPrefix(hostAddr, "http://") && !strings.HasPrefix(hostAddr, "https://") {
|
||||||
|
hostAddr = "//" + hostAddr
|
||||||
|
}
|
||||||
|
|
||||||
// Parse address to extract host and scheme field
|
// Parse address to extract host and scheme field
|
||||||
u, err := url.Parse(hostAddr)
|
u, err := url.Parse(hostAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Ignore scheme not present error
|
|
||||||
if !strings.Contains(err.Error(), "missing protocol scheme") {
|
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
addr = u.Host
|
addr = u.Host
|
||||||
scheme = u.Scheme
|
scheme = u.Scheme
|
||||||
}
|
|
||||||
|
|
||||||
// Use the given parameter again if url.Parse()
|
// Use the given parameter again if url.Parse()
|
||||||
// didn't return any useful result.
|
// didn't return any useful result.
|
||||||
|
@ -223,7 +223,7 @@ func TestCheckLocalServerAddr(t *testing.T) {
|
|||||||
{"localhost:54321", nil},
|
{"localhost:54321", nil},
|
||||||
{"0.0.0.0:9000", nil},
|
{"0.0.0.0:9000", nil},
|
||||||
{"", fmt.Errorf("missing port in address")},
|
{"", fmt.Errorf("missing port in address")},
|
||||||
{"localhost", fmt.Errorf("missing port in address localhost")},
|
{"localhost", fmt.Errorf("address localhost: missing port in address")},
|
||||||
{"example.org:54321", fmt.Errorf("host in server address should be this server")},
|
{"example.org:54321", fmt.Errorf("host in server address should be this server")},
|
||||||
{":0", fmt.Errorf("port number must be between 1 to 65535")},
|
{":0", fmt.Errorf("port number must be between 1 to 65535")},
|
||||||
{":-10", fmt.Errorf("port number must be between 1 to 65535")},
|
{":-10", fmt.Errorf("port number must be between 1 to 65535")},
|
||||||
@ -251,7 +251,6 @@ func TestExtractHostPort(t *testing.T) {
|
|||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{"", "", "", errors.New("unable to process empty address")},
|
{"", "", "", errors.New("unable to process empty address")},
|
||||||
{"localhost", "localhost", "80", nil},
|
|
||||||
{"localhost:9000", "localhost", "9000", nil},
|
{"localhost:9000", "localhost", "9000", nil},
|
||||||
{"http://:9000/", "", "9000", nil},
|
{"http://:9000/", "", "9000", nil},
|
||||||
{"http://8.8.8.8:9000/", "8.8.8.8", "9000", nil},
|
{"http://8.8.8.8:9000/", "8.8.8.8", "9000", nil},
|
||||||
@ -294,7 +293,9 @@ func TestSameLocalAddrs(t *testing.T) {
|
|||||||
{":9000", ":9000", true, nil},
|
{":9000", ":9000", true, nil},
|
||||||
{"localhost:9000", ":9000", true, nil},
|
{"localhost:9000", ":9000", true, nil},
|
||||||
{"localhost:9000", "http://localhost:9000", true, nil},
|
{"localhost:9000", "http://localhost:9000", true, nil},
|
||||||
{"8.8.8.8:9000", "http://localhost:9000", false, nil},
|
{"http://localhost:9000", ":9000", true, nil},
|
||||||
|
{"http://localhost:9000", "http://localhost:9000", true, nil},
|
||||||
|
{"http://8.8.8.8:9000", "http://localhost:9000", false, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
|
@ -58,7 +58,7 @@ func TestNewWebHookNotify(t *testing.T) {
|
|||||||
t.Fatal("Unexpected should fail")
|
t.Fatal("Unexpected should fail")
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfig.Notify.SetWebhookByID("10", webhookNotify{Enable: true, Endpoint: "http://127.0.0.1:xxx"})
|
serverConfig.Notify.SetWebhookByID("10", webhookNotify{Enable: true, Endpoint: "http://127.0.0.1:80"})
|
||||||
_, err = newWebhookNotify("10")
|
_, err = newWebhookNotify("10")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected should not fail with lookupEndpoint", err)
|
t.Fatal("Unexpected should not fail with lookupEndpoint", err)
|
||||||
|
@ -939,15 +939,11 @@ func signRequestV2(req *http.Request, accessKey, secretKey string) error {
|
|||||||
req.Header.Set("Date", d.Format(http.TimeFormat))
|
req.Header.Set("Date", d.Format(http.TimeFormat))
|
||||||
}
|
}
|
||||||
|
|
||||||
// url.RawPath will be valid if path has any encoded characters, if not it will
|
|
||||||
// be empty - in which case we need to consider url.Path (bug in net/http?)
|
|
||||||
encodedResource := req.URL.RawPath
|
|
||||||
if encodedResource == "" {
|
|
||||||
splits := strings.Split(req.URL.Path, "?")
|
splits := strings.Split(req.URL.Path, "?")
|
||||||
|
var encodedResource string
|
||||||
if len(splits) > 0 {
|
if len(splits) > 0 {
|
||||||
encodedResource = getURLEncodedName(splits[0])
|
encodedResource = getURLEncodedName(splits[0])
|
||||||
}
|
}
|
||||||
}
|
|
||||||
encodedQuery := req.URL.Query().Encode()
|
encodedQuery := req.URL.Query().Encode()
|
||||||
|
|
||||||
// Calculate HMAC for secretAccessKey.
|
// Calculate HMAC for secretAccessKey.
|
||||||
@ -1088,16 +1084,9 @@ func newTestRequest(method, urlStr string, contentLength int64, body io.ReadSeek
|
|||||||
method = "POST"
|
method = "POST"
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest(method, urlStr, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Content-Length
|
|
||||||
req.ContentLength = contentLength
|
|
||||||
|
|
||||||
// Save for subsequent use
|
// Save for subsequent use
|
||||||
var hashedPayload string
|
var hashedPayload string
|
||||||
|
var md5Base64 string
|
||||||
switch {
|
switch {
|
||||||
case body == nil:
|
case body == nil:
|
||||||
hashedPayload = getSHA256Hash([]byte{})
|
hashedPayload = getSHA256Hash([]byte{})
|
||||||
@ -1107,21 +1096,25 @@ func newTestRequest(method, urlStr string, contentLength int64, body io.ReadSeek
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
hashedPayload = getSHA256Hash(payloadBytes)
|
hashedPayload = getSHA256Hash(payloadBytes)
|
||||||
md5Base64 := getMD5HashBase64(payloadBytes)
|
md5Base64 = getMD5HashBase64(payloadBytes)
|
||||||
req.Header.Set("Content-Md5", md5Base64)
|
|
||||||
}
|
}
|
||||||
req.Header.Set("x-amz-content-sha256", hashedPayload)
|
|
||||||
// Seek back to beginning.
|
// Seek back to beginning.
|
||||||
if body != nil {
|
if body != nil {
|
||||||
body.Seek(0, 0)
|
body.Seek(0, 0)
|
||||||
// Add body
|
|
||||||
req.Body = ioutil.NopCloser(body)
|
|
||||||
} else {
|
} else {
|
||||||
// this is added to avoid panic during ioutil.ReadAll(req.Body).
|
body = bytes.NewReader([]byte(""))
|
||||||
// th stack trace can be found here https://github.com/minio/minio/pull/2074 .
|
|
||||||
// This is very similar to https://github.com/golang/go/issues/7527.
|
|
||||||
req.Body = ioutil.NopCloser(bytes.NewReader([]byte("")))
|
|
||||||
}
|
}
|
||||||
|
req, err := http.NewRequest(method, urlStr, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if md5Base64 != "" {
|
||||||
|
req.Header.Set("Content-Md5", md5Base64)
|
||||||
|
}
|
||||||
|
req.Header.Set("x-amz-content-sha256", hashedPayload)
|
||||||
|
|
||||||
|
// Add Content-Length
|
||||||
|
req.ContentLength = contentLength
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
6
main.go
6
main.go
@ -33,8 +33,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Minio requires at least Go v1.7
|
// Minio requires at least Go v1.8.3
|
||||||
minGoVersion = "1.7"
|
minGoVersion = "1.8.3"
|
||||||
goVersionConstraint = ">= " + minGoVersion
|
goVersionConstraint = ">= " + minGoVersion
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ func checkGoVersion(goVersionStr string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !constraint.Check(goVersion) {
|
if !constraint.Check(goVersion) {
|
||||||
return fmt.Errorf("Minio is not compiled by Go %s. Please recompile accordingly.",
|
return fmt.Errorf("Minio is not compiled by Go %s. Please recompile accordingly",
|
||||||
goVersionConstraint)
|
goVersionConstraint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,9 +28,9 @@ func TestCheckGoVersion(t *testing.T) {
|
|||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{minGoVersion, nil},
|
{minGoVersion, nil},
|
||||||
{minGoVersion + ".10", nil},
|
{"1.6.8", fmt.Errorf("Minio is not compiled by Go >= 1.8.3. Please recompile accordingly")},
|
||||||
{"1.6.8", fmt.Errorf("Minio is not compiled by Go >= 1.7. Please recompile accordingly.")},
|
{"1.5", fmt.Errorf("Minio is not compiled by Go >= 1.8.3. Please recompile accordingly")},
|
||||||
{"0.1", fmt.Errorf("Minio is not compiled by Go >= 1.7. Please recompile accordingly.")},
|
{"0.1", fmt.Errorf("Minio is not compiled by Go >= 1.8.3. Please recompile accordingly")},
|
||||||
{".1", fmt.Errorf("Malformed version: .1")},
|
{".1", fmt.Errorf("Malformed version: .1")},
|
||||||
{"somejunk", fmt.Errorf("Malformed version: somejunk")},
|
{"somejunk", fmt.Errorf("Malformed version: somejunk")},
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
// BufConn - is a generic stream-oriented network connection supporting buffered reader and read/write timeout.
|
// BufConn - is a generic stream-oriented network connection supporting buffered reader and read/write timeout.
|
||||||
type BufConn struct {
|
type BufConn struct {
|
||||||
net.Conn
|
QuirkConn
|
||||||
bufReader *bufio.Reader // buffered reader wraps reader in net.Conn.
|
bufReader *bufio.Reader // buffered reader wraps reader in net.Conn.
|
||||||
readTimeout time.Duration // sets the read timeout in the connection.
|
readTimeout time.Duration // sets the read timeout in the connection.
|
||||||
writeTimeout time.Duration // sets the write timeout in the connection.
|
writeTimeout time.Duration // sets the write timeout in the connection.
|
||||||
@ -34,7 +34,7 @@ type BufConn struct {
|
|||||||
|
|
||||||
// Sets read timeout
|
// Sets read timeout
|
||||||
func (c *BufConn) setReadTimeout() {
|
func (c *BufConn) setReadTimeout() {
|
||||||
if c.readTimeout != 0 {
|
if c.readTimeout != 0 && c.canSetReadDeadline() {
|
||||||
c.SetReadDeadline(time.Now().UTC().Add(c.readTimeout))
|
c.SetReadDeadline(time.Now().UTC().Add(c.readTimeout))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ func (c *BufConn) Write(b []byte) (n int, err error) {
|
|||||||
func newBufConn(c net.Conn, readTimeout, writeTimeout time.Duration,
|
func newBufConn(c net.Conn, readTimeout, writeTimeout time.Duration,
|
||||||
updateBytesReadFunc, updateBytesWrittenFunc func(int)) *BufConn {
|
updateBytesReadFunc, updateBytesWrittenFunc func(int)) *BufConn {
|
||||||
return &BufConn{
|
return &BufConn{
|
||||||
Conn: c,
|
QuirkConn: QuirkConn{Conn: c},
|
||||||
bufReader: bufio.NewReader(c),
|
bufReader: bufio.NewReader(c),
|
||||||
readTimeout: readTimeout,
|
readTimeout: readTimeout,
|
||||||
writeTimeout: writeTimeout,
|
writeTimeout: writeTimeout,
|
||||||
|
48
pkg/http/conn_bug_21133.go
Normal file
48
pkg/http/conn_bug_21133.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2017 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// QuirkConn - similar to golang net.Conn struct, but contains a workaround of the
|
||||||
|
// following the go bug reported here https://github.com/golang/go/issues/21133.
|
||||||
|
// Once the bug will be fixed, we can remove this structure and replaces it with
|
||||||
|
// the standard net.Conn
|
||||||
|
type QuirkConn struct {
|
||||||
|
net.Conn
|
||||||
|
hadReadDeadlineInPast int32 // atomic
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetReadDeadline - implements a workaround of SetReadDeadline go bug
|
||||||
|
func (q *QuirkConn) SetReadDeadline(t time.Time) error {
|
||||||
|
inPast := int32(0)
|
||||||
|
if t.Before(time.Now()) {
|
||||||
|
inPast = 1
|
||||||
|
}
|
||||||
|
atomic.StoreInt32(&q.hadReadDeadlineInPast, inPast)
|
||||||
|
return q.Conn.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// canSetReadDeadline - returns if it is safe to set a new
|
||||||
|
// read deadline without triggering golang/go#21133 issue.
|
||||||
|
func (q *QuirkConn) canSetReadDeadline() bool {
|
||||||
|
return atomic.LoadInt32(&q.hadReadDeadlineInPast) != 1
|
||||||
|
}
|
@ -180,9 +180,6 @@ func TestIsHTTPMethod(t *testing.T) {
|
|||||||
|
|
||||||
func TestNewHTTPListener(t *testing.T) {
|
func TestNewHTTPListener(t *testing.T) {
|
||||||
errMsg := ": no such host"
|
errMsg := ": no such host"
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
errMsg = ": No such host is known."
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteAddrErrMsg := "listen tcp 93.184.216.34:9000: bind: cannot assign requested address"
|
remoteAddrErrMsg := "listen tcp 93.184.216.34:9000: bind: cannot assign requested address"
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
@ -204,7 +201,7 @@ func TestNewHTTPListener(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{[]string{"93.184.216.34:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New(remoteAddrErrMsg)},
|
{[]string{"93.184.216.34:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New(remoteAddrErrMsg)},
|
||||||
{[]string{"example.org:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New(remoteAddrErrMsg)},
|
{[]string{"example.org:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New(remoteAddrErrMsg)},
|
||||||
{[]string{"unknown-host"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New("listen tcp: missing port in address unknown-host")},
|
{[]string{"unknown-host"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New("listen tcp: address unknown-host: missing port in address")},
|
||||||
{[]string{"unknown-host:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New("listen tcp: lookup unknown-host" + errMsg)},
|
{[]string{"unknown-host:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New("listen tcp: lookup unknown-host" + errMsg)},
|
||||||
{[]string{"localhost:9000", "93.184.216.34:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New(remoteAddrErrMsg)},
|
{[]string{"localhost:9000", "93.184.216.34:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New(remoteAddrErrMsg)},
|
||||||
{[]string{"localhost:9000", "unknown-host:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New("listen tcp: lookup unknown-host" + errMsg)},
|
{[]string{"localhost:9000", "unknown-host:9000"}, nil, time.Duration(0), time.Duration(0), time.Duration(0), nil, nil, nil, errors.New("listen tcp: lookup unknown-host" + errMsg)},
|
||||||
|
Loading…
Reference in New Issue
Block a user