func directoryGetMultiple(ctx *restContext, curEntry *directoryEntry, filenames []string) ( entry *directoryEntry, found bool, status retcode.Status) { if len(filenames) == 0 { // End reached entry = curEntry found = true return } else { // Process current if !curEntry.isDirectory { // Not a directory, cannot go further found = false return } else { // Ok, process next var nextEntry *directoryEntry var nextStatus retcode.Status nextEntry, found, nextStatus = directoryGet(ctx, curEntry.targetHash, filenames[0]) if !found { return } if !nextStatus.IsOk() { status = nextStatus return } // Ok, looks good, can go to next nextFilenames := filenames[1:] entry, found, status = directoryGetMultiple(ctx, nextEntry, nextFilenames) return } } }
func (self *restServer) directoryGet(ctx *restContext) { var status retcode.Status hashAsString, status := ctx.UrlParams.NonEmptyString("hash") if !status.IsOk() { ctx.WriteErrorStatus(status) return } hash, err := encoding.Base32Decode(hashAsString) if err != nil { status = retcode.NewStatusFmt(retcode.ErrorClient, "Hash does not seem to be a base32 hash") ctx.WriteErrorStatus(status) return } filenames := directorySubPath(ctx.UrlParams, ctx) curEntry := &directoryEntry{ isDirectory: true, targetHash: hash, } finalEntry, found, status := directoryGetMultiple(ctx, curEntry, filenames) if !found { status = retcode.NewStatusFmt(retcode.OkNotFound, "Entry not found") ctx.WriteErrorStatus(status) return } if finalEntry.isDirectory { // Output all files from directory as json directoryOutputAsJson(ctx, finalEntry) } else { // Redirect to blobget hash := finalEntry.targetHash hashAsString := encoding.Base32Encode(hash) mime := finalEntry.mimeType self.blobGetWithParams(ctx, hash, hashAsString, nil, mime) } }
func (self *blobstoreStruct) op_put(operation *operations.Put, state *minos.OperationState) (ret bucket.BucketReturn) { commonOp := new(commonOperation) retStatus := commonOp.fill(operation.Key, operation.Value) if !retStatus.IsOk() { return &bucket.ReturnGeneric{retStatus} } var status retcode.Status switch commonOp.operation { case operation_incubation_append: if len(commonOp.value) != 1 { panic("When calling append, need exactly one value (data to append)") } status = self.incubator.appendData(state, commonOp.incubationId, commonOp.value[0]) case operation_incubation_cancel: status = self.incubator.cleanIncubation(state, commonOp.incubationId) case operation_incubation_finish: status = self.public.publish(state, commonOp.incubationId) case operation_incubation_new: status = self.incubator.new(state, commonOp.incubationId, true) default: err := errors.New(fmt.Sprintf("Unknown operation: operation-code: "+ "%v (this usually means you called PUT instead of GET). Key: %v\n", commonOp.operation, operation.Key)) status = retcode.NewStatusError(retcode.ErrorClient, err) } // Done, return if status.IsOk() { return &operations.PutReturn{status} } else { return &bucket.ReturnGeneric{status} } }
func (self *blobstoreStruct) op_get(operation *operations.Get, state *minos.OperationState) (ret bucket.BucketReturn) { commonOp := new(commonOperation) retStatus := commonOp.fill(operation.Key, nil) if !retStatus.IsOk() { return &bucket.ReturnGeneric{retStatus} } var value types.Array var status retcode.Status switch commonOp.operation { case operation_incubation_sum: var incInfo incubationState incInfo, status = self.incubator.information(state, commonOp.incubationId) if status.Code == retcode.OkNotFound { // Not found break } if !status.IsOk() { break } hash := incInfo.restoreHash().Sum(nil) hashEncoded, err := encoding.Cbor().Encode(hash) if err != nil { panic("Error encoding hash") } length := incInfo.length lengthEncoded, err := encoding.Cbor().Encode(length) if err != nil { panic("Error encoding length") } value = types.Array{hashEncoded, lengthEncoded} case operation_public_content: var skipData []byte var limitData []byte if len(commonOp.restKey) > 0 { skipData = commonOp.restKey[0] } if len(commonOp.restKey) > 1 { limitData = commonOp.restKey[1] } var err error var skip uint64 if skipData != nil { skip, err = binary.ReadUvarint(bytes.NewReader(skipData)) if err != nil { panic("Error decoding 'skip' (should be a variable uint)") } } var limit int64 if limitData != nil { var limitUint64 uint64 limitUint64, err = binary.ReadUvarint(bytes.NewReader(limitData)) if err != nil { panic("Error decoding 'limit' (should be a variable uint)") } limit = int64(limitUint64) } else { limit = -1 // No limit } var data []byte var entireLength uint64 data, entireLength, status = self.public.read(state, commonOp.hash, skip, limit) if !status.IsOk() { break } if status.Code == retcode.OkNotFound { // Not found break } var lengthEncoded []byte lengthEncoded, err = encoding.Cbor().Encode(entireLength) if err != nil { panic("Error encoding length") } // Ok, found it, return the value value = types.Array{data, lengthEncoded} case operation_public_length: var pubInfo publicState if commonOp.hash == nil { err := errors.New("Hash is missing for getting length") status = retcode.NewStatusError(retcode.ErrorClient, err) } pubInfo, status = self.public.information(state, commonOp.hash) if status.Code == retcode.OkNotFound { // Not found break } if !status.IsOk() { break } length := pubInfo.length lengthEncoded, err := encoding.Cbor().Encode(length) if err != nil { panic("Error encoding length") } value = types.Array{lengthEncoded} default: err := errors.New(fmt.Sprintf("Unknown operation: operation-code: "+ "%v (this usually means you called GET instead of PUT)\n", commonOp.operation)) status = retcode.NewStatusError(retcode.ErrorClient, err) } // Done, return if status.IsOk() { if status.Code == retcode.OkNotFound { if status.Text == "" { status.Text = fmt.Sprintf("Given hash is: %v", commonOp.hash) } return &bucket.ReturnGeneric{status} } else { return &operations.GetReturn{ Status: status, Value: value, } } } else { return &bucket.ReturnGeneric{status} } }
func (self *restServer) blobPost(ctx *restContext) { var status retcode.Status var isGlobalBlobStore bool bucketId, bucketIdAsString, status := ctx.ReadBucketId(&ctx.UrlParams, "bucketId", true) if !status.IsOk() { ctx.WriteErrorStatus(status) return } if len(bucketId) == 0 { // Take the global blob store if no bucket id is supplied bucketId = self.caprica.GlobalBlobStoreId() isGlobalBlobStore = true } var out interface{} // Begin beginUpload := &operations.BucketPutIn{ BucketOperation: operations.BucketOperation{ BucketId: bucketId, }, Key: "incubation/from_rest_api/new", Value: [][]byte{}, } out, status = ctx.execute(beginUpload, operations.BucketPut) if !status.IsOk() { ctx.WriteErrorStatus(status) return } // Now put the entire payload for true { readBuffer := make([]byte, maxReadPerElement) numReadFromBody, err := ctx.Request.Body.Read(readBuffer) defer ctx.Request.Body.Close() if err != nil && err != io.EOF { status = retcode.NewStatusFmt(retcode.ErrorClient, "Could not read body from client: "+ "%v.", err) ctx.WriteErrorStatus(status) return } if numReadFromBody > 0 { uploadOneElement := &operations.BucketPutIn{ BucketOperation: operations.BucketOperation{ BucketId: bucketId, }, Key: "incubation/from_rest_api/append", Value: [][]byte{readBuffer[:numReadFromBody]}, } out, status = ctx.execute(uploadOneElement, operations.BucketPut) if !status.IsOk() { ctx.WriteErrorStatus(status) return } } if err == io.EOF { // End, have read everything break } } // Now read the hash code readHashCode := &operations.BucketGetIn{ BucketOperation: operations.BucketOperation{ BucketId: bucketId, }, Key: "incubation/from_rest_api/sum", } out, status = ctx.execute(readHashCode, operations.BucketGet) if !status.IsOk() { ctx.WriteErrorStatus(status) return } readHashCodeRet := out.(operations.BucketGetOut) hashCodeValues := readHashCodeRet.Value.([][]byte) if len(hashCodeValues) < 2 { status = retcode.NewStatusFmt(retcode.ErrorServer, "Could not get calculated hash value."+ " Blob bucket returned less than 2 value elements.") ctx.WriteErrorStatus(status) return } var hashAsBinary []byte err := encoding.Cbor().Decode(hashCodeValues[0], &hashAsBinary) if err != nil { status = retcode.NewStatusFmt(retcode.ErrorServer, "Cbor decoding of hash code "+ "failed: %v.", err) ctx.WriteErrorStatus(status) return } hashAsBase32 := encoding.Base32Encode(hashAsBinary) var location string if isGlobalBlobStore { location = fmt.Sprintf("/data/%v", hashAsBase32) } else { location = fmt.Sprintf("/data/%v/%v", bucketIdAsString, hashAsBase32) } // And now commit that thing commit := &operations.BucketPutIn{ BucketOperation: operations.BucketOperation{ BucketId: bucketId, }, Key: "incubation/from_rest_api/finish", Value: [][]byte{}, } out, status = ctx.execute(commit, operations.BucketPut) if !status.IsOk() { ctx.WriteErrorStatus(status) return } // Ok, everything ok ctx.WriteLocation(location) ctx.Writer.WriteHeader(201) }