Beispiel #1
0
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
		}
	}
}
Beispiel #2
0
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)
	}
}
Beispiel #3
0
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}
	}
}
Beispiel #4
0
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}
	}
}
Beispiel #5
0
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)
}