Skip to content

XL/fs: Internal Server Error for PutObject with a name longer than 255 bytes #1501

Closed
@hnakamur

Description

@hnakamur

First of all, thanks for sharing a great software!

I tested putting an object with a name longer than 255 bytes.
Then it took about 20 seconds to get the results and the error
was "500 Internal Server Error".

I believe another error should be defined in minio/api-errors.go and the server returns it immediately.

My test environment:

$ go version
go version go1.6.2 linux/amd64
$ cd $GOPATH/src/github.com/minio/minio && git rev-parse HEAD
e4d89d8156927b2c60f5e719a78f0750a270f540

I tested with the following code.

package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
    "testing"
    "time"

    "github.com/minio/minio-go"
)

func startMinio(addr, configDir, storageDir string) (*exec.Cmd, error) {
    err := os.MkdirAll(configDir, 0700)
    if err != nil {
        return nil, err
    }
    err = os.MkdirAll(storageDir, 0700)
    if err != nil {
        return nil, err
    }
    cmd := exec.Command("minio", "--config-dir", configDir, "server", "--address", addr, storageDir)
    err = cmd.Start()

    // NOTE: We need to wait some time for clients to work properly.
    // If clients connect to the server too soon, I got the
    // "The access key ID you provided does not exist in our records." error
    // when I call APIs like ListBuckets or MakeBucket
    time.Sleep(time.Second)

    return cmd, err
}

func stopMinio(cmd *exec.Cmd) error {
    return cmd.Process.Kill()
}

type Config struct {
    Credential Credential `json:"credential"`
    Region     string     `json:"region"`
}

type Credential struct {
    AccessKey string `json:"accessKey"`
    SecretKey string `json:"secretKey"`
}

func readConfig(configDir string) (config Config, err error) {
    configPath := filepath.Join(configDir, "config.json")
    file, err := os.Open(configPath)
    if err != nil {
        return
    }
    defer file.Close()

    decoder := json.NewDecoder(file)
    err = decoder.Decode(&config)
    return
}

func startMinioForTest(t *testing.T, addr string) (cmd *exec.Cmd, baseDir string, config Config, err error) {
    baseDir, err = ioutil.TempDir("", "minio-test")
    if err != nil {
        return
    }
    t.Logf("startMinioForTest created baseDir=%s", baseDir)

    configDir := filepath.Join(baseDir, "config")
    storageDir := filepath.Join(baseDir, "storage")
    cmd, err = startMinio(addr, configDir, storageDir)
    if err != nil {
        return
    }
    t.Logf("startMinioForTest started minio server. pid=%d, listenAddr=%s", cmd.Process.Pid, addr)
    config, err = readConfig(configDir)
    return
}

func stopMinioForTest(t *testing.T, addr string, cmd *exec.Cmd, baseDir string) {
    err := stopMinio(cmd)
    if err != nil {
        t.Errorf("failed to stop minio server with pid=%d, listenAddress=%s", cmd.Process.Pid, addr)
    }
    t.Logf("stopMinioForTest stopped minio server with pid=%d, listenAddress=%s", cmd.Process.Pid, addr)
    err = os.RemoveAll(baseDir)
    if err != nil {
        t.Errorf("failed to remove directory %s: err=%s", baseDir, err)
    }
    t.Logf("stopMinioForTest removed baseDir=%s", baseDir)
}

func newClient(addr string, config Config) (*minio.Client, error) {
    return minio.New(addr, config.Credential.AccessKey, config.Credential.SecretKey, true)
}

const listenAddr = "127.0.0.1:19999"

func TestPutAndTextFileWithTooLongDirName(t *testing.T) {
    cmd, baseDir, config, err := startMinioForTest(t, listenAddr)
    if err != nil {
        t.Fatal(err)
    }
    defer stopMinioForTest(t, listenAddr, cmd, baseDir)

    client, err := newClient(listenAddr, config)
    if err != nil {
        t.Error(err)
    }

    bucketName := "bucket1.example.com"
    err = client.MakeBucket(bucketName, config.Region)
    if err != nil {
        t.Error(err)
    }

    objectName := strings.Repeat("a", 256)
    contentType := "text/plain"
    var buf bytes.Buffer
    content := "hello world\ngoodbye world\n"
    buf.WriteString(content)
    _, err = client.PutObject(bucketName, objectName, &buf, contentType)
    if err == nil {
        t.Error("should have an error")
    }
    // NOTE: This error should not be "500 Internal Server Error"
    wantedError := "500 Internal Server Error"
    if err.Error() != wantedError {
        t.Errorf("unexpected error, got %s; want %s", err.Error(), wantedError)
    }
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions