Spring WebFlux and CalDav HTTP methods

Viewed 80

I want to create a react-spring (with Netty underhood) proxy that can handle CalDav HTTP methods like REPORT. If I use the ProxyExchange object in the controller it doesn't understand the REPORT method and I get an NPE when using the proxy.forward() method. How can I teach webflux to understand REPORT?

My controller code:

@Controller
public class RestController {

    @RequestMapping(value = "/")
    public Mono<ResponseEntity<byte[]>> proxy(ProxyExchange<byte[]> proxy, ServerHttpRequest request) {
        UriComponents uriComponents = UriComponentsBuilder
                .fromHttpUrl("https://myhost.com")
                .path(request.getPath().value())
                .queryParams(request.getQueryParams())
                .build();

        return proxy
                .sensitive(HttpHeaders.HOST)
                .uri(uriComponents.toUri().toASCIIString())
                .forward();
    }
}
1 Answers

I found solution. You need redefine several spring webflux classes. You should create this package structure in YOUR project: java/org/springframework/cloud/gateway/webflux java/org/springframework/http

Than redefine standard spring ProxyExchange class (just copy class to "java/org/springframework/cloud/gateway/webflux"). Add this code to standard calss:

public Mono<ResponseEntity<T>> report() {
    RequestEntity<Object> requestEntity = headers(RequestEntity.report(uri)).body(body());
    return exchange(requestEntity);
}

public <S> Mono<ResponseEntity<S>> report(Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
    return report().map(converter::apply);
}

public Mono<ResponseEntity<T>> forward() {
    switch (httpMethod) {
        case GET:
            return get();
        case HEAD:
            return head();
        case OPTIONS:
            return options();
        case POST:
            return post();
        case DELETE:
            return delete();
        case PUT:
            return put();
        case PATCH:
            return patch();
        case REPORT:
            return report();
        default:
            return Mono.empty();
    }
}

public <S> Mono<ResponseEntity<S>> forward(Function<ResponseEntity<T>, ResponseEntity<S>> converter) {
    switch (httpMethod) {
        case GET:
            return get(converter);
        case HEAD:
            return head(converter);
        case OPTIONS:
            return options(converter);
        case POST:
            return post(converter);
        case DELETE:
            return delete(converter);
        case PUT:
            return put(converter);
        case PATCH:
            return patch(converter);
        case REPORT:
            return report(converter);
        default:
            return Mono.empty();
    }
}

Then redefine standard spring HttpMethod class (add code below) in "java/org/springframework/http":

public enum HttpMethod {

GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE, REPORT;

And then redefine standard spring RequestEntity class (add code below) in "java/org/springframework/http":

/**
 * Create an HTTP REPORT builder with the given url.
 *
 * @param url the URL
 * @return the created builder
 */
public static BodyBuilder report(URI url) {
    return method(HttpMethod.REPORT, url);
}

/**
 * Create an HTTP REPORT builder with the given string base uri template.
 *
 * @param uriTemplate  the uri template to use
 * @param uriVariables variables to expand the URI template with
 * @return the created builder
 * @since 5.3
 */
public static BodyBuilder report(String uriTemplate, Object... uriVariables) {
    return method(HttpMethod.REPORT, uriTemplate, uriVariables);
}
Related