Java Code Examples for com.linecorp.armeria.common.HttpResponse#from()

The following examples show how to use com.linecorp.armeria.common.HttpResponse#from() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: AuthService.java    From armeria with Apache License 2.0 6 votes vote down vote up
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
    return HttpResponse.from(AuthorizerUtil.authorize(authorizer, ctx, req).handleAsync((result, cause) -> {
        try {
            final HttpService delegate = (HttpService) unwrap();
            if (cause == null) {
                if (result != null) {
                    return result ? successHandler.authSucceeded(delegate, ctx, req)
                                  : failureHandler.authFailed(delegate, ctx, req, null);
                }
                cause = AuthorizerUtil.newNullResultException(authorizer);
            }

            return failureHandler.authFailed(delegate, ctx, req, cause);
        } catch (Exception e) {
            return Exceptions.throwUnsafely(e);
        }
    }, ctx.contextAwareEventLoop()));
}
 
Example 2
Source File: RepositoryService.java    From centraldogma with Apache License 2.0 6 votes vote down vote up
/**
 * POST /projects/{projectName}/repositories/{repoName}/delete/revisions/{revision}{path}
 * Deletes a file.
 */
@Post("regex:/projects/(?<projectName>[^/]+)/repositories/(?<repoName>[^/]+)" +
      "/delete/revisions/(?<revision>[^/]+)(?<path>/.*$)")
@RequiresWritePermission
public HttpResponse deleteFile(@Param String projectName,
                               @Param String repoName,
                               @Param String revision,
                               @Param String path,
                               AggregatedHttpRequest request,
                               ServiceRequestContext ctx) {
    final CommitMessageDto commitMessage;
    try {
        final JsonNode node = Jackson.readTree(request.contentUtf8());
        commitMessage = Jackson.convertValue(node.get("commitMessage"), CommitMessageDto.class);
    } catch (IOException e) {
        throw new IllegalArgumentException("invalid data to be parsed", e);
    }

    final CompletableFuture<?> future =
            push(projectName, repoName, new Revision(revision), AuthUtil.currentAuthor(ctx),
                 commitMessage.getSummary(), commitMessage.getDetail().getContent(),
                 Markup.valueOf(commitMessage.getDetail().getMarkup()), Change.ofRemoval(path));

    return HttpResponse.from(future.thenApply(unused -> HttpResponse.of(HttpStatus.OK)));
}
 
Example 3
Source File: WebOperationService.java    From armeria with Apache License 2.0 6 votes vote down vote up
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) {
    final CompletableFuture<HttpResponse> resFuture = new CompletableFuture<>();
    req.aggregate().handle((aggregatedReq, t) -> {
        if (t != null) {
            resFuture.completeExceptionally(t);
            return null;
        }
        if (operation.isBlocking()) {
            ctx.blockingTaskExecutor().execute(() -> invoke(ctx, aggregatedReq, resFuture));
        } else {
            invoke(ctx, aggregatedReq, resFuture);
        }
        return null;
    });
    return HttpResponse.from(resFuture);
}
 
Example 4
Source File: DeferredHttpFile.java    From armeria with Apache License 2.0 6 votes vote down vote up
@Override
public HttpService asService() {
    final HttpFile delegate = this.delegate;
    if (delegate != null) {
        return delegate.asService();
    }

    return (ctx, req) -> HttpResponse.from(stage.thenApply(file -> {
        setDelegate(file);
        try {
            return file.asService().serve(ctx, req);
        } catch (Exception e) {
            return Exceptions.throwUnsafely(e);
        }
    }));
}
 
Example 5
Source File: HttpServerStreamingTest.java    From armeria with Apache License 2.0 6 votes vote down vote up
@Override
protected HttpResponse doPost(ServiceRequestContext ctx, HttpRequest req) {
    final CompletableFuture<HttpResponse> responseFuture = new CompletableFuture<>();
    final HttpResponse res = HttpResponse.from(responseFuture);
    req.subscribe(new StreamConsumer(ctx.eventLoop(), slow) {
        @Override
        public void onError(Throwable cause) {
            responseFuture.complete(
                    HttpResponse.of(
                            HttpStatus.INTERNAL_SERVER_ERROR,
                            MediaType.PLAIN_TEXT_UTF_8,
                            Exceptions.traceText(cause)));
        }

        @Override
        public void onComplete() {
            responseFuture.complete(
                    HttpResponse.of(
                            HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, "%d", numReceivedBytes()));
        }
    });
    return res;
}
 
Example 6
Source File: THttpService.java    From armeria with Apache License 2.0 5 votes vote down vote up
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
    if (req.method() != HttpMethod.POST) {
        return HttpResponse.of(HttpStatus.METHOD_NOT_ALLOWED);
    }

    final SerializationFormat serializationFormat = determineSerializationFormat(req);
    if (serializationFormat == null) {
        return HttpResponse.of(HttpStatus.UNSUPPORTED_MEDIA_TYPE,
                               MediaType.PLAIN_TEXT_UTF_8, PROTOCOL_NOT_SUPPORTED);
    }

    if (!validateAcceptHeaders(req, serializationFormat)) {
        return HttpResponse.of(HttpStatus.NOT_ACCEPTABLE,
                               MediaType.PLAIN_TEXT_UTF_8, ACCEPT_THRIFT_PROTOCOL_MUST_MATCH_CONTENT_TYPE);
    }

    final CompletableFuture<HttpResponse> responseFuture = new CompletableFuture<>();
    final HttpResponse res = HttpResponse.from(responseFuture);
    ctx.logBuilder().serializationFormat(serializationFormat);
    ctx.logBuilder().defer(RequestLogProperty.REQUEST_CONTENT);
    PooledHttpRequest.of(req).aggregateWithPooledObjects(
            ctx.eventLoop(), ctx.alloc()).handle((aReq, cause) -> {
        if (cause != null) {
            final HttpResponse errorRes;
            if (ctx.config().verboseResponses()) {
                errorRes = HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR,
                                           MediaType.PLAIN_TEXT_UTF_8,
                                           Exceptions.traceText(cause));
            } else {
                errorRes = HttpResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
            }
            responseFuture.complete(errorRes);
            return null;
        }
        decodeAndInvoke(ctx, aReq, serializationFormat, responseFuture);
        return null;
    }).exceptionally(CompletionActions::log);
    return res;
}
 
Example 7
Source File: SamlAuthSsoHandler.java    From centraldogma with Apache License 2.0 5 votes vote down vote up
@Override
public HttpResponse loginSucceeded(ServiceRequestContext ctx, AggregatedHttpRequest req,
                                   MessageContext<Response> message, @Nullable String sessionIndex,
                                   @Nullable String relayState) {
    final Response response = requireNonNull(message, "message").getMessage();
    final String username = Optional.ofNullable(findLoginNameFromSubjects(response))
                                    .orElseGet(() -> findLoginNameFromAttributes(response));
    if (Strings.isNullOrEmpty(username)) {
        return loginFailed(ctx, req, message,
                           new IllegalStateException("Cannot get a username from the response"));
    }

    final String sessionId = sessionIdGenerator.get();
    final Session session =
            new Session(sessionId, loginNameNormalizer.apply(username), sessionValidDuration);

    final String redirectionScript;
    if (!Strings.isNullOrEmpty(relayState)) {
        redirectionScript = "window.location.href='/#" + relayState + '\'';
    } else {
        redirectionScript = "window.location.href='/'";
    }
    return HttpResponse.from(loginSessionPropagator.apply(session).thenApply(
            unused -> HttpResponse.of(HttpStatus.OK, MediaType.HTML_UTF_8, getHtmlWithOnload(
                    "localStorage.setItem('sessionId','" + sessionId + "')",
                    redirectionScript))));
}
 
Example 8
Source File: RetryingClient.java    From armeria with Apache License 2.0 5 votes vote down vote up
@Override
protected HttpResponse doExecute(ClientRequestContext ctx, HttpRequest req) throws Exception {
    final CompletableFuture<HttpResponse> responseFuture = new CompletableFuture<>();
    final HttpResponse res = HttpResponse.from(responseFuture, ctx.eventLoop());
    final HttpRequestDuplicator reqDuplicator = req.toDuplicator(ctx.eventLoop(), 0);
    doExecute0(ctx, reqDuplicator, req, res, responseFuture);
    return res;
}
 
Example 9
Source File: MockWebServerExtension.java    From armeria with Apache License 2.0 5 votes vote down vote up
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
    return HttpResponse.from(req.aggregate().thenApply(aggReq -> {
        recordedRequests.add(new RecordedRequest(ctx, aggReq));

        final HttpResponse response = mockResponses.poll();
        if (response == null) {
            throw new IllegalStateException(
                    "No response enqueued. Did you call MockWebServer.enqueue? Request: " + aggReq);
        }

        return response;
    }));
}
 
Example 10
Source File: AbstractUnsafeUnaryGrpcService.java    From armeria with Apache License 2.0 5 votes vote down vote up
@Override
protected final HttpResponse doPost(ServiceRequestContext ctx, PooledHttpRequest req) {
    final CompletableFuture<HttpResponse> responseFuture =
            req.aggregateWithPooledObjects(ctx.contextAwareEventLoop(), ctx.alloc())
               .thenCompose(msg -> deframeMessage(msg.content(), ctx.alloc()))
               .thenCompose(this::handleMessage)
               .thenApply(responseMessage -> {
                   final ArmeriaMessageFramer framer = new ArmeriaMessageFramer(
                           ctx.alloc(), Integer.MAX_VALUE);
                   final HttpData framed = framer.writePayload(responseMessage);
                   return HttpResponse.of(
                           RESPONSE_HEADERS,
                           framed,
                           GrpcTrailersUtil.statusToTrailers(StatusCodes.OK, null, true).build());
               })
               .exceptionally(t -> {
                   final HttpHeadersBuilder trailers;
                   if (t instanceof ArmeriaStatusException) {
                       final ArmeriaStatusException statusException = (ArmeriaStatusException) t;
                       trailers = GrpcTrailersUtil.statusToTrailers(
                               statusException.getCode(), statusException.getMessage(), false);
                   } else {
                       trailers = GrpcTrailersUtil.statusToTrailers(
                               StatusCodes.INTERNAL, t.getMessage(), false);
                   }
                   return HttpResponse.of(trailers.build());
               });

    return HttpResponse.from(responseFuture);
}
 
Example 11
Source File: DefaultLogoutService.java    From centraldogma with Apache License 2.0 5 votes vote down vote up
@Override
protected HttpResponse doPost(ServiceRequestContext ctx, HttpRequest req) throws Exception {
    return HttpResponse.from(
            req.aggregate()
               .thenApply(msg -> AuthTokenExtractors.oAuth2().apply(RequestHeaders.of(msg.headers())))
               .thenCompose(token -> {
                   final String sessionId = token.accessToken();
                   return executor.execute(Command.removeSession(sessionId));
               })
               .thenApply(unused -> HttpResponse.of(HttpStatus.OK))
               .exceptionally(cause -> HttpApiUtil.newResponse(ctx, HttpStatus.INTERNAL_SERVER_ERROR,
                                                               cause)));
}
 
Example 12
Source File: ContentPreviewingServiceTest.java    From armeria with Apache License 2.0 5 votes vote down vote up
@Override
protected void configure(ServerBuilder sb) throws Exception {
    final HttpService httpService = (ctx, req) -> HttpResponse.from(
            req.aggregate()
               .thenApply(aggregated -> {
                   final ResponseHeaders responseHeaders =
                           ResponseHeaders.of(HttpStatus.OK,
                                              HttpHeaderNames.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8);
                   return HttpResponse.of(responseHeaders,
                                          HttpData.ofUtf8("Hello " + aggregated.contentUtf8() + '!'));
               }));
    sb.decorator("/beforeEncoding", EncodingService.builder()
                                                   .minBytesToForceChunkedEncoding(1)
                                                   .newDecorator());
    sb.decorator("/beforeEncoding", ContentPreviewingService.newDecorator(100));
    sb.service("/beforeEncoding", httpService);

    sb.decorator("/encoded", decodingContentPreviewDecorator());
    sb.decorator("/encoded", EncodingService.builder()
                                            .minBytesToForceChunkedEncoding(1)
                                            .newDecorator());
    sb.service("/encoded", httpService);

    sb.decoratorUnder("/", (delegate, ctx, req) -> {
        contextCaptor.set(ctx);
        return delegate.serve(ctx, req);
    });
}
 
Example 13
Source File: ServerTest.java    From armeria with Apache License 2.0 4 votes vote down vote up
@Override
protected final HttpResponse doPost(ServiceRequestContext ctx, HttpRequest req) {
    return HttpResponse.from(req.aggregate()
                                .thenApply(this::echo)
                                .exceptionally(CompletionActions::log));
}
 
Example 14
Source File: AnnotatedService.java    From armeria with Apache License 2.0 4 votes vote down vote up
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
    return HttpResponse.from(serve0(ctx, req));
}
 
Example 15
Source File: AnnotatedServiceExceptionHandlerTest.java    From armeria with Apache License 2.0 4 votes vote down vote up
@Get("/resp2")
@ExceptionHandler(NoExceptionHandler.class)
@ExceptionHandler(AnticipatedExceptionHandler2.class)
public HttpResponse asyncHttpResponse(ServiceRequestContext ctx, HttpRequest req) {
    return HttpResponse.from(completeExceptionallyLater(ctx));
}
 
Example 16
Source File: AbstractHttpFile.java    From armeria with Apache License 2.0 4 votes vote down vote up
@Override
public HttpService asService() {
    return (ctx, req) -> {
        final HttpMethod method = ctx.method();
        if (method != HttpMethod.GET && method != HttpMethod.HEAD) {
            return HttpResponse.of(HttpStatus.METHOD_NOT_ALLOWED);
        }

        return HttpResponse.from(readAttributes(ctx.blockingTaskExecutor()).thenApply(attrs -> {
            if (attrs == null) {
                return HttpResponse.of(HttpStatus.NOT_FOUND);
            }

            // See https://tools.ietf.org/html/rfc7232#section-6 for more information
            // about how conditional requests are handled.

            // Handle 'if-none-match' header.
            final RequestHeaders reqHeaders = req.headers();
            final String etag = generateEntityTag(attrs);
            final String ifNoneMatch = reqHeaders.get(HttpHeaderNames.IF_NONE_MATCH);
            if (etag != null && ifNoneMatch != null) {
                if ("*".equals(ifNoneMatch) || entityTagMatches(etag, ifNoneMatch)) {
                    return newNotModified(attrs, etag);
                }
            }

            // Handle 'if-modified-since' header, only if 'if-none-match' does not exist.
            if (ifNoneMatch == null) {
                try {
                    final Long ifModifiedSince =
                            reqHeaders.getTimeMillis(HttpHeaderNames.IF_MODIFIED_SINCE);
                    if (ifModifiedSince != null) {
                        // HTTP-date does not have subsecond-precision; add 999ms to it.
                        final long ifModifiedSinceMillis = LongMath.saturatedAdd(ifModifiedSince, 999);
                        if (attrs.lastModifiedMillis() <= ifModifiedSinceMillis) {
                            return newNotModified(attrs, etag);
                        }
                    }
                } catch (Exception ignore) {
                    // Malformed date.
                }
            }

            // Precondition did not match. Handle as usual.
            switch (ctx.method()) {
                case HEAD:
                    final ResponseHeaders resHeaders = readHeaders(attrs);
                    if (resHeaders != null) {
                        return HttpResponse.of(resHeaders);
                    }
                    break;
                case GET:
                    final HttpResponse res = read(ctx.blockingTaskExecutor(), ctx.alloc(), attrs);
                    if (res != null) {
                        return res;
                    }
                    break;
                default:
                    throw new Error(); // Never reaches here.
            }

            // readHeaders() or read() returned null above.
            return HttpResponse.of(HttpStatus.NOT_FOUND);
        }));
    };
}
 
Example 17
Source File: SamlService.java    From armeria with Apache License 2.0 4 votes vote down vote up
@Override
public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception {
    final SamlServiceFunction func = serviceMap.get(req.path());
    if (func == null) {
        return HttpResponse.of(HttpStatus.BAD_REQUEST, MediaType.PLAIN_TEXT_UTF_8,
                               DATA_INCORRECT_PATH);
    }

    final CompletionStage<AggregatedHttpRequest> f;
    if (portConfigHolder.isDone()) {
        f = req.aggregate();
    } else {
        f = portConfigHolder.future().thenCompose(unused -> req.aggregate());
    }
    return HttpResponse.from(f.handle((aggregatedReq, cause) -> {
        if (cause != null) {
            logger.warn("{} Failed to aggregate a SAML request.", ctx, cause);
            return HttpResponse.of(HttpStatus.BAD_REQUEST, MediaType.PLAIN_TEXT_UTF_8,
                                   DATA_AGGREGATION_FAILURE);
        }

        final SamlPortConfig portConfig = portConfigHolder.config();
        final boolean isTls = ctx.sessionProtocol().isTls();
        if (portConfig.scheme().isTls() != isTls) {
            if (isTls) {
                logger.warn("{} Received a SAML request via a TLS connection.", ctx);
                return HttpResponse.of(HttpStatus.BAD_REQUEST, MediaType.PLAIN_TEXT_UTF_8,
                                       DATA_NOT_CLEARTEXT);
            } else {
                logger.warn("{} Received a SAML request via a cleartext connection.", ctx);
                return HttpResponse.of(HttpStatus.BAD_REQUEST, MediaType.PLAIN_TEXT_UTF_8,
                                       DATA_NOT_TLS);
            }
        }

        // Use user-specified hostname if it exists.
        // If there's no hostname set by a user, the default virtual hostname will be used.
        final String defaultHostname =
                firstNonNull(sp.hostname(), ctx.config().virtualHost().defaultHostname());
        return func.serve(ctx, aggregatedReq, defaultHostname, portConfig);
    }));
}
 
Example 18
Source File: UnframedGrpcService.java    From armeria with Apache License 2.0 4 votes vote down vote up
@Override
public HttpResponse serve(
        PooledHttpService delegate, ServiceRequestContext ctx, PooledHttpRequest req) throws Exception {
    final RequestHeaders clientHeaders = req.headers();
    final MediaType contentType = clientHeaders.contentType();
    if (contentType == null) {
        // All gRPC requests, whether framed or non-framed, must have content-type. If it's not sent, let
        // the delegate return its usual error message.
        return delegate.serve(ctx, req);
    }

    for (SerializationFormat format : GrpcSerializationFormats.values()) {
        if (format.isAccepted(contentType)) {
            // Framed request, so just delegate.
            return delegate.serve(ctx, req);
        }
    }

    final String methodName = GrpcRequestUtil.determineMethod(ctx);
    final MethodDescriptor<?, ?> method = methodName != null ? methodsByName.get(methodName) : null;
    if (method == null) {
        // Unknown method, let the delegate return a usual error.
        return delegate.serve(ctx, req);
    }

    if (method.getType() != MethodType.UNARY) {
        return HttpResponse.of(HttpStatus.BAD_REQUEST,
                               MediaType.PLAIN_TEXT_UTF_8,
                               "Only unary methods can be used with non-framed requests.");
    }

    final RequestHeadersBuilder grpcHeaders = clientHeaders.toBuilder();

    final MediaType framedContentType;
    if (contentType.is(MediaType.PROTOBUF)) {
        framedContentType = GrpcSerializationFormats.PROTO.mediaType();
    } else if (contentType.is(MediaType.JSON_UTF_8)) {
        framedContentType = GrpcSerializationFormats.JSON.mediaType();
    } else {
        return HttpResponse.of(HttpStatus.UNSUPPORTED_MEDIA_TYPE,
                               MediaType.PLAIN_TEXT_UTF_8,
                               "Unsupported media type. Only application/protobuf is supported.");
    }
    grpcHeaders.contentType(framedContentType);

    if (grpcHeaders.get(GrpcHeaderNames.GRPC_ENCODING) != null) {
        return HttpResponse.of(HttpStatus.UNSUPPORTED_MEDIA_TYPE,
                               MediaType.PLAIN_TEXT_UTF_8,
                               "gRPC encoding is not supported for non-framed requests.");
    }

    // All clients support no encoding, and we don't support gRPC encoding for non-framed requests, so just
    // clear the header if it's present.
    grpcHeaders.remove(GrpcHeaderNames.GRPC_ACCEPT_ENCODING);

    ctx.logBuilder().defer(RequestLogProperty.REQUEST_CONTENT,
                           RequestLogProperty.RESPONSE_CONTENT);

    final CompletableFuture<HttpResponse> responseFuture = new CompletableFuture<>();
    req.aggregateWithPooledObjects(ctx.eventLoop(), ctx.alloc()).handle((clientRequest, t) -> {
        if (t != null) {
            responseFuture.completeExceptionally(t);
        } else {
            frameAndServe(ctx, grpcHeaders.build(), clientRequest, responseFuture);
        }
        return null;
    });
    return HttpResponse.from(responseFuture);
}
 
Example 19
Source File: CallCredentialsDecoratingClient.java    From armeria with Apache License 2.0 4 votes vote down vote up
@Override
protected HttpResponse execute(PooledHttpClient client, ClientRequestContext ctx, PooledHttpRequest req) {
    final CompletableFuture<HttpResponse> response = new CompletableFuture<>();

    final RequestInfo requestInfo = new RequestInfo() {
        @Override
        public MethodDescriptor<?, ?> getMethodDescriptor() {
            return method;
        }

        @Override
        public SecurityLevel getSecurityLevel() {
            // Semantics of SecurityLevel aren't very clear but we follow the pattern of the upstream
            // client.
            // https://github.com/grpc/grpc-java/blob/bf2a66c8a2d52be41afd7090c151984a3ce64e0d/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java#L586
            return ctx.sessionProtocol().isTls() ? SecurityLevel.PRIVACY_AND_INTEGRITY : SecurityLevel.NONE;
        }

        @Override
        public String getAuthority() {
            return authority;
        }

        @Override
        public Attributes getTransportAttrs() {
            // There is a race condition where the first request to an endpoint will not have transport
            // attributes available yet. It seems unlikely that CallCredentials could ever use these
            // attributes reliably, so for now don't return them and revisit if anyone needs them.

            // The most popular CallCredentials, GoogleAuthLibraryCallCredentials, do not use the transport
            // attributes.
            // https://github.com/grpc/grpc-java/blob/master/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java
            return Attributes.EMPTY;
        }
    };

    credentials.applyRequestMetadata(
            requestInfo,
            CommonPools.blockingTaskExecutor(),
            new MetadataApplier() {
                @Override
                public void apply(Metadata metadata) {
                    ctx.mutateAdditionalRequestHeaders(
                            headers -> MetadataUtil.fillHeaders(metadata, headers));
                    try {
                        response.complete(client.execute(ctx, req));
                    } catch (Exception e) {
                        response.completeExceptionally(e);
                    }
                }

                @Override
                public void fail(Status status) {
                    response.completeExceptionally(status.asRuntimeException());
                }
            });

    return HttpResponse.from(response);
}
 
Example 20
Source File: LogoutService.java    From centraldogma with Apache License 2.0 4 votes vote down vote up
@Override
protected HttpResponse doPost(ServiceRequestContext ctx, HttpRequest req) throws Exception {
    return HttpResponse.from(
            req.aggregate().thenApply(msg -> AuthTokenExtractors.oAuth2().apply(
                    RequestHeaders.of(msg.headers())))
               .thenApplyAsync(token -> {
                   if (token == null) {
                       return HttpResponse.of(HttpStatus.OK);
                   }

                   final String sessionId = token.accessToken();
                   // Need to set the thread-local security manager to silence
                   // the UnavailableSecurityManagerException logged at DEBUG level.
                   ThreadContext.bind(securityManager);
                   try {
                       final Session session = securityManager.getSession(new DefaultSessionKey(sessionId));
                       if (session != null) {
                           final Subject currentUser = new Subject.Builder(securityManager)
                                   .sessionCreationEnabled(false)
                                   .sessionId(sessionId)
                                   .buildSubject();

                           // Get the principal before logging out because otherwise it will be cleared out.
                           final String username = (String) currentUser.getPrincipal();
                           currentUser.logout();
                       }
                   } catch (Throwable t) {
                       logger.warn("{} Failed to log out: {}", ctx, sessionId, t);
                   } finally {
                       ThreadContext.unbindSecurityManager();
                   }

                   // Do not care the exception raised before, then try to remove session from the
                   // Central Dogma session manager. If it succeeded, the session ID has been also
                   // invalidated so that the logout request with the session ID would not come here again.
                   return HttpResponse.from(
                           logoutSessionPropagator.apply(sessionId).handle((unused, cause) -> {
                               if (cause != null) {
                                   return HttpResponse.of(HttpApiUtil.newResponse(
                                           ctx, HttpStatus.INTERNAL_SERVER_ERROR, cause));
                               } else {
                                   return HttpResponse.of(HttpStatus.OK);
                               }
                           }));
               }, ctx.blockingTaskExecutor()));
}