private Callback<String> idConverterCallback(BlobInfo blobInfo, String blobId) {
      return buildCallback(frontendMetrics.putIdConversionMetrics, convertedBlobId -> {
        restResponseChannel.setHeader(Headers.LOCATION, convertedBlobId);
        // Do ttl update with retryExecutor. Use the blob ID returned from the router instead of the converted ID
        // since the converted ID may be changed by the ID converter.
        String serviceId = blobInfo.getBlobProperties().getServiceId();
        retryExecutor.runWithRetries(retryPolicy,
            callback -> router.updateBlobTtl(null, blobId, serviceId, Utils.Infinite_Time, callback,
                QuotaUtils.buildQuotaChargeCallback(restRequest, quotaManager, false)), this::isRetriable,
            routerTtlUpdateCallback(blobInfo, blobId));
      }, uri, LOGGER, finalCallback);
    }
After {@link IdConverter#convert} finishes, call {@link SecurityService#postProcessRequest} to perform
request time security checks that rely on the request being fully parsed and any additional arguments set.
@param blobInfo the {@link BlobInfo} to use for security checks.
@param blobId the blob ID returned by the router (without decoration or obfuscation by id converter).
@return a {@link Callback} to be used with {@link IdConverter#convert}.
ambry-frontend/src/main/java/com/github/ambry/frontend/s3/S3MultipartCompleteUploadHandler.java