Support for Jetty 10
Closes gh-26123
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package org.springframework.http.client.reactive;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.reactive.client.ReactiveResponse;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -30,9 +32,11 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpResponse} implementation for the Jetty ReactiveStreams HTTP client.
|
||||
@@ -46,6 +50,11 @@ class JettyClientHttpResponse implements ClientHttpResponse {
|
||||
|
||||
private static final Pattern SAMESITE_PATTERN = Pattern.compile("(?i).*SameSite=(Strict|Lax|None).*");
|
||||
|
||||
private static final ClassLoader loader = JettyClientHttpResponse.class.getClassLoader();
|
||||
|
||||
private static final boolean jetty10Present = ClassUtils.isPresent(
|
||||
"org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer", loader);
|
||||
|
||||
|
||||
private final ReactiveResponse reactiveResponse;
|
||||
|
||||
@@ -58,8 +67,11 @@ class JettyClientHttpResponse implements ClientHttpResponse {
|
||||
this.reactiveResponse = reactiveResponse;
|
||||
this.content = Flux.from(content);
|
||||
|
||||
MultiValueMap<String, String> adapter = new JettyHeadersAdapter(reactiveResponse.getHeaders());
|
||||
this.headers = HttpHeaders.readOnlyHttpHeaders(adapter);
|
||||
MultiValueMap<String, String> headers = (jetty10Present ?
|
||||
Jetty10HttpFieldsHelper.getHttpHeaders(reactiveResponse) :
|
||||
new JettyHeadersAdapter(reactiveResponse.getHeaders()));
|
||||
|
||||
this.headers = HttpHeaders.readOnlyHttpHeaders(headers);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,4 +122,38 @@ class JettyClientHttpResponse implements ClientHttpResponse {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
|
||||
private static class Jetty10HttpFieldsHelper {
|
||||
|
||||
private static final Method getHeadersMethod;
|
||||
|
||||
private static final Method getNameMethod;
|
||||
|
||||
private static final Method getValueMethod;
|
||||
|
||||
static {
|
||||
try {
|
||||
getHeadersMethod = Response.class.getMethod("getHeaders");
|
||||
Class<?> type = loader.loadClass("org.eclipse.jetty.http.HttpField");
|
||||
getNameMethod = type.getMethod("getName");
|
||||
getValueMethod = type.getMethod("getValue");
|
||||
}
|
||||
catch (ClassNotFoundException | NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("No compatible Jetty version found", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpHeaders getHttpHeaders(ReactiveResponse response) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
Iterable<?> iterator = (Iterable<?>)
|
||||
ReflectionUtils.invokeMethod(getHeadersMethod, response.getResponse());
|
||||
for (Object field : iterator) {
|
||||
headers.add(
|
||||
(String) ReflectionUtils.invokeMethod(getNameMethod, field),
|
||||
(String) ReflectionUtils.invokeMethod(getValueMethod, field));
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* 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.
|
||||
@@ -36,6 +36,7 @@ import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
@@ -49,6 +50,10 @@ import org.springframework.util.MultiValueMap;
|
||||
*/
|
||||
public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
|
||||
private static final boolean jetty10Present = ClassUtils.isPresent(
|
||||
"org.eclipse.jetty.http.CookieCutter", JettyHttpHandlerAdapter.class.getClassLoader());
|
||||
|
||||
|
||||
public JettyHttpHandlerAdapter(HttpHandler httpHandler) {
|
||||
super(httpHandler);
|
||||
}
|
||||
@@ -58,16 +63,29 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext context)
|
||||
throws IOException, URISyntaxException {
|
||||
|
||||
// TODO: need to compile against Jetty 10 to use HttpFields (class->interface)
|
||||
if (jetty10Present) {
|
||||
return super.createRequest(request, context);
|
||||
}
|
||||
|
||||
Assert.notNull(getServletPath(), "Servlet path is not initialized");
|
||||
return new JettyServerHttpRequest(request, context, getServletPath(), getDataBufferFactory(), getBufferSize());
|
||||
return new JettyServerHttpRequest(
|
||||
request, context, getServletPath(), getDataBufferFactory(), getBufferSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServletServerHttpResponse createResponse(HttpServletResponse response,
|
||||
AsyncContext context, ServletServerHttpRequest request) throws IOException {
|
||||
|
||||
return new JettyServerHttpResponse(
|
||||
response, context, getDataBufferFactory(), getBufferSize(), request);
|
||||
// TODO: need to compile against Jetty 10 to use HttpFields (class->interface)
|
||||
if (jetty10Present) {
|
||||
return new BaseJettyServerHttpResponse(
|
||||
response, context, getDataBufferFactory(), getBufferSize(), request);
|
||||
}
|
||||
else {
|
||||
return new JettyServerHttpResponse(
|
||||
response, context, getDataBufferFactory(), getBufferSize(), request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +105,34 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
}
|
||||
|
||||
|
||||
private static final class JettyServerHttpResponse extends ServletServerHttpResponse {
|
||||
private static class BaseJettyServerHttpResponse extends ServletServerHttpResponse {
|
||||
|
||||
BaseJettyServerHttpResponse(HttpServletResponse response, AsyncContext asyncContext,
|
||||
DataBufferFactory bufferFactory, int bufferSize, ServletServerHttpRequest request)
|
||||
throws IOException {
|
||||
|
||||
super(response, asyncContext, bufferFactory, bufferSize, request);
|
||||
}
|
||||
|
||||
BaseJettyServerHttpResponse(HttpHeaders headers, HttpServletResponse response, AsyncContext asyncContext,
|
||||
DataBufferFactory bufferFactory, int bufferSize, ServletServerHttpRequest request)
|
||||
throws IOException {
|
||||
|
||||
super(headers, response, asyncContext, bufferFactory, bufferSize, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException {
|
||||
ByteBuffer input = dataBuffer.asByteBuffer();
|
||||
int len = input.remaining();
|
||||
ServletResponse response = getNativeResponse();
|
||||
((HttpOutput) response.getOutputStream()).write(input);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class JettyServerHttpResponse extends BaseJettyServerHttpResponse {
|
||||
|
||||
JettyServerHttpResponse(HttpServletResponse response, AsyncContext asyncContext,
|
||||
DataBufferFactory bufferFactory, int bufferSize, ServletServerHttpRequest request)
|
||||
@@ -124,15 +169,6 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||
response.setContentLengthLong(contentLength);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException {
|
||||
ByteBuffer input = dataBuffer.asByteBuffer();
|
||||
int len = input.remaining();
|
||||
ServletResponse response = getNativeResponse();
|
||||
((HttpOutput) response.getOutputStream()).write(input);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user