@Override
  public void preProcessRequest(RestRequest restRequest, Callback<Void> callback) {
    Exception exception = null;
    frontendMetrics.securityServicePreProcessRequestRate.mark();
    long startTimeMs = System.currentTimeMillis();
    if (!isOpen) {
      exception = new RestServiceException("SecurityService is closed", RestServiceErrorCode.ServiceUnavailable);
    } else if (restRequest == null) {
      throw new IllegalArgumentException("RestRequest is null");
    } else if (restRequest.getArgs().containsKey(InternalKeys.KEEP_ALIVE_ON_ERROR_HINT)) {
      exception = new RestServiceException(InternalKeys.KEEP_ALIVE_ON_ERROR_HINT + " is not allowed in the request",
          RestServiceErrorCode.BadRequest);
      //we can't check all internal keys due to we have test in processRequestTest to test preProcessRequest without handler.
    } else if (restRequest.getArgs().containsKey(InternalKeys.SEND_TRACKING_INFO)) {
      exception = new RestServiceException(InternalKeys.SEND_TRACKING_INFO + " is not allowed in the request",
          RestServiceErrorCode.BadRequest);
    }
    restRequest.setArg(InternalKeys.SEND_TRACKING_INFO, frontendConfig.attachTrackingInfo);
    if (exception == null && urlSigningService.isRequestSigned(restRequest)) {
      urlSigningService.verifySignedRequest(restRequest, (r, e) -> {
        frontendMetrics.securityServicePreProcessRequestTimeInMs.update(System.currentTimeMillis() - startTimeMs);
        // This is a hack to make sure the blob names are url encoded in the restRequest so later in the RequestPath.parse
        // it be can be correctly decoded back.
        // The reason why we have to do this for signed url, is that in signed urls, blob names are placed in the query
        // parameter, not in the header, so it's already url decoded. In most case, decode an already decoded string
        // won't change this string, but there is a one special case - "+". A url encoded "+" is "%2B", but a url encode
        // space " " is "+". So if the blob name contains a "+", then it would be decoded to "+" and then further
        // decoded to " " if we don't re-encode it here.
        // And we have to do this after verifying signed url since this would change the signature.
        if (restRequest.getArgs().get(Headers.BLOB_ID) != null) {
          try {
            String encodedBlobId =
                URLEncoder.encode((String) restRequest.getArgs().get(Headers.BLOB_ID), StandardCharsets.UTF_8.name());
            restRequest.setArg(Headers.BLOB_ID, encodedBlobId);
          } catch (Exception encodingException) {
            LOGGER.error("Failed to encode blob id signed url: {}", restRequest.getArgs().get(Headers.BLOB_ID), e);
          }
        }
        callback.onCompletion(r, e);
      });
    } else {
      frontendMetrics.securityServicePreProcessRequestTimeInMs.update(System.currentTimeMillis() - startTimeMs);
      callback.onCompletion(null, exception);
    }
  }
Default implementation of {@link SecurityService} for Ambry that doesn't do any validations, but just
sets the respective headers on response.
ambry-frontend/src/main/java/com/github/ambry/frontend/AmbrySecurityService.java