### Question:
AmbrySecurityService implements SecurityService { @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); } 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); callback.onCompletion(r, e); }); } else { frontendMetrics.securityServicePreProcessRequestTimeInMs.update(System.currentTimeMillis() - startTimeMs); callback.onCompletion(null, exception); } } AmbrySecurityService(FrontendConfig frontendConfig, FrontendMetrics frontendMetrics,
      UrlSigningService urlSigningService, QuotaManager quotaManager); @Override void preProcessRequest(RestRequest restRequest, Callback<Void> callback); @Override void processRequest(RestRequest restRequest, Callback<Void> callback); @Override void postProcessRequest(RestRequest restRequest, Callback<Void> callback); @Override void processResponse(RestRequest restRequest, RestResponseChannel responseChannel, BlobInfo blobInfo,
      Callback<Void> callback); @Override void close();  }### Answer:
@Test public void preProcessRequestTest() throws Exception { RestMethod[] methods = new RestMethod[]{RestMethod.POST, RestMethod.GET, RestMethod.DELETE, RestMethod.HEAD, RestMethod.OPTIONS, RestMethod.PUT}; for (RestMethod restMethod : methods) { JSONObject headers = new JSONObject(); headers.put(RestUtils.InternalKeys.KEEP_ALIVE_ON_ERROR_HINT, true); RestRequest restRequest = createRestRequest(restMethod, "/", headers); try { securityService.preProcessRequest(restRequest).get(1, TimeUnit.SECONDS); Assert.fail("Should have failed because the request contains a prohibited header: " + RestUtils.InternalKeys.KEEP_ALIVE_ON_ERROR_HINT); } catch (ExecutionException e) { RestServiceException rse = (RestServiceException) Utils.getRootCause(e); Assert.assertEquals("Should be a bad request", RestServiceErrorCode.BadRequest, rse.getErrorCode()); } } RestRequest restRequest = createRestRequest(RestMethod.GET, "/", null); securityService.preProcessRequest(restRequest).get(); Assert.assertTrue("The arg with key: ambry-internal-keys-send-tracking-info should be set to true", (Boolean) restRequest.getArgs().get(RestUtils.InternalKeys.SEND_TRACKING_INFO)); Properties properties = new Properties(); properties.setProperty("frontend.attach.tracking.info", "false"); FrontendConfig frontendConfig = new FrontendConfig(new VerifiableProperties(properties)); SecurityService securityServiceWithTrackingDisabled = new AmbrySecurityService(frontendConfig, new FrontendMetrics(new MetricRegistry()), URL_SIGNING_SERVICE_FACTORY.getUrlSigningService(), quotaManager); restRequest = createRestRequest(RestMethod.GET, "/", null); securityServiceWithTrackingDisabled.preProcessRequest(restRequest); Assert.assertFalse("The arg with key: ambry-internal-keys-send-tracking-info should be set to false", (Boolean) restRequest.getArgs().get(RestUtils.InternalKeys.SEND_TRACKING_INFO)); }