Skip to content

Commit

Permalink
Expose DispatcherHandler as PreFlightRequestHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
rstoyanchev authored and lxbzmy committed Mar 26, 2022
1 parent 4db97df commit fcd5af1
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.cors.reactive;

import reactor.core.publisher.Mono;

import org.springframework.web.server.ServerWebExchange;

/**
* Handler for CORS pre-flight requests.
*
* @author Rossen Stoyanchev
* @since 5.3.4
*/
public interface PreFlightRequestHandler {

/**
* Handle a pre-flight request by finding and applying the CORS configuration
* that matches the expected actual request. As a result of handling, the
* response should be updated with CORS headers or rejected with
* {@link org.springframework.http.HttpStatus#FORBIDDEN}.
* @param exchange the exchange for the request
* @return a completion handle
*/
Mono<Void> handlePreFlight(ServerWebExchange exchange);

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.cors.reactive.PreFlightRequestHandler;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebHandler;
Expand All @@ -53,9 +53,10 @@
*
* <p>{@code DispatcherHandler} is also designed to be a Spring bean itself and
* implements {@link ApplicationContextAware} for access to the context it runs
* in. If {@code DispatcherHandler} is declared with the bean name "webHandler"
* it is discovered by {@link WebHttpHandlerBuilder#applicationContext} which
* creates a processing chain together with {@code WebFilter},
* in. If {@code DispatcherHandler} is declared as a bean with the name
* "webHandler", it is discovered by
* {@link WebHttpHandlerBuilder#applicationContext(ApplicationContext)} which
* puts together a processing chain together with {@code WebFilter},
* {@code WebExceptionHandler} and others.
*
* <p>A {@code DispatcherHandler} bean declaration is included in
Expand All @@ -68,7 +69,7 @@
* @since 5.0
* @see WebHttpHandlerBuilder#applicationContext(ApplicationContext)
*/
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
public class DispatcherHandler implements WebHandler, PreFlightRequestHandler, ApplicationContextAware {

@Nullable
private List<HandlerMapping> handlerMappings;
Expand Down Expand Up @@ -142,6 +143,9 @@ public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
return handlePreFlight(exchange);
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
Expand All @@ -158,11 +162,8 @@ private <R> Mono<R> createNotFoundError() {
}

private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
// No handling for CORS rejected requests and pre-flight requests
ServerHttpRequest request = exchange.getRequest();
HttpStatus status = exchange.getResponse().getStatusCode();
if (ObjectUtils.nullSafeEquals(status, HttpStatus.FORBIDDEN) || CorsUtils.isPreFlightRequest(request)) {
return Mono.empty();
if (ObjectUtils.nullSafeEquals(exchange.getResponse().getStatusCode(), HttpStatus.FORBIDDEN)) {
return Mono.empty(); // CORS rejection
}
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
Expand Down Expand Up @@ -196,4 +197,13 @@ private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
}

@Override
public Mono<Void> handlePreFlight(ServerWebExchange exchange) {
return Flux.fromIterable(this.handlerMappings != null ? this.handlerMappings : Collections.emptyList())
.concatMap(mapping -> mapping.getHandler(exchange))
.switchIfEmpty(Mono.fromRunnable(() -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN)))
.next()
.then();
}

}

0 comments on commit fcd5af1

Please sign in to comment.