mirror of
https://github.com/minio/minio.git
synced 2025-11-07 04:42:56 -05:00
move to GET for internal stream READs instead of POST (#20160)
the main reason is to let Go net/http perform necessary book keeping properly, and in essential from consistency point of view its GETs all the way. Deprecate sendFile() as its buggy inside Go runtime.
This commit is contained in:
@@ -251,7 +251,7 @@ func guessIsRPCReq(req *http.Request) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
return req.Method == http.MethodPost &&
|
||||
return (req.Method == http.MethodPost || req.Method == http.MethodGet) &&
|
||||
strings.HasPrefix(req.URL.Path, minioReservedBucketPath+SlashSeparator)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,9 +51,10 @@ func TestGuessIsRPC(t *testing.T) {
|
||||
r = &http.Request{
|
||||
Proto: "HTTP/1.1",
|
||||
Method: http.MethodGet,
|
||||
URL: u,
|
||||
}
|
||||
if guessIsRPCReq(r) {
|
||||
t.Fatal("Test shouldn't report as net/rpc for a non net/rpc request.")
|
||||
if !guessIsRPCReq(r) {
|
||||
t.Fatal("Test shouldn't fail for a possible net/rpc request.")
|
||||
}
|
||||
r = &http.Request{
|
||||
Proto: "HTTP/1.1",
|
||||
|
||||
@@ -617,9 +617,11 @@ func (client *storageRESTClient) ReadFileStream(ctx context.Context, volume, pat
|
||||
values.Set(storageRESTFilePath, path)
|
||||
values.Set(storageRESTOffset, strconv.Itoa(int(offset)))
|
||||
values.Set(storageRESTLength, strconv.Itoa(int(length)))
|
||||
respBody, err := client.call(ctx, storageRESTMethodReadFileStream, values, nil, -1)
|
||||
values.Set(storageRESTDiskID, *client.diskID.Load())
|
||||
|
||||
respBody, err := client.restClient.CallWithHTTPMethod(ctx, http.MethodGet, storageRESTMethodReadFileStream, values, nil, -1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, toStorageErr(err)
|
||||
}
|
||||
return respBody, nil
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ package cmd
|
||||
//go:generate msgp -file $GOFILE -unexported
|
||||
|
||||
const (
|
||||
storageRESTVersion = "v59" // Change ReadOptions inclFreeVersions
|
||||
storageRESTVersion = "v60" // ReadFileStream now uses http.MethodGet
|
||||
storageRESTVersionPrefix = SlashSeparator + storageRESTVersion
|
||||
storageRESTPrefix = minioReservedBucketPath + "/storage"
|
||||
)
|
||||
|
||||
@@ -29,14 +29,12 @@ import (
|
||||
"net/http"
|
||||
"os/user"
|
||||
"path"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/minio/minio/internal/grid"
|
||||
"github.com/tinylib/msgp/msgp"
|
||||
|
||||
@@ -606,8 +604,6 @@ func (s *storageRESTServer) ReadFileStreamHandler(w http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set(xhttp.ContentLength, strconv.FormatInt(length, 10))
|
||||
|
||||
rc, err := s.getStorage().ReadFileStream(r.Context(), volume, filePath, offset, length)
|
||||
if err != nil {
|
||||
s.writeErrorResponse(w, err)
|
||||
@@ -615,28 +611,6 @@ func (s *storageRESTServer) ReadFileStreamHandler(w http.ResponseWriter, r *http
|
||||
}
|
||||
defer rc.Close()
|
||||
|
||||
noReadFrom := runtime.GOOS == "windows" || length < 4*humanize.MiByte
|
||||
if !noReadFrom {
|
||||
rf, ok := w.(io.ReaderFrom)
|
||||
if ok {
|
||||
// Attempt to use splice/sendfile() optimization, A very specific behavior mentioned below is necessary.
|
||||
// See https://github.com/golang/go/blob/f7c5cbb82087c55aa82081e931e0142783700ce8/src/net/sendfile_linux.go#L20
|
||||
// Windows can lock up with this optimization, so we fall back to regular copy.
|
||||
sr, ok := rc.(*sendFileReader)
|
||||
if ok {
|
||||
// Sendfile sends in 4MiB chunks per sendfile syscall which is more than enough
|
||||
// for most setups.
|
||||
_, err = rf.ReadFrom(sr.Reader)
|
||||
if !xnet.IsNetworkOrHostDown(err, true) { // do not need to log disconnected clients
|
||||
storageLogIf(r.Context(), err)
|
||||
}
|
||||
if err == nil || !errors.Is(err, xhttp.ErrNotImplemented) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} // noReadFrom means use io.Copy()
|
||||
|
||||
_, err = xioutil.Copy(w, rc)
|
||||
if !xnet.IsNetworkOrHostDown(err, true) { // do not need to log disconnected clients
|
||||
storageLogIf(r.Context(), err)
|
||||
@@ -1367,12 +1341,12 @@ func registerStorageRESTHandlers(router *mux.Router, endpointServerPools Endpoin
|
||||
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodCreateFile).HandlerFunc(h(server.CreateFileHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFile).HandlerFunc(h(server.ReadFileHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFileStream).HandlerFunc(h(server.ReadFileStreamHandler))
|
||||
|
||||
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteVersions).HandlerFunc(h(server.DeleteVersionsHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodVerifyFile).HandlerFunc(h(server.VerifyFileHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodStatInfoFile).HandlerFunc(h(server.StatInfoFile))
|
||||
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadMultiple).HandlerFunc(h(server.ReadMultiple))
|
||||
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodCleanAbandoned).HandlerFunc(h(server.CleanAbandonedDataHandler))
|
||||
subrouter.Methods(http.MethodGet).Path(storageRESTVersionPrefix + storageRESTMethodReadFileStream).HandlerFunc(h(server.ReadFileStreamHandler))
|
||||
logger.FatalIf(storageListDirRPC.RegisterNoInput(gm, server.ListDirHandler, endpoint.Path), "unable to register handler")
|
||||
logger.FatalIf(storageReadAllRPC.Register(gm, server.ReadAllHandler, endpoint.Path), "unable to register handler")
|
||||
logger.FatalIf(storageWriteAllRPC.Register(gm, server.WriteAllHandler, endpoint.Path), "unable to register handler")
|
||||
|
||||
Reference in New Issue
Block a user