use of com.github.ambry.messageformat.BlobInfo in project ambry by linkedin.
the class MockRouter method putBlob.
@Override
public Future<String> putBlob(BlobProperties blobProperties, byte[] userMetadata, ReadableStreamChannel channel, PutBlobOptions options, Callback<String> callback, QuotaChargeCallback quotaChargeCallback) {
lock.lock();
try {
FutureResult<String> future = new FutureResult<>();
long size = channel.getSize();
try {
InputStream input = new ReadableStreamChannelInputStream(channel);
byte[] bytes = Utils.readBytesFromStream(input, (int) size);
BlobInfoAndData blob = new BlobInfoAndData(new BlobInfo(blobProperties, userMetadata), bytes);
String id;
do {
id = TestUtils.getRandomString(10);
} while (allBlobs.putIfAbsent(id, blob) != null);
future.done(id, null);
if (callback != null) {
callback.onCompletion(id, null);
}
return future;
} catch (Exception e) {
logger.error("Failed to put blob", e);
future.done(null, e);
if (callback != null) {
callback.onCompletion(null, e);
}
return future;
}
} finally {
lock.unlock();
}
}
use of com.github.ambry.messageformat.BlobInfo in project ambry by linkedin.
the class AmbrySecurityServiceTest method testExceptionCasesProcessResponse.
/**
* Tests exception cases for
* {@link SecurityService#processResponse(RestRequest, RestResponseChannel, BlobInfo, Callback)}
* @param restMethod the {@link RestMethod} of the request to be made
* @param restResponseChannel the {@link RestResponseChannel} to write responses over.
* @param blobInfo the {@link BlobInfo} to be used for the {@link RestRequest}
* @param expectedErrorCode the {@link RestServiceErrorCode} expected in the exception returned.
* @throws Exception
*/
private void testExceptionCasesProcessResponse(RestMethod restMethod, RestResponseChannel restResponseChannel, BlobInfo blobInfo, RestServiceErrorCode expectedErrorCode) throws Exception {
ThrowingConsumer<ExecutionException> errorAction = e -> {
Assert.assertTrue("Exception should have been an instance of RestServiceException", e.getCause() instanceof RestServiceException);
RestServiceException re = (RestServiceException) e.getCause();
Assert.assertEquals("Unexpected RestServerErrorCode (Future)", expectedErrorCode, re.getErrorCode());
};
RestRequest restRequest = createRestRequest(restMethod, "/", null);
TestUtils.assertException(ExecutionException.class, () -> securityService.processResponse(restRequest, restResponseChannel, blobInfo).get(), errorAction);
}
use of com.github.ambry.messageformat.BlobInfo in project ambry by linkedin.
the class AmbrySecurityServiceTest method testGetSubResource.
/**
* Tests GET of sub-resources.
* @param subResource the {@link RestUtils.SubResource} to test.
* @throws Exception
*/
private void testGetSubResource(BlobInfo blobInfo, RestUtils.SubResource subResource) throws Exception {
MockRestResponseChannel restResponseChannel = new MockRestResponseChannel();
RestRequest restRequest = createRestRequest(RestMethod.GET, "/sampleId/" + subResource, null);
Pair<Account, Container> accountAndContainer = getAccountAndContainer(blobInfo.getBlobProperties());
insertAccountAndContainer(restRequest, accountAndContainer.getFirst(), accountAndContainer.getSecond());
securityService.processResponse(restRequest, restResponseChannel, blobInfo).get();
Assert.assertEquals("ProcessResponse status should have been set ", ResponseStatus.Ok, restResponseChannel.getStatus());
Assert.assertNotNull("Date has not been set", restResponseChannel.getHeader(RestUtils.Headers.DATE));
Assert.assertEquals("Last Modified does not match creation time", RestUtils.toSecondsPrecisionInMs(blobInfo.getBlobProperties().getCreationTimeInMs()), RestUtils.getTimeFromDateString(restResponseChannel.getHeader(RestUtils.Headers.LAST_MODIFIED)).longValue());
if (subResource.equals(RestUtils.SubResource.BlobInfo)) {
verifyBlobPropertiesHeaders(blobInfo.getBlobProperties(), restResponseChannel);
verifyAccountAndContainerHeaders(restResponseChannel, accountAndContainer.getFirst(), accountAndContainer.getSecond());
Assert.assertEquals("LifeVersion mismatch", Short.toString(blobInfo.getLifeVersion()), restResponseChannel.getHeader(RestUtils.Headers.LIFE_VERSION));
} else {
verifyAbsenceOfHeaders(restResponseChannel, RestUtils.Headers.PRIVATE, RestUtils.Headers.TTL, RestUtils.Headers.SERVICE_ID, RestUtils.Headers.OWNER_ID, RestUtils.Headers.AMBRY_CONTENT_TYPE, RestUtils.Headers.CREATION_TIME, RestUtils.Headers.BLOB_SIZE, RestUtils.Headers.ACCEPT_RANGES, RestUtils.Headers.CONTENT_RANGE, RestUtils.Headers.LIFE_VERSION);
}
Map<String, String> userMetadata = blobInfo.getUserMetadata() != null ? RestUtils.buildUserMetadata(blobInfo.getUserMetadata()) : null;
if (userMetadata == null && !(blobInfo.getUserMetadata().length == 0)) {
Assert.assertTrue("Internal key " + RestUtils.InternalKeys.SEND_USER_METADATA_AS_RESPONSE_BODY + " should be set", (Boolean) restRequest.getArgs().get(RestUtils.InternalKeys.SEND_USER_METADATA_AS_RESPONSE_BODY));
} else if (!(blobInfo.getUserMetadata().length == 0)) {
USER_METADATA.forEach((key, value) -> Assert.assertEquals("Value of " + key + " not as expected", value, restResponseChannel.getHeader(key)));
}
}
use of com.github.ambry.messageformat.BlobInfo in project ambry by linkedin.
the class FrontendRestRequestService method securityPostProcessRequestCallback.
/**
* Build a callback to use for {@link SecurityService#postProcessRequest}. This callback forwards request to the
* {@link Router} once ID conversion is completed. In the case of some sub-resources
* (e.g., {@link SubResource#Replicas}), the request is completed and not forwarded to the {@link Router}.
* @param convertedId the converted blob ID to use in router requests.
* @param restRequest the {@link RestRequest}.
* @param restResponseChannel the {@link RestResponseChannel}.
* @param getCallback the {@link GetCallback} to use if this is a {@link RestMethod#GET} request, or null for other
* request types.
* @param headCallback the {@link HeadCallback} to use if this is a {@link RestMethod#HEAD} request, or null for other
* request types.
* @param deleteCallback the {@link DeleteCallback} to use if this is a {@link RestMethod#DELETE} request, or null for
* other request types.
* @return the {@link Callback} to use.
*/
private Callback<Void> securityPostProcessRequestCallback(String convertedId, RestRequest restRequest, RestResponseChannel restResponseChannel, GetCallback getCallback, HeadCallback headCallback, DeleteCallback deleteCallback) {
Callback<ReadableStreamChannel> completionCallback = (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception);
RestMethod restMethod = restRequest.getRestMethod();
AsyncOperationTracker.Metrics metrics;
switch(restMethod) {
case GET:
metrics = frontendMetrics.getSecurityPostProcessRequestMetrics;
break;
case HEAD:
metrics = frontendMetrics.headSecurityPostProcessRequestMetrics;
break;
case DELETE:
metrics = frontendMetrics.deleteSecurityPostProcessRequestMetrics;
break;
default:
throw new IllegalStateException("Unrecognized RestMethod: " + restMethod);
}
return FrontendUtils.buildCallback(metrics, result -> {
ReadableStreamChannel response = null;
switch(restMethod) {
case GET:
SubResource subResource = getRequestPath(restRequest).getSubResource();
// inject encryption metrics if need be
if (BlobId.isEncrypted(convertedId)) {
RestRequestMetrics restRequestMetrics = getMetricsGroupForGet(frontendMetrics, subResource).getRestRequestMetrics(restRequest.isSslUsed(), true);
restRequest.getMetricsTracker().injectMetrics(restRequestMetrics);
}
if (subResource == null) {
getCallback.markStartTime();
router.getBlob(convertedId, getCallback.options, getCallback, QuotaUtils.buildQuotaChargeCallback(restRequest, quotaManager, true));
} else {
switch(subResource) {
case BlobInfo:
case UserMetadata:
case Segment:
getCallback.markStartTime();
router.getBlob(convertedId, getCallback.options, getCallback, QuotaUtils.buildQuotaChargeCallback(restRequest, quotaManager, true));
break;
case Replicas:
response = getReplicasHandler.getReplicas(convertedId, restResponseChannel);
break;
}
}
break;
case HEAD:
GetOption getOption = getGetOption(restRequest, frontendConfig.defaultRouterGetOption);
// inject encryption metrics if need be
if (BlobId.isEncrypted(convertedId)) {
RestRequestMetrics requestMetrics = frontendMetrics.headBlobMetricsGroup.getRestRequestMetrics(restRequest.isSslUsed(), true);
restRequest.getMetricsTracker().injectMetrics(requestMetrics);
}
headCallback.markStartTime();
router.getBlob(convertedId, new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.BlobInfo).getOption(getOption).restRequest(restRequest).build(), headCallback, QuotaUtils.buildQuotaChargeCallback(restRequest, quotaManager, false));
break;
case DELETE:
deleteCallback.markStartTime();
router.deleteBlob(convertedId, getHeader(restRequest.getArgs(), Headers.SERVICE_ID, false), deleteCallback, QuotaUtils.buildQuotaChargeCallback(restRequest, quotaManager, false));
break;
default:
throw new IllegalStateException("Unrecognized RestMethod: " + restMethod);
}
if (response != null) {
completionCallback.onCompletion(response, null);
}
}, restRequest.getUri(), logger, completionCallback);
}
use of com.github.ambry.messageformat.BlobInfo in project ambry by linkedin.
the class AmbryIdConverterFactoryTest method testConversionForNamedBlob.
/**
* Tests the conversion by the {@code idConverter}.
* @param idConverter the {@link IdConverter} instance to use.
* @param restMethod the {@link RestMethod} of the {@link RestRequest} that will be created.
* @param signedIdMetadata the headers of the {@link RestRequest}.
* @param expectedOutput the expected output from the {@code idConverter}.
* @param input the input string
* @throws Exception
*/
private void testConversionForNamedBlob(IdConverter idConverter, RestMethod restMethod, Map<String, String> signedIdMetadata, String expectedOutput, String input) throws Exception {
JSONObject requestData = new JSONObject();
JSONObject headers = new JSONObject();
String contentType = "application/octet-stream";
headers.put(RestUtils.Headers.AMBRY_CONTENT_TYPE, contentType);
requestData.put(MockRestRequest.REST_METHOD_KEY, restMethod.name());
requestData.put(MockRestRequest.URI_KEY, NAMED_BLOB_PATH);
requestData.put(MockRestRequest.HEADERS_KEY, headers);
RestRequest restRequest = new MockRestRequest(requestData, null);
if (signedIdMetadata != null) {
restRequest.setArg(RestUtils.InternalKeys.SIGNED_ID_METADATA_KEY, signedIdMetadata);
}
BlobInfo blobInfo = null;
if (restMethod.equals(RestMethod.PUT)) {
restRequest.setArg(RestUtils.InternalKeys.REQUEST_PATH, RequestPath.parse(NAMED_BLOB_PATH, Collections.emptyMap(), Collections.emptyList(), "Ambry-test"));
blobInfo = new BlobInfo(new BlobProperties(-1, "service", accountId, containerId, false), new byte[0]);
}
IdConversionCallback callback = new IdConversionCallback();
assertEquals("Converted ID does not match expected (Future)", expectedOutput, idConverter.convert(restRequest, input, blobInfo, callback).get(5, TimeUnit.SECONDS));
assertEquals("Converted ID does not match expected (Callback)", expectedOutput, callback.result);
}
Aggregations