// doList - list all entities inside a folder func doList(clnt client.Client, recursive bool) error { var err error for contentCh := range clnt.List(recursive) { if contentCh.Err != nil { switch err := iodine.ToError(contentCh.Err).(type) { // handle this specifically for filesystem case client.ISBrokenSymlink: console.Errors(ErrorMessage{ Message: "Failed with", Error: iodine.New(err, nil), }) continue } if os.IsNotExist(iodine.ToError(contentCh.Err)) || os.IsPermission(iodine.ToError(contentCh.Err)) { console.Errors(ErrorMessage{ Message: "Failed with", Error: iodine.New(contentCh.Err, nil), }) continue } err = contentCh.Err break } console.Prints(parseContent(contentCh.Content)) } if err != nil { return iodine.New(err, map[string]string{"Target": clnt.URL().String()}) } return nil }
// PutBucketACLHandler - PUT Bucket ACL // ---------- // This implementation of the PUT operation modifies the bucketACL for authenticated request func (api Minio) PutBucketACLHandler(w http.ResponseWriter, req *http.Request) { // Ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until Ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) // read from 'x-amz-acl' aclType := getACLType(req) if aclType == unsupportedACLType { writeErrorResponse(w, req, NotImplemented, acceptsContentType, req.URL.Path) return } vars := mux.Vars(req) bucket := vars["bucket"] err := api.Donut.SetBucketMetadata(bucket, map[string]string{"acl": getACLTypeString(aclType)}) switch iodine.ToError(err).(type) { case nil: writeSuccessResponse(w, acceptsContentType) case donut.BucketNameInvalid: writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path) case donut.BucketNotFound: writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path) default: log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } }
// ListBucketsHandler - GET Service // ----------- // This implementation of the GET operation returns a list of all buckets // owned by the authenticated sender of the request. func (api Minio) ListBucketsHandler(w http.ResponseWriter, req *http.Request) { // Ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until Ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) // uncomment this when we have webcli // without access key credentials one cannot list buckets // if _, err := stripAuth(req); err != nil { // writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path) // return // } buckets, err := api.Donut.ListBuckets() switch iodine.ToError(err).(type) { case nil: // generate response response := generateListBucketsResponse(buckets) encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType) // write headers setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write response w.Write(encodedSuccessResponse) default: log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } }
func doCatCmd(sourceURL string) (string, error) { sourceClnt, err := source2Client(sourceURL) if err != nil { return "Unable to create client: " + sourceURL, iodine.New(err, nil) } reader, size, err := sourceClnt.GetObject(0, 0) if err != nil { return "Unable to retrieve file: " + sourceURL, iodine.New(err, nil) } defer reader.Close() _, err = io.CopyN(os.Stdout, reader, int64(size)) if err != nil { switch e := iodine.ToError(err).(type) { case *os.PathError: if e.Err == syscall.EPIPE { // stdout closed by the user. Gracefully exit. return "", nil } return "Writing data to stdout failed, unexpected problem.. please report this error", iodine.New(err, nil) default: return "Reading data from source failed: " + sourceURL, iodine.New(err, nil) } } return "", nil }
// GET Bucket (List Multipart uploads) // ------------------------- // This operation lists in-progress multipart uploads. An in-progress // multipart upload is a multipart upload that has been initiated, // using the Initiate Multipart Upload request, but has not yet been completed or aborted. // This operation returns at most 1,000 multipart uploads in the response. // func (server *minioAPI) listMultipartUploadsHandler(w http.ResponseWriter, req *http.Request) { acceptsContentType := getContentType(req) resources := getBucketMultipartResources(req.URL.Query()) if resources.MaxUploads == 0 { resources.MaxUploads = maxObjectList } vars := mux.Vars(req) bucket := vars["bucket"] resources, err := server.driver.ListMultipartUploads(bucket, resources) switch iodine.ToError(err).(type) { case nil: // success { // generate response response := generateListMultipartUploadsResult(bucket, resources) encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType) // write headers setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write body w.Write(encodedSuccessResponse) } case drivers.BucketNotFound: { writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path) } default: { log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } } }
// HEAD Bucket // ---------- // This operation is useful to determine if a bucket exists. // The operation returns a 200 OK if the bucket exists and you // have permission to access it. Otherwise, the operation might // return responses such as 404 Not Found and 403 Forbidden. func (server *minioAPI) headBucketHandler(w http.ResponseWriter, req *http.Request) { acceptsContentType := getContentType(req) vars := mux.Vars(req) bucket := vars["bucket"] _, err := server.driver.GetBucketMetadata(bucket) switch iodine.ToError(err).(type) { case nil: { writeSuccessResponse(w, acceptsContentType) } case drivers.BucketNotFound: { error := getErrorCode(NoSuchBucket) w.WriteHeader(error.HTTPStatusCode) } case drivers.BucketNameInvalid: { error := getErrorCode(InvalidBucketName) w.WriteHeader(error.HTTPStatusCode) } default: { log.Error.Println(iodine.New(err, nil)) error := getErrorCode(InternalError) w.WriteHeader(error.HTTPStatusCode) } } }
// PUT Bucket ACL // ---------- // This implementation of the PUT operation modifies the bucketACL for authenticated request func (server *minioAPI) putBucketACLHandler(w http.ResponseWriter, req *http.Request) { acceptsContentType := getContentType(req) // read from 'x-amz-acl' aclType := getACLType(req) if aclType == unsupportedACLType { writeErrorResponse(w, req, NotImplemented, acceptsContentType, req.URL.Path) return } vars := mux.Vars(req) bucket := vars["bucket"] err := server.driver.SetBucketMetadata(bucket, getACLTypeString(aclType)) switch iodine.ToError(err).(type) { case nil: { writeSuccessResponse(w, acceptsContentType) } case drivers.BucketNameInvalid: { writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path) } case drivers.BucketNotFound: { writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path) } default: { log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } } }
// HeadBucketHandler - HEAD Bucket // ---------- // This operation is useful to determine if a bucket exists. // The operation returns a 200 OK if the bucket exists and you // have permission to access it. Otherwise, the operation might // return responses such as 404 Not Found and 403 Forbidden. func (api Minio) HeadBucketHandler(w http.ResponseWriter, req *http.Request) { // Ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until Ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) vars := mux.Vars(req) bucket := vars["bucket"] _, err := api.Donut.GetBucketMetadata(bucket) switch iodine.ToError(err).(type) { case nil: writeSuccessResponse(w, acceptsContentType) case donut.BucketNotFound: error := getErrorCode(NoSuchBucket) w.WriteHeader(error.HTTPStatusCode) case donut.BucketNameInvalid: error := getErrorCode(InvalidBucketName) w.WriteHeader(error.HTTPStatusCode) default: log.Error.Println(iodine.New(err, nil)) error := getErrorCode(InternalError) w.WriteHeader(error.HTTPStatusCode) } }
func (s *MySuite) TestInvalidTcpAddr(c *C) { os.Setenv(envCountKey, "") n := &minNet{} _, err := n.Listen("tcp", "abc") c.Assert(err, Not(IsNil)) c.Assert(regexp.MustCompile("^missing port in address abc$").MatchString(iodine.ToError(err).Error()), Equals, true) }
// runListCmd - is a handler for mc ls command func runListCmd(ctx *cli.Context) { args := ctx.Args() if globalAliasFlag { if !ctx.Args().Present() { args = []string{"."} } } else if !ctx.Args().Present() || ctx.Args().First() == "help" { cli.ShowCommandHelpAndExit(ctx, "ls", 1) // last argument is exit code } config := mustGetMcConfig() for _, arg := range args { targetURL, err := getExpandedURL(arg, config.Aliases) if err != nil { switch e := iodine.ToError(err).(type) { case errUnsupportedScheme: console.Fatalf("Unknown type of URL %s. %s\n", e.url, err) default: console.Fatalf("Unable to parse argument %s. %s\n", arg, err) } } // if recursive strip off the "..." newTargetURL := stripRecursiveURL(targetURL) err = doListCmd(newTargetURL, isURLRecursive(targetURL)) if err != nil { console.Fatalf("Failed to list : %s. %s\n", targetURL, err) } } }
func runCatCmd(ctx *cli.Context) { if !ctx.Args().Present() || ctx.Args().First() == "help" { cli.ShowCommandHelpAndExit(ctx, "cat", 1) // last argument is exit code } if !isMcConfigExists() { console.Fatalf("Please run \"mc config generate\". %s\n", errNotConfigured{}) } config := mustGetMcConfig() // Convert arguments to URLs: expand alias, fix format... for _, arg := range ctx.Args() { sourceURL, err := getExpandedURL(arg, config.Aliases) if err != nil { switch e := iodine.ToError(err).(type) { case errUnsupportedScheme: console.Fatalf("Unknown type of URL %s. %s\n", e.url, err) default: console.Fatalf("Unable to parse argument %s. %s\n", arg, err) } } errorMsg, err := doCatCmd(sourceURL) if err != nil { console.Fatalln(errorMsg) } } }
// runMakeBucketCmd is the handler for mc mb command func runMakeBucketCmd(ctx *cli.Context) { if !ctx.Args().Present() || ctx.Args().First() == "help" { cli.ShowCommandHelpAndExit(ctx, "mb", 1) // last argument is exit code } if !isMcConfigExists() { console.Fatalf("Please run \"mc config generate\". %s\n", errNotConfigured{}) } config := mustGetMcConfig() for _, arg := range ctx.Args() { targetURL, err := getExpandedURL(arg, config.Aliases) if err != nil { switch e := iodine.ToError(err).(type) { case errUnsupportedScheme: console.Fatalf("Unknown type of URL %s. %s\n", e.url, err) default: console.Fatalf("Unable to parse argument %s. %s\n", arg, err) } } msg, err := doMakeBucketCmd(targetURL) if err != nil { console.Fatalln(msg) } console.Infoln(msg) } }
// AbortMultipartUploadHandler - Abort multipart upload func (api Minio) AbortMultipartUploadHandler(w http.ResponseWriter, req *http.Request) { // Ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until Ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) if !api.isValidOp(w, req, acceptsContentType) { return } vars := mux.Vars(req) bucket := vars["bucket"] object := vars["object"] objectResourcesMetadata := getObjectResources(req.URL.Query()) err := api.Donut.AbortMultipartUpload(bucket, object, objectResourcesMetadata.UploadID) switch iodine.ToError(err).(type) { case nil: setCommonHeaders(w, getContentTypeString(acceptsContentType), 0) w.WriteHeader(http.StatusNoContent) case donut.InvalidUploadID: writeErrorResponse(w, req, NoSuchUpload, acceptsContentType, req.URL.Path) default: log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } }
// GET Service // ----------- // This implementation of the GET operation returns a list of all buckets // owned by the authenticated sender of the request. func (server *minioAPI) listBucketsHandler(w http.ResponseWriter, req *http.Request) { acceptsContentType := getContentType(req) // uncomment this when we have webcli // without access key credentials one cannot list buckets // if _, err := stripAuth(req); err != nil { // writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path) // return // } buckets, err := server.driver.ListBuckets() switch iodine.ToError(err).(type) { case nil: { // generate response response := generateListBucketsResponse(buckets) encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType) // write headers setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write response w.Write(encodedSuccessResponse) } default: { log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } } }
func (s *MySuite) TestInvalidNetwork(c *C) { os.Setenv(envCountKey, "") n := &minNet{} _, err := n.Listen("foo", "") c.Assert(err, Not(IsNil)) c.Assert(regexp.MustCompile("^unknown network foo$").MatchString(iodine.ToError(err).Error()), Equals, true) }
func doCatCmd(sourceURL string) (string, error) { sourceClnt, err := source2Client(sourceURL) if err != nil { return "Unable to create client: " + sourceURL, NewIodine(iodine.New(err, nil)) } // ignore size, since os.Stat() would not return proper size all the time for local filesystem // for example /proc files. reader, _, err := sourceClnt.GetObject(0, 0) if err != nil { return "Unable to retrieve file: " + sourceURL, NewIodine(iodine.New(err, nil)) } defer reader.Close() // read till EOF _, err = io.Copy(os.Stdout, reader) if err != nil { switch e := iodine.ToError(err).(type) { case *os.PathError: if e.Err == syscall.EPIPE { // stdout closed by the user. Gracefully exit. return "", nil } return "Writing data to stdout failed, unexpected problem.. please report this error", iodine.New(err, nil) default: return "Reading data from source failed: " + sourceURL, NewIodine(iodine.New(err, nil)) } } return "", nil }
// Abort multipart upload func (server *minioAPI) abortMultipartUploadHandler(w http.ResponseWriter, req *http.Request) { acceptsContentType := getContentType(req) // handle ACL's here at bucket level if !server.isValidOp(w, req, acceptsContentType) { return } vars := mux.Vars(req) bucket := vars["bucket"] object := vars["object"] objectResourcesMetadata := getObjectResources(req.URL.Query()) err := server.driver.AbortMultipartUpload(bucket, object, objectResourcesMetadata.UploadID) switch iodine.ToError(err).(type) { case nil: { setCommonHeaders(w, getContentTypeString(acceptsContentType), 0) w.WriteHeader(http.StatusNoContent) } case drivers.InvalidUploadID: { writeErrorResponse(w, req, NoSuchUpload, acceptsContentType, req.URL.Path) } default: { log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } } }
func runAccessCmd(ctx *cli.Context) { if !ctx.Args().Present() || ctx.Args().First() == "help" { cli.ShowCommandHelpAndExit(ctx, "access", 1) // last argument is exit code } config := mustGetMcConfig() acl := bucketACL(ctx.Args().First()) if !acl.isValidBucketACL() { console.Fatalf("Valid types are [private, public, readonly]. %s\n", errInvalidACL{acl: acl.String()}) } for _, arg := range ctx.Args().Tail() { targetURL, err := getExpandedURL(arg, config.Aliases) if err != nil { switch e := iodine.ToError(err).(type) { case errUnsupportedScheme: console.Fatalf("Unknown type of URL %s. %s\n", e.url, err) default: console.Fatalf("Unable to parse argument %s. %s\n", arg, err) } } msg, err := doUpdateAccessCmd(targetURL, acl) if err != nil { console.Fatalln(msg) } console.Infoln(msg) } }
// doConfig is the handler for "mc config" sub-command. func doConfig(arg string, aliases []string) (string, error) { configPath, err := getMcConfigPath() if err != nil { return "Unable to determine config file path.", NewIodine(iodine.New(err, nil)) } err = saveConfig(arg, aliases) if err != nil { switch iodine.ToError(err).(type) { case errConfigExists: return "Configuration file [" + configPath + "]", NewIodine(iodine.New(err, nil)) case errInvalidArgument: return "Incorrect usage, please use \"mc config help\" ", NewIodine(iodine.New(err, nil)) case errAliasExists: return "Alias name: [" + aliases[0] + "]", NewIodine(iodine.New(err, nil)) case errInvalidAliasName: return "Alias [" + aliases[0] + "] is reserved word or invalid", NewIodine(iodine.New(err, nil)) case errInvalidURL: return "Alias [" + aliases[1] + "] is invalid URL", NewIodine(iodine.New(err, nil)) default: // unexpected error return "Unable to modify config file [" + configPath + "].", NewIodine(iodine.New(err, nil)) } } if arg == "alias" { return "Alias written to [" + configPath + "].", nil } return "", NewIodine(iodine.New(errUnexpected{}, nil)) }
// GetObjectHandler - GET Object // ---------- // This implementation of the GET operation retrieves object. To use GET, // you must have READ access to the object. func (api Minio) GetObjectHandler(w http.ResponseWriter, req *http.Request) { // ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until Ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) if !api.isValidOp(w, req, acceptsContentType) { return } var object, bucket string vars := mux.Vars(req) bucket = vars["bucket"] object = vars["object"] metadata, err := api.Donut.GetObjectMetadata(bucket, object) switch iodine.ToError(err).(type) { case nil: // success { httpRange, err := getRequestedRange(req, metadata.Size) if err != nil { writeErrorResponse(w, req, InvalidRange, acceptsContentType, req.URL.Path) return } switch httpRange.start == 0 && httpRange.length == 0 { case true: setObjectHeaders(w, metadata) if _, err := api.Donut.GetObject(w, bucket, object); err != nil { // unable to write headers, we've already printed data. Just close the connection. log.Error.Println(iodine.New(err, nil)) } case false: metadata.Size = httpRange.length setRangeObjectHeaders(w, metadata, httpRange) w.WriteHeader(http.StatusPartialContent) if _, err := api.Donut.GetPartialObject(w, bucket, object, httpRange.start, httpRange.length); err != nil { // unable to write headers, we've already printed data. Just close the connection. log.Error.Println(iodine.New(err, nil)) } } } case donut.BucketNameInvalid: writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path) case donut.BucketNotFound: writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path) case donut.ObjectNotFound: writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path) case donut.ObjectNameInvalid: writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path) default: log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } }
// ListMultipartUploadsHandler - GET Bucket (List Multipart uploads) // ------------------------- // This operation lists in-progress multipart uploads. An in-progress // multipart upload is a multipart upload that has been initiated, // using the Initiate Multipart Upload request, but has not yet been completed or aborted. // This operation returns at most 1,000 multipart uploads in the response. // func (api Minio) ListMultipartUploadsHandler(w http.ResponseWriter, req *http.Request) { // Ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) if !api.isValidOp(w, req, acceptsContentType) { return } resources := getBucketMultipartResources(req.URL.Query()) if resources.MaxUploads < 0 { writeErrorResponse(w, req, InvalidMaxUploads, acceptsContentType, req.URL.Path) return } if resources.MaxUploads == 0 { resources.MaxUploads = maxObjectList } vars := mux.Vars(req) bucket := vars["bucket"] var signature *donut.Signature if _, ok := req.Header["Authorization"]; ok { // Init signature V4 verification var err error signature, err = InitSignatureV4(req) if err != nil { writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) return } } resources, err := api.Donut.ListMultipartUploads(bucket, resources, signature) switch iodine.ToError(err).(type) { case nil: // success { // generate response response := generateListMultipartUploadsResponse(bucket, resources) encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType) // write headers setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write body w.Write(encodedSuccessResponse) } case donut.SignatureDoesNotMatch: writeErrorResponse(w, req, SignatureDoesNotMatch, acceptsContentType, req.URL.Path) case donut.BucketNotFound: writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path) default: log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } }
// CompleteMultipartUploadHandler - Complete multipart upload func (api Minio) CompleteMultipartUploadHandler(w http.ResponseWriter, req *http.Request) { // Ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until Ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) if !api.isValidOp(w, req, acceptsContentType) { return } vars := mux.Vars(req) bucket := vars["bucket"] object := vars["object"] objectResourcesMetadata := getObjectResources(req.URL.Query()) var signature *donut.Signature if _, ok := req.Header["Authorization"]; ok { // Init signature V4 verification var err error signature, err = InitSignatureV4(req) if err != nil { writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) return } } metadata, err := api.Donut.CompleteMultipartUpload(bucket, object, objectResourcesMetadata.UploadID, req.Body, signature) switch iodine.ToError(err).(type) { case nil: { response := generateCompleteMultpartUploadResponse(bucket, object, "", metadata.MD5Sum) encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType) // write headers setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write body w.Write(encodedSuccessResponse) } case donut.InvalidUploadID: writeErrorResponse(w, req, NoSuchUpload, acceptsContentType, req.URL.Path) case donut.InvalidPartOrder: writeErrorResponse(w, req, InvalidPartOrder, acceptsContentType, req.URL.Path) case donut.MissingDateHeader: writeErrorResponse(w, req, RequestTimeTooSkewed, acceptsContentType, req.URL.Path) case donut.SignatureDoesNotMatch: writeErrorResponse(w, req, SignatureDoesNotMatch, acceptsContentType, req.URL.Path) case donut.IncompleteBody: writeErrorResponse(w, req, IncompleteBody, acceptsContentType, req.URL.Path) case donut.MalformedXML: writeErrorResponse(w, req, MalformedXML, acceptsContentType, req.URL.Path) default: log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } }
func (s *MySuite) TestInvalidCountEnvVariable(c *C) { os.Setenv(envCountKey, "a") n := &minNet{} expected := regexp.MustCompile("^found invalid count value: LISTEN_FDS=a$") err := n.getInheritedListeners() c.Assert(err, Not(IsNil)) c.Assert(expected.MatchString(iodine.ToError(err).Error()), Equals, true) }
func (s *MySuite) TestInheritErrorOnListenTCPWithInvalidCount(c *C) { os.Setenv(envCountKey, "a") n := &minNet{} expected := regexp.MustCompile("^found invalid count value: LISTEN_FDS=a$") _, err := n.Listen("tcp", ":0") c.Assert(err, Not(IsNil)) c.Assert(expected.MatchString(iodine.ToError(err).Error()), Equals, true) }
// CompleteMultipartUploadHandler - Complete multipart upload func (api Minio) CompleteMultipartUploadHandler(w http.ResponseWriter, req *http.Request) { // Ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until Ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) if !api.isValidOp(w, req, acceptsContentType) { return } decoder := xml.NewDecoder(req.Body) parts := &CompleteMultipartUpload{} err := decoder.Decode(parts) if err != nil { log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) return } if !sort.IsSorted(completedParts(parts.Part)) { writeErrorResponse(w, req, InvalidPartOrder, acceptsContentType, req.URL.Path) return } vars := mux.Vars(req) bucket := vars["bucket"] object := vars["object"] objectResourcesMetadata := getObjectResources(req.URL.Query()) partMap := make(map[int]string) for _, part := range parts.Part { partMap[part.PartNumber] = part.ETag } metadata, err := api.Donut.CompleteMultipartUpload(bucket, object, objectResourcesMetadata.UploadID, partMap) switch iodine.ToError(err).(type) { case nil: { response := generateCompleteMultpartUploadResult(bucket, object, "", metadata.MD5Sum) encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType) // write headers setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write body w.Write(encodedSuccessResponse) } case donut.InvalidUploadID: writeErrorResponse(w, req, NoSuchUpload, acceptsContentType, req.URL.Path) default: log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } }
// NewMultipartUploadHandler - New multipart upload func (api Minio) NewMultipartUploadHandler(w http.ResponseWriter, req *http.Request) { // Ticket master block { op := Operation{} op.ProceedCh = make(chan struct{}) api.OP <- op // block until Ticket master gives us a go <-op.ProceedCh } acceptsContentType := getContentType(req) if !api.isValidOp(w, req, acceptsContentType) { return } if !isRequestUploads(req.URL.Query()) { writeErrorResponse(w, req, MethodNotAllowed, acceptsContentType, req.URL.Path) return } var object, bucket string vars := mux.Vars(req) bucket = vars["bucket"] object = vars["object"] var signature *donut.Signature if _, ok := req.Header["Authorization"]; ok { // Init signature V4 verification var err error signature, err = InitSignatureV4(req) if err != nil { writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) return } } uploadID, err := api.Donut.NewMultipartUpload(bucket, object, req.Header.Get("Content-Type"), signature) switch iodine.ToError(err).(type) { case nil: { response := generateInitiateMultipartUploadResponse(bucket, object, uploadID) encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType) // write headers setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write body w.Write(encodedSuccessResponse) } case donut.SignatureDoesNotMatch: writeErrorResponse(w, req, SignatureDoesNotMatch, acceptsContentType, req.URL.Path) case donut.ObjectExists: writeErrorResponse(w, req, MethodNotAllowed, acceptsContentType, req.URL.Path) default: log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } }
func testGetDirectoryReturnsObjectNotFound(c *check.C, create func() Driver) { drivers := create() err := drivers.CreateBucket("bucket", "") c.Assert(err, check.IsNil) _, err = drivers.CreateObject("bucket", "dir1/dir2/object", "", "", int64(len("hello world")), bytes.NewBufferString("hello world")) c.Assert(err, check.IsNil) var byteBuffer bytes.Buffer length, err := drivers.GetObject(&byteBuffer, "bucket", "dir1") c.Assert(length, check.Equals, int64(0)) switch err := iodine.ToError(err).(type) { case ObjectNotFound: { c.Assert(err.Bucket, check.Equals, "bucket") c.Assert(err.Object, check.Equals, "dir1") } default: { // force a failure with a line number c.Assert(err, check.Equals, "ObjectNotFound") } } c.Assert(len(byteBuffer.Bytes()), check.Equals, 0) var byteBuffer2 bytes.Buffer length, err = drivers.GetObject(&byteBuffer, "bucket", "dir1/") c.Assert(length, check.Equals, int64(0)) switch err := iodine.ToError(err).(type) { case ObjectNotFound: { c.Assert(err.Bucket, check.Equals, "bucket") c.Assert(err.Object, check.Equals, "dir1/") } default: { // force a failure with a line number c.Assert(err, check.Equals, "ObjectNotFound") } } c.Assert(len(byteBuffer2.Bytes()), check.Equals, 0) }
// runDiffCmd - is a handler for mc diff command func runDiffCmd(ctx *cli.Context) { if len(ctx.Args()) != 2 || ctx.Args().First() == "help" { cli.ShowCommandHelpAndExit(ctx, "diff", 1) // last argument is exit code } if !isMcConfigExists() { console.Fatalf("Please run \"mc config generate\". %s\n", errNotConfigured{}) } config := mustGetMcConfig() firstURL := ctx.Args().First() secondURL := ctx.Args()[1] var err error firstURL, err = getExpandedURL(firstURL, config.Aliases) if err != nil { switch e := iodine.ToError(err).(type) { case errUnsupportedScheme: console.Fatalf("Unknown type of URL %s. %s\n", e.url, err) default: console.Fatalf("Unable to parse argument %s. %s\n", firstURL, err) } } secondURL, err = getExpandedURL(secondURL, config.Aliases) if err != nil { switch e := iodine.ToError(err).(type) { case errUnsupportedScheme: console.Fatalf("Unknown type of URL %s. %s\n", e.url, err) default: console.Fatalf("Unable to parse argument %s. %s\n", secondURL, err) } } if isURLRecursive(secondURL) { console.Fatalf("Second URL cannot be recursive. %s\n", errInvalidArgument{}) } newFirstURL := stripRecursiveURL(firstURL) for diff := range doDiffCmd(newFirstURL, secondURL, isURLRecursive(firstURL)) { if diff.err != nil { console.Fatalln(diff.message) } console.Infoln(diff.message) } }
// GET Object // ---------- // This implementation of the GET operation retrieves object. To use GET, // you must have READ access to the object. func (server *minioAPI) getObjectHandler(w http.ResponseWriter, req *http.Request) { acceptsContentType := getContentType(req) // verify if this operation is allowed if !server.isValidOp(w, req, acceptsContentType) { return } var object, bucket string vars := mux.Vars(req) bucket = vars["bucket"] object = vars["object"] metadata, err := server.driver.GetObjectMetadata(bucket, object) switch iodine.ToError(err).(type) { case nil: // success { httpRange, err := getRequestedRange(req, metadata.Size) if err != nil { writeErrorResponse(w, req, InvalidRange, acceptsContentType, req.URL.Path) return } switch httpRange.start == 0 && httpRange.length == 0 { case true: setObjectHeaders(w, metadata) if _, err := server.driver.GetObject(w, bucket, object); err != nil { // unable to write headers, we've already printed data. Just close the connection. log.Error.Println(iodine.New(err, nil)) } case false: metadata.Size = httpRange.length setRangeObjectHeaders(w, metadata, httpRange) w.WriteHeader(http.StatusPartialContent) if _, err := server.driver.GetPartialObject(w, bucket, object, httpRange.start, httpRange.length); err != nil { // unable to write headers, we've already printed data. Just close the connection. log.Error.Println(iodine.New(err, nil)) } } } case drivers.ObjectNotFound: { writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path) } case drivers.ObjectNameInvalid: { writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path) } default: { log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } } }
// Complete multipart upload func (server *minioAPI) completeMultipartUploadHandler(w http.ResponseWriter, req *http.Request) { acceptsContentType := getContentType(req) // handle ACL's here at bucket level if !server.isValidOp(w, req, acceptsContentType) { return } decoder := xml.NewDecoder(req.Body) parts := &CompleteMultipartUpload{} err := decoder.Decode(parts) if err != nil { log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) return } if !sort.IsSorted(completedParts(parts.Part)) { writeErrorResponse(w, req, InvalidPartOrder, acceptsContentType, req.URL.Path) return } vars := mux.Vars(req) bucket := vars["bucket"] object := vars["object"] objectResourcesMetadata := getObjectResources(req.URL.Query()) partMap := make(map[int]string) for _, part := range parts.Part { partMap[part.PartNumber] = part.ETag } etag, err := server.driver.CompleteMultipartUpload(bucket, object, objectResourcesMetadata.UploadID, partMap) switch iodine.ToError(err).(type) { case nil: { response := generateCompleteMultpartUploadResult(bucket, object, "", etag) encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType) // write headers setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse)) // write body w.Write(encodedSuccessResponse) } case drivers.InvalidUploadID: { writeErrorResponse(w, req, NoSuchUpload, acceptsContentType, req.URL.Path) } default: { log.Error.Println(iodine.New(err, nil)) writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path) } } }