use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.
the class RestUtilsTest method doBuildGetBlobOptionsTestForSubResource.
/**
* Test that {@link RestUtils#buildGetBlobOptions(Map, RestUtils.SubResource, GetOption, int)} works correctly with given args and a
* specified sub-resource.
* @param args the map of args for the method call.
* @param subResource the sub-resource for the call.
* @param expectedRange the {@link ByteRange} expected to be parsed if the call should succeed, or {@code null} if no
* range is expected.
* @param expectedOpType the {@link OperationType} expected to be set in the {@link GetBlobOptions}
* object.
* @param expectedResolveRangeOnEmptyBlob the expected value of {@link GetBlobOptions#resolveRangeOnEmptyBlob}.
* @param shouldSucceed {@code true} if the call should succeed.
* @throws RestServiceException
*/
private void doBuildGetBlobOptionsTestForSubResource(Map<String, Object> args, RestUtils.SubResource subResource, ByteRange expectedRange, OperationType expectedOpType, boolean expectedResolveRangeOnEmptyBlob, boolean shouldSucceed) throws RestServiceException {
if (shouldSucceed) {
GetBlobOptions options = RestUtils.buildGetBlobOptions(args, subResource, GetOption.None, null, NO_BLOB_SEGMENT_IDX_SPECIFIED);
assertEquals("Unexpected range for args=" + args + " and subResource=" + subResource, expectedRange, options.getRange());
assertEquals("Unexpected operation type for args=" + args + " and subResource=" + subResource, expectedOpType, options.getOperationType());
assertEquals("Unexpected get options type for args=" + args + " and subResource=" + subResource, GetOption.None, options.getGetOption());
assertEquals("Unexpected resolveRangeOnEmptyBlob for args=" + args + " and subResource=" + subResource, expectedResolveRangeOnEmptyBlob, options.resolveRangeOnEmptyBlob());
} else {
try {
RestUtils.buildGetBlobOptions(args, subResource, GetOption.None, null, NO_BLOB_SEGMENT_IDX_SPECIFIED);
fail("buildGetBlobOptions should not have succeeded with args=" + args + "and subResource=" + subResource);
} catch (RestServiceException expected) {
assertEquals("Unexpected error code.", RestServiceErrorCode.InvalidArgs, expected.getErrorCode());
}
}
}
use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.
the class RestUtilsTest method doBuildGetBlobOptionsTestForSubResource.
/**
* Test that {@link RestUtils#buildGetBlobOptions(Map, RestUtils.SubResource, GetOption)} works correctly with given args and a
* specified sub-resource.
* @param args the map of args for the method call.
* @param subResource the sub-resource for the call.
* @param expectedRange the {@link ByteRange} expected to be parsed if the call should succeed, or {@code null} if no
* range is expected.
* @param expectedOpType the {@link GetBlobOptions.OperationType} expected to be set in the {@link GetBlobOptions}
* object.
* @param shouldSucceed {@code true} if the call should succeed.
* @throws RestServiceException
*/
private void doBuildGetBlobOptionsTestForSubResource(Map<String, Object> args, RestUtils.SubResource subResource, ByteRange expectedRange, GetBlobOptions.OperationType expectedOpType, boolean shouldSucceed) throws RestServiceException {
if (shouldSucceed) {
GetBlobOptions options = RestUtils.buildGetBlobOptions(args, subResource, GetOption.None);
assertEquals("Unexpected range for args=" + args + " and subResource=" + subResource, expectedRange, options.getRange());
assertEquals("Unexpected operation type for args=" + args + " and subResource=" + subResource, expectedOpType, options.getOperationType());
assertEquals("Unexpected get options type for args=" + args + " and subResource=" + subResource, GetOption.None, options.getGetOption());
} else {
try {
RestUtils.buildGetBlobOptions(args, subResource, GetOption.None);
fail("buildGetBlobOptions should not have succeeded with args=" + args + "and subResource=" + subResource);
} catch (RestServiceException expected) {
assertEquals("Unexpected error code.", RestServiceErrorCode.InvalidArgs, expected.getErrorCode());
}
}
}
use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.
the class FrontendRestRequestService method handleGet.
@Override
public void handleGet(final RestRequest restRequest, final RestResponseChannel restResponseChannel) {
ThrowingConsumer<RequestPath> routingAction = requestPath -> {
if (requestPath.matchesOperation(Operations.GET_PEERS)) {
getPeersHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
} else if (requestPath.matchesOperation(Operations.GET_CLUSTER_MAP_SNAPSHOT)) {
getClusterMapSnapshotHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
} else if (requestPath.matchesOperation(Operations.GET_SIGNED_URL)) {
getSignedUrlHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
} else if (requestPath.matchesOperation(Operations.ACCOUNTS)) {
getAccountsHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
} else if (requestPath.matchesOperation(Operations.STATS_REPORT)) {
getStatsReportHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
} else if (requestPath.matchesOperation(Operations.NAMED_BLOB) && NamedBlobPath.parse(requestPath, restRequest.getArgs()).getBlobName() == null) {
listNamedBlobsHandler.handle(restRequest, restResponseChannel, ((result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception)));
} else {
SubResource subResource = requestPath.getSubResource();
GetBlobOptions options = buildGetBlobOptions(restRequest.getArgs(), subResource, getGetOption(restRequest, frontendConfig.defaultRouterGetOption), restRequest, requestPath.getBlobSegmentIdx());
GetCallback routerCallback = new GetCallback(restRequest, restResponseChannel, subResource, options);
SecurityProcessRequestCallback securityCallback = new SecurityProcessRequestCallback(restRequest, restResponseChannel, routerCallback);
if (subResource == SubResource.Replicas) {
securityCallback = new SecurityProcessRequestCallback(restRequest, restResponseChannel);
}
RestRequestMetricsGroup metricsGroup = getMetricsGroupForGet(frontendMetrics, subResource);
RestRequestMetrics restRequestMetrics = metricsGroup.getRestRequestMetrics(restRequest.isSslUsed(), false);
restRequest.getMetricsTracker().injectMetrics(restRequestMetrics);
// named blob requests have their account/container in the URI, so checks can be done prior to ID conversion.
if (requestPath.matchesOperation(Operations.NAMED_BLOB)) {
accountAndContainerInjector.injectAccountAndContainerForNamedBlob(restRequest, metricsGroup);
}
securityService.processRequest(restRequest, securityCallback);
}
};
preProcessAndRouteRequest(restRequest, restResponseChannel, frontendMetrics.getPreProcessingMetrics, routingAction);
}
use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.
the class AmbrySecurityService method processResponse.
@Override
public void processResponse(RestRequest restRequest, RestResponseChannel responseChannel, BlobInfo blobInfo, Callback<Void> callback) {
Exception exception = null;
frontendMetrics.securityServiceProcessResponseRate.mark();
long startTimeMs = System.currentTimeMillis();
if (!isOpen) {
exception = new RestServiceException("SecurityService is closed", RestServiceErrorCode.ServiceUnavailable);
} else {
if (restRequest == null || responseChannel == null) {
throw new IllegalArgumentException("One of the required params is null");
}
RequestPath requestPath = RestUtils.getRequestPath(restRequest);
RestMethod restMethod = restRequest.getRestMethod();
if (blobInfo == null && !restMethod.equals(RestMethod.OPTIONS) && !restMethod.equals(RestMethod.PUT)) {
if (!requestPath.matchesOperation(Operations.GET_SIGNED_URL)) {
throw new IllegalArgumentException("BlobInfo is null");
}
}
try {
GetBlobOptions options;
responseChannel.setHeader(RestUtils.Headers.DATE, new GregorianCalendar().getTime());
switch(restMethod) {
case HEAD:
options = RestUtils.buildGetBlobOptions(restRequest.getArgs(), null, GetOption.None, restRequest, NO_BLOB_SEGMENT_IDX_SPECIFIED);
responseChannel.setStatus(options.getRange() == null ? ResponseStatus.Ok : ResponseStatus.PartialContent);
responseChannel.setHeader(RestUtils.Headers.LAST_MODIFIED, new Date(blobInfo.getBlobProperties().getCreationTimeInMs()));
setHeadResponseHeaders(blobInfo, options, restRequest, responseChannel);
break;
case GET:
if (!requestPath.matchesOperation(Operations.GET_SIGNED_URL)) {
options = RestUtils.buildGetBlobOptions(restRequest.getArgs(), null, GetOption.None, restRequest, NO_BLOB_SEGMENT_IDX_SPECIFIED);
responseChannel.setStatus(ResponseStatus.Ok);
RestUtils.SubResource subResource = RestUtils.getRequestPath(restRequest).getSubResource();
responseChannel.setHeader(RestUtils.Headers.LAST_MODIFIED, new Date(blobInfo.getBlobProperties().getCreationTimeInMs()));
if (subResource == null) {
Long ifModifiedSinceMs = getIfModifiedSinceMs(restRequest);
if (ifModifiedSinceMs != null && RestUtils.toSecondsPrecisionInMs(blobInfo.getBlobProperties().getCreationTimeInMs()) <= ifModifiedSinceMs) {
responseChannel.setStatus(ResponseStatus.NotModified);
} else {
if (options.getRange() != null) {
responseChannel.setStatus(ResponseStatus.PartialContent);
}
setGetBlobResponseHeaders(blobInfo, options, responseChannel);
setBlobPropertiesHeaders(blobInfo.getBlobProperties(), responseChannel);
setAccountAndContainerHeaders(restRequest, responseChannel);
setUserMetadataHeaders(blobInfo.getUserMetadata(), responseChannel);
responseChannel.setHeader(RestUtils.Headers.LIFE_VERSION, blobInfo.getLifeVersion());
}
setCacheHeaders(restRequest, responseChannel);
} else {
if (subResource.equals(RestUtils.SubResource.BlobInfo)) {
setBlobInfoHeaders(blobInfo.getBlobProperties(), responseChannel);
setBlobPropertiesHeaders(blobInfo.getBlobProperties(), responseChannel);
setAccountAndContainerHeaders(restRequest, responseChannel);
responseChannel.setHeader(RestUtils.Headers.LIFE_VERSION, blobInfo.getLifeVersion());
} else if (subResource.equals(SubResource.Segment)) {
setGetBlobResponseHeaders(blobInfo, options, responseChannel);
setBlobPropertiesHeaders(blobInfo.getBlobProperties(), responseChannel);
setAccountAndContainerHeaders(restRequest, responseChannel);
}
if (!setUserMetadataHeaders(blobInfo.getUserMetadata(), responseChannel)) {
restRequest.setArg(InternalKeys.SEND_USER_METADATA_AS_RESPONSE_BODY, true);
}
}
}
break;
case POST:
responseChannel.setStatus(ResponseStatus.Created);
responseChannel.setHeader(RestUtils.Headers.CONTENT_LENGTH, 0);
responseChannel.setHeader(RestUtils.Headers.CREATION_TIME, new Date(blobInfo.getBlobProperties().getCreationTimeInMs()));
break;
case OPTIONS:
case PUT:
if (requestPath.matchesOperation(Operations.NAMED_BLOB)) {
responseChannel.setStatus(ResponseStatus.Created);
responseChannel.setHeader(RestUtils.Headers.CONTENT_LENGTH, 0);
responseChannel.setHeader(RestUtils.Headers.CREATION_TIME, new Date(blobInfo.getBlobProperties().getCreationTimeInMs()));
}
break;
default:
exception = new RestServiceException("Cannot process response for request with method " + restMethod, RestServiceErrorCode.InternalServerError);
}
} catch (RestServiceException e) {
exception = e;
}
}
processRequestCharges(restRequest, responseChannel, blobInfo);
frontendMetrics.securityServiceProcessResponseTimeInMs.update(System.currentTimeMillis() - startTimeMs);
callback.onCompletion(null, exception);
}
use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.
the class GetManagerTest method testBadCallback.
/**
* Test that a bad user defined callback will not crash the router.
* @param getBlobCallback User defined callback to be called after getBlob operation.
* @param getBlobCallbackCalled This latch should be at 0 after {@code getBlobCallback} has been called.
* @param checkBadCallbackBlob {@code true} if the blob contents provided by the getBlob operation with the bad
* callback should be inspected for correctness.
* @throws Exception
*/
private void testBadCallback(Callback<GetBlobResult> getBlobCallback, CountDownLatch getBlobCallbackCalled, Boolean checkBadCallbackBlob) throws Exception {
router = getNonBlockingRouter();
setOperationParams(LARGE_BLOB_SIZE, new GetBlobOptionsBuilder().build());
final CountDownLatch getBlobInfoCallbackCalled = new CountDownLatch(1);
String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get();
List<Future<GetBlobResult>> getBlobInfoFutures = new ArrayList<>();
List<Future<GetBlobResult>> getBlobDataFutures = new ArrayList<>();
GetBlobOptions infoOptions = new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.BlobInfo).build();
GetBlobOptions dataOptions = new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.Data).build();
for (int i = 0; i < 5; i++) {
if (i == 1) {
getBlobInfoFutures.add(router.getBlob(blobId, infoOptions, new Callback<GetBlobResult>() {
@Override
public void onCompletion(GetBlobResult result, Exception exception) {
getBlobInfoCallbackCalled.countDown();
throw new RuntimeException("Throwing an exception in the user callback");
}
}, quotaChargeCallback));
getBlobDataFutures.add(router.getBlob(blobId, dataOptions, getBlobCallback, quotaChargeCallback));
} else {
getBlobInfoFutures.add(router.getBlob(blobId, infoOptions));
getBlobDataFutures.add(router.getBlob(blobId, dataOptions));
}
}
options = dataOptions;
for (int i = 0; i < getBlobDataFutures.size(); i++) {
if (i != 1 || checkBadCallbackBlob) {
compareContent(getBlobDataFutures.get(i).get().getBlobDataChannel());
}
}
options = infoOptions;
for (Future<GetBlobResult> future : getBlobInfoFutures) {
compareBlobInfo(future.get().getBlobInfo(), -1);
}
Assert.assertTrue("getBlobInfo callback not called.", getBlobInfoCallbackCalled.await(2, TimeUnit.SECONDS));
Assert.assertTrue("getBlob callback not called.", getBlobCallbackCalled.await(2, TimeUnit.SECONDS));
Assert.assertEquals("All operations should be finished.", 0, router.getOperationsCount());
Assert.assertTrue("Router should not be closed", router.isOpen());
// Test that GetManager is still operational
setOperationParams(CHUNK_SIZE, new GetBlobOptionsBuilder().build());
blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get();
getBlobAndCompareContent(blobId, -1);
this.options = infoOptions;
getBlobAndCompareContent(blobId, -1);
router.close();
}
Aggregations