Early support for Jetty 12 (developed against 12.0.0.alpha2)
Reflective getHeaders calls to be revisited; see GitHub issue #8938 in Jetty project. HttpOutput optimization commented out still in order to avoid alpha build dependency. See gh-29575
This commit is contained in:
parent
4ff18741fd
commit
45d45c2989
|
@ -37,6 +37,12 @@ dependencies {
|
||||||
optional("org.eclipse.jetty:jetty-servlet") {
|
optional("org.eclipse.jetty:jetty-servlet") {
|
||||||
exclude group: "jakarta.servlet", module: "jakarta.servlet-api"
|
exclude group: "jakarta.servlet", module: "jakarta.servlet-api"
|
||||||
}
|
}
|
||||||
|
/* Jetty 12: see org.springframework.http.server.reactive.JettyHttpHandlerAdapter
|
||||||
|
optional("org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.0.alpha2") {
|
||||||
|
exclude group: "jakarta.servlet", module: "jakarta.servlet-api"
|
||||||
|
exclude group: "org.eclipse.jetty", module: "jetty-session"
|
||||||
|
}
|
||||||
|
*/
|
||||||
optional("org.eclipse.jetty:jetty-reactive-httpclient")
|
optional("org.eclipse.jetty:jetty-reactive-httpclient")
|
||||||
optional('org.apache.httpcomponents.client5:httpclient5')
|
optional('org.apache.httpcomponents.client5:httpclient5')
|
||||||
optional('org.apache.httpcomponents.core5:httpcore5-reactive')
|
optional('org.apache.httpcomponents.core5:httpcore5-reactive')
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.springframework.http.client.reactive;
|
||||||
|
|
||||||
import java.util.AbstractSet;
|
import java.util.AbstractSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -186,7 +185,6 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||||
public Iterator<Entry<String, List<String>>> iterator() {
|
public Iterator<Entry<String, List<String>>> iterator() {
|
||||||
return new EntryIterator();
|
return new EntryIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return headers.size();
|
return headers.size();
|
||||||
|
@ -203,16 +201,16 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||||
|
|
||||||
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
||||||
|
|
||||||
private final Enumeration<String> names = headers.getFieldNames();
|
private final Iterator<String> names = headers.getFieldNamesCollection().iterator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return this.names.hasMoreElements();
|
return this.names.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Entry<String, List<String>> next() {
|
public Entry<String, List<String>> next() {
|
||||||
return new HeaderEntry(this.names.nextElement());
|
return new HeaderEntry(this.names.next());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.springframework.http.server.reactive;
|
||||||
|
|
||||||
import java.util.AbstractSet;
|
import java.util.AbstractSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -46,8 +45,8 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||||
private final HttpFields.Mutable headers;
|
private final HttpFields.Mutable headers;
|
||||||
|
|
||||||
|
|
||||||
JettyHeadersAdapter(HttpFields.Mutable headers) {
|
JettyHeadersAdapter(HttpFields headers) {
|
||||||
this.headers = headers;
|
this.headers = (headers instanceof HttpFields.Mutable mutable ? mutable : HttpFields.build(headers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,7 +169,6 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||||
public Iterator<Entry<String, List<String>>> iterator() {
|
public Iterator<Entry<String, List<String>>> iterator() {
|
||||||
return new EntryIterator();
|
return new EntryIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return headers.size();
|
return headers.size();
|
||||||
|
@ -187,16 +185,16 @@ class JettyHeadersAdapter implements MultiValueMap<String, String> {
|
||||||
|
|
||||||
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
private class EntryIterator implements Iterator<Entry<String, List<String>>> {
|
||||||
|
|
||||||
private final Enumeration<String> names = headers.getFieldNames();
|
private final Iterator<String> names = headers.getFieldNamesCollection().iterator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return this.names.hasMoreElements();
|
return this.names.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Entry<String, List<String>> next() {
|
public Entry<String, List<String>> next() {
|
||||||
return new HeaderEntry(this.names.nextElement());
|
return new HeaderEntry(this.names.next());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,13 @@
|
||||||
package org.springframework.http.server.reactive;
|
package org.springframework.http.server.reactive;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import jakarta.servlet.AsyncContext;
|
import jakarta.servlet.AsyncContext;
|
||||||
import jakarta.servlet.ServletResponse;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
@ -36,8 +37,11 @@ import org.springframework.core.io.buffer.DataBuffer;
|
||||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ServletHttpHandlerAdapter} extension that uses Jetty APIs for writing
|
* {@link ServletHttpHandlerAdapter} extension that uses Jetty APIs for writing
|
||||||
|
@ -50,6 +54,23 @@ import org.springframework.util.MultiValueMap;
|
||||||
*/
|
*/
|
||||||
public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
|
|
||||||
|
private static final boolean jetty11Present = ClassUtils.isPresent(
|
||||||
|
"org.eclipse.jetty.server.HttpOutput", JettyHttpHandlerAdapter.class.getClassLoader());
|
||||||
|
|
||||||
|
/* Jetty 12: see spring-web.gradle
|
||||||
|
private static final boolean jetty12Present = ClassUtils.isPresent(
|
||||||
|
"org.eclipse.jetty.ee10.servlet.HttpOutput", JettyHttpHandlerAdapter.class.getClassLoader());
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static final Method getRequestHeadersMethod =
|
||||||
|
ClassUtils.getMethodIfAvailable(Request.class, "getHeaders");
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static final Method getResponseHeadersMethod =
|
||||||
|
ClassUtils.getMethodIfAvailable(Response.class, "getHeaders");
|
||||||
|
|
||||||
|
|
||||||
public JettyHttpHandlerAdapter(HttpHandler httpHandler) {
|
public JettyHttpHandlerAdapter(HttpHandler httpHandler) {
|
||||||
super(httpHandler);
|
super(httpHandler);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +105,13 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
|
|
||||||
private static MultiValueMap<String, String> createHeaders(HttpServletRequest servletRequest) {
|
private static MultiValueMap<String, String> createHeaders(HttpServletRequest servletRequest) {
|
||||||
Request request = getRequest(servletRequest);
|
Request request = getRequest(servletRequest);
|
||||||
HttpFields.Mutable fields = HttpFields.build(request.getHttpFields());
|
HttpFields fields;
|
||||||
|
if (getRequestHeadersMethod != null) {
|
||||||
|
fields = (HttpFields) ReflectionUtils.invokeMethod(getRequestHeadersMethod, request);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fields = request.getHttpFields();
|
||||||
|
}
|
||||||
return new JettyHeadersAdapter(fields);
|
return new JettyHeadersAdapter(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +142,13 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
|
|
||||||
private static HttpHeaders createHeaders(HttpServletResponse servletResponse) {
|
private static HttpHeaders createHeaders(HttpServletResponse servletResponse) {
|
||||||
Response response = getResponse(servletResponse);
|
Response response = getResponse(servletResponse);
|
||||||
HttpFields.Mutable fields = response.getHttpFields();
|
HttpFields fields;
|
||||||
|
if (getResponseHeadersMethod != null) {
|
||||||
|
fields = (HttpFields) ReflectionUtils.invokeMethod(getResponseHeadersMethod, response);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fields = response.getHttpFields();
|
||||||
|
}
|
||||||
return new HttpHeaders(new JettyHeadersAdapter(fields));
|
return new HttpHeaders(new JettyHeadersAdapter(fields));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,16 +168,32 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException {
|
protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException {
|
||||||
ByteBuffer input = dataBuffer.toByteBuffer();
|
OutputStream output = getOutputStream();
|
||||||
int len = input.remaining();
|
if (jetty11Present) {
|
||||||
ServletResponse response = getNativeResponse();
|
if (output instanceof HttpOutput httpOutput) {
|
||||||
((HttpOutput) response.getOutputStream()).write(input);
|
ByteBuffer input = dataBuffer.toByteBuffer();
|
||||||
return len;
|
int len = input.remaining();
|
||||||
|
httpOutput.write(input);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Jetty 12: see spring-web.gradle
|
||||||
|
else if (jetty12Present) {
|
||||||
|
if (output instanceof org.eclipse.jetty.ee10.servlet.HttpOutput httpOutput) {
|
||||||
|
ByteBuffer input = dataBuffer.toByteBuffer();
|
||||||
|
int len = input.remaining();
|
||||||
|
httpOutput.write(input);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return super.writeToOutputStream(dataBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyHeaders() {
|
protected void applyHeaders() {
|
||||||
HttpServletResponse response = getNativeResponse();
|
HttpServletResponse response = getNativeResponse();
|
||||||
|
|
||||||
MediaType contentType = null;
|
MediaType contentType = null;
|
||||||
try {
|
try {
|
||||||
contentType = getHeaders().getContentType();
|
contentType = getHeaders().getContentType();
|
||||||
|
@ -156,10 +205,12 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
if (response.getContentType() == null && contentType != null) {
|
if (response.getContentType() == null && contentType != null) {
|
||||||
response.setContentType(contentType.toString());
|
response.setContentType(contentType.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
Charset charset = (contentType != null ? contentType.getCharset() : null);
|
Charset charset = (contentType != null ? contentType.getCharset() : null);
|
||||||
if (response.getCharacterEncoding() == null && charset != null) {
|
if (response.getCharacterEncoding() == null && charset != null) {
|
||||||
response.setCharacterEncoding(charset.name());
|
response.setCharacterEncoding(charset.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
long contentLength = getHeaders().getContentLength();
|
long contentLength = getHeaders().getContentLength();
|
||||||
if (contentLength != -1) {
|
if (contentLength != -1) {
|
||||||
response.setContentLengthLong(contentLength);
|
response.setContentLengthLong(contentLength);
|
||||||
|
|
|
@ -56,6 +56,7 @@ import org.springframework.util.StringUtils;
|
||||||
* Adapt {@link ServerHttpRequest} to the Servlet {@link HttpServletRequest}.
|
* Adapt {@link ServerHttpRequest} to the Servlet {@link HttpServletRequest}.
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
|
@ -65,6 +66,8 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
|
|
||||||
private final HttpServletRequest request;
|
private final HttpServletRequest request;
|
||||||
|
|
||||||
|
private final ServletInputStream inputStream;
|
||||||
|
|
||||||
private final RequestBodyPublisher bodyPublisher;
|
private final RequestBodyPublisher bodyPublisher;
|
||||||
|
|
||||||
private final Object cookieLock = new Object();
|
private final Object cookieLock = new Object();
|
||||||
|
@ -99,8 +102,8 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
this.asyncListener = new RequestAsyncListener();
|
this.asyncListener = new RequestAsyncListener();
|
||||||
|
|
||||||
// Tomcat expects ReadListener registration on initial thread
|
// Tomcat expects ReadListener registration on initial thread
|
||||||
ServletInputStream inputStream = request.getInputStream();
|
this.inputStream = request.getInputStream();
|
||||||
this.bodyPublisher = new RequestBodyPublisher(inputStream);
|
this.bodyPublisher = new RequestBodyPublisher(this.inputStream);
|
||||||
this.bodyPublisher.registerReadListener();
|
this.bodyPublisher.registerReadListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +234,13 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
return this.asyncListener;
|
return this.asyncListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link ServletInputStream} for the current response.
|
||||||
|
*/
|
||||||
|
protected final ServletInputStream getInputStream() {
|
||||||
|
return this.inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read from the request body InputStream and return a DataBuffer.
|
* Read from the request body InputStream and return a DataBuffer.
|
||||||
* Invoked only when {@link ServletInputStream#isReady()} returns "true".
|
* Invoked only when {@link ServletInputStream#isReady()} returns "true".
|
||||||
|
@ -239,7 +249,7 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
* or {@link #EOF_BUFFER} if the input stream returned -1.
|
* or {@link #EOF_BUFFER} if the input stream returned -1.
|
||||||
*/
|
*/
|
||||||
DataBuffer readFromInputStream() throws IOException {
|
DataBuffer readFromInputStream() throws IOException {
|
||||||
int read = this.request.getInputStream().read(this.buffer);
|
int read = this.inputStream.read(this.buffer);
|
||||||
logBytesRead(read);
|
logBytesRead(read);
|
||||||
|
|
||||||
if (read > 0) {
|
if (read > 0) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2021 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -44,6 +44,7 @@ import org.springframework.util.Assert;
|
||||||
* Adapt {@link ServerHttpResponse} to the Servlet {@link HttpServletResponse}.
|
* Adapt {@link ServerHttpResponse} to the Servlet {@link HttpServletResponse}.
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
||||||
|
@ -185,6 +186,13 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
|
||||||
return processor;
|
return processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link ServletOutputStream} for the current response.
|
||||||
|
*/
|
||||||
|
protected final ServletOutputStream getOutputStream() {
|
||||||
|
return this.outputStream;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the DataBuffer to the response body OutputStream.
|
* Write the DataBuffer to the response body OutputStream.
|
||||||
* Invoked only when {@link ServletOutputStream#isReady()} returns "true"
|
* Invoked only when {@link ServletOutputStream#isReady()} returns "true"
|
||||||
|
|
|
@ -23,9 +23,6 @@ import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import jakarta.servlet.AsyncContext;
|
import jakarta.servlet.AsyncContext;
|
||||||
import jakarta.servlet.ServletInputStream;
|
|
||||||
import jakarta.servlet.ServletRequest;
|
|
||||||
import jakarta.servlet.ServletResponse;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
@ -57,7 +54,6 @@ import org.springframework.util.ReflectionUtils;
|
||||||
*/
|
*/
|
||||||
public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
|
|
||||||
|
|
||||||
public TomcatHttpHandlerAdapter(HttpHandler httpHandler) {
|
public TomcatHttpHandlerAdapter(HttpHandler httpHandler) {
|
||||||
super(httpHandler);
|
super(httpHandler);
|
||||||
}
|
}
|
||||||
|
@ -130,11 +126,11 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DataBuffer readFromInputStream() throws IOException {
|
protected DataBuffer readFromInputStream() throws IOException {
|
||||||
ServletInputStream inputStream = ((ServletRequest) getNativeRequest()).getInputStream();
|
if (!(getInputStream() instanceof CoyoteInputStream coyoteInputStream)) {
|
||||||
if (!(inputStream instanceof CoyoteInputStream coyoteInputStream)) {
|
|
||||||
// It's possible InputStream can be wrapped, preventing use of CoyoteInputStream
|
// It's possible InputStream can be wrapped, preventing use of CoyoteInputStream
|
||||||
return super.readFromInputStream();
|
return super.readFromInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer byteBuffer = this.factory.isDirect() ?
|
ByteBuffer byteBuffer = this.factory.isDirect() ?
|
||||||
ByteBuffer.allocateDirect(this.bufferSize) :
|
ByteBuffer.allocateDirect(this.bufferSize) :
|
||||||
ByteBuffer.allocate(this.bufferSize);
|
ByteBuffer.allocate(this.bufferSize);
|
||||||
|
@ -198,6 +194,7 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
@Override
|
@Override
|
||||||
protected void applyHeaders() {
|
protected void applyHeaders() {
|
||||||
HttpServletResponse response = getNativeResponse();
|
HttpServletResponse response = getNativeResponse();
|
||||||
|
|
||||||
MediaType contentType = null;
|
MediaType contentType = null;
|
||||||
try {
|
try {
|
||||||
contentType = getHeaders().getContentType();
|
contentType = getHeaders().getContentType();
|
||||||
|
@ -210,10 +207,12 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
response.setContentType(contentType.toString());
|
response.setContentType(contentType.toString());
|
||||||
}
|
}
|
||||||
getHeaders().remove(HttpHeaders.CONTENT_TYPE);
|
getHeaders().remove(HttpHeaders.CONTENT_TYPE);
|
||||||
|
|
||||||
Charset charset = (contentType != null ? contentType.getCharset() : null);
|
Charset charset = (contentType != null ? contentType.getCharset() : null);
|
||||||
if (response.getCharacterEncoding() == null && charset != null) {
|
if (response.getCharacterEncoding() == null && charset != null) {
|
||||||
response.setCharacterEncoding(charset.name());
|
response.setCharacterEncoding(charset.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
long contentLength = getHeaders().getContentLength();
|
long contentLength = getHeaders().getContentLength();
|
||||||
if (contentLength != -1) {
|
if (contentLength != -1) {
|
||||||
response.setContentLengthLong(contentLength);
|
response.setContentLengthLong(contentLength);
|
||||||
|
@ -223,10 +222,13 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException {
|
protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException {
|
||||||
|
if (!(getOutputStream() instanceof CoyoteOutputStream coyoteOutputStream)) {
|
||||||
|
return super.writeToOutputStream(dataBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
ByteBuffer input = dataBuffer.toByteBuffer();
|
ByteBuffer input = dataBuffer.toByteBuffer();
|
||||||
int len = input.remaining();
|
int len = input.remaining();
|
||||||
ServletResponse response = getNativeResponse();
|
coyoteOutputStream.write(input);
|
||||||
((CoyoteOutputStream) response.getOutputStream()).write(input);
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
@ -171,9 +172,9 @@ public class JettyXhrTransport extends AbstractXhrTransport implements Lifecycle
|
||||||
|
|
||||||
private static HttpHeaders toHttpHeaders(HttpFields httpFields) {
|
private static HttpHeaders toHttpHeaders(HttpFields httpFields) {
|
||||||
HttpHeaders responseHeaders = new HttpHeaders();
|
HttpHeaders responseHeaders = new HttpHeaders();
|
||||||
Enumeration<String> names = httpFields.getFieldNames();
|
Iterator<String> names = httpFields.getFieldNamesCollection().iterator();
|
||||||
while (names.hasMoreElements()) {
|
while (names.hasNext()) {
|
||||||
String name = names.nextElement();
|
String name = names.next();
|
||||||
Enumeration<String> values = httpFields.getValues(name);
|
Enumeration<String> values = httpFields.getValues(name);
|
||||||
while (values.hasMoreElements()) {
|
while (values.hasMoreElements()) {
|
||||||
String value = values.nextElement();
|
String value = values.nextElement();
|
||||||
|
|
Loading…
Reference in New Issue