Skip to content

Commit

Permalink
Merge remote-tracking branch 3.1 into 4.0
Browse files Browse the repository at this point in the history
Signed-off-by: jansupol <jan.supol@oracle.com>
  • Loading branch information
jansupol committed Mar 21, 2024
2 parents 4e597a7 + 9b9e494 commit 41f52e6
Show file tree
Hide file tree
Showing 44 changed files with 1,022 additions and 337 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -32,8 +32,10 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -531,7 +533,7 @@ public ClientResponse apply(final ClientRequest clientRequest) throws Processing

try {
final ConnectionClosingMechanism closingMechanism = new ConnectionClosingMechanism(clientRequest, request);
responseContext.setEntityStream(getInputStream(response, closingMechanism));
responseContext.setEntityStream(getInputStream(response, closingMechanism, () -> clientRequest.isCancelled()));
} catch (final IOException e) {
LOGGER.log(Level.SEVERE, null, e);
}
Expand Down Expand Up @@ -741,13 +743,14 @@ private static Map<String, String> writeOutBoundHeaders(final ClientRequest clie
}

private static InputStream getInputStream(final CloseableHttpResponse response,
final ConnectionClosingMechanism closingMechanism) throws IOException {
final ConnectionClosingMechanism closingMechanism,
final Supplier<Boolean> isCancelled) throws IOException {
final InputStream inputStream;

if (response.getEntity() == null) {
inputStream = new ByteArrayInputStream(new byte[0]);
} else {
final InputStream i = response.getEntity().getContent();
final InputStream i = new CancellableInputStream(response.getEntity().getContent(), isCancelled);
if (i.markSupported()) {
inputStream = i;
} else {
Expand Down Expand Up @@ -889,4 +892,69 @@ protected void prepareSocket(SSLSocket socket) throws IOException {
}
}
}

private static class CancellableInputStream extends InputStream {
private final InputStream in;
private final Supplier<Boolean> isCancelled;

private CancellableInputStream(InputStream in, Supplier<Boolean> isCancelled) {
this.in = in;
this.isCancelled = isCancelled;
}

public int read(byte b[]) throws IOException {
checkAborted();
return in.read();
}

public int read(byte b[], int off, int len) throws IOException {
checkAborted();
return in.read(b, off, len);
}

@Override
public int read() throws IOException {
checkAborted();
return in.read();
}

public boolean markSupported() {
return in.markSupported();
}

@Override
public long skip(long n) throws IOException {
checkAborted();
return in.skip(n);
}

@Override
public int available() throws IOException {
checkAborted();
return in.available();
}

@Override
public void close() throws IOException {
in.close();
}

@Override
public synchronized void mark(int readlimit) {
in.mark(readlimit);
}

@Override
public synchronized void reset() throws IOException {
checkAborted();
in.reset();
}

private void checkAborted() throws IOException {
if (isCancelled.get()) {
throw new IOException(new CancellationException());
}
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -360,48 +360,55 @@ private FirstByteCachingStream(InputStream inner) {
@Override
public int read() throws IOException {
lock.lock();
final int r = zero != -1 ? zero : inner.read();
zero = -1;
lock.unlock();
return r;
try {
final int r = zero != -1 ? zero : inner.read();
zero = -1;
return r;
} finally {
lock.unlock();
}
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
lock.lock();
int r;
if (zero != -1) {
b[off] = (byte) (zero & 0xFF);
r = inner.read(b, off + 1, len - 1);
} else {
r = inner.read(b, off, len);
try {
if (zero != -1) {
b[off] = (byte) (zero & 0xFF);
r = inner.read(b, off + 1, len - 1);
} else {
r = inner.read(b, off, len);
}
zero = -1;
} finally {
lock.unlock();
}
zero = -1;
lock.unlock();
return r;

}

@Override
public int available() throws IOException {
lock.lock();
if (zero != -1) {
lock.unlock();
return 1;
}
try {
if (zero != -1) {
return 1;
}

int available = inner.available();
if (available != 1) {
lock.unlock();
return available;
}
int available = inner.available();
if (available != 1) {
return available;
}

zero = inner.read();
if (zero == -1) {
available = 0;
zero = inner.read();
if (zero == -1) {
available = 0;
}
return available;
} finally {
lock.unlock();
}
lock.unlock();
return available;
}

@Override
Expand All @@ -418,10 +425,14 @@ public boolean markSupported() {
}

@Override
public synchronized void mark(int readlimit) {
public void mark(int readlimit) {
inner.mark(readlimit);
}

@Override
public void reset() throws IOException {
inner.reset();
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -25,6 +25,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
Expand Down Expand Up @@ -158,6 +159,10 @@ protected void notifyResponse() {

@Override
public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
if (jerseyRequest.isCancelled()) {
responseAvailable.completeExceptionally(new CancellationException());
return;
}
if (msg instanceof HttpResponse) {
final HttpResponse response = (HttpResponse) msg;
jerseyResponse = new ClientResponse(new Response.StatusType() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -294,6 +294,7 @@ protected void service(final HttpServletRequest request, final HttpServletRespon
final URI baseUri;
final URI requestUri;
try {
LOGGER.debugLog("ServletContainer.service(...) started");
baseUri = absoluteUriBuilder.replacePath(encodedBasePath).build();
String queryParameters = ContainerUtils.encodeUnsafeCharacters(request.getQueryString());
if (queryParameters == null) {
Expand Down Expand Up @@ -530,6 +531,7 @@ private void doFilter(final HttpServletRequest request, final HttpServletRespons
final URI baseUri;
final URI requestUri;
try {
LOGGER.debugLog("ServletContainer.doFilter(...) started");
final UriBuilder absoluteUriBuilder = UriBuilder.fromUri(request.getRequestURL().toString());

// depending on circumstances, use the correct path to replace in the absolute request URI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.glassfish.jersey.internal.inject.ReferencingFactory;
import org.glassfish.jersey.internal.util.ExtendedLogger;
import org.glassfish.jersey.internal.util.collection.Ref;
import org.glassfish.jersey.jetty.internal.LocalizationMessages;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ApplicationHandler;
import org.glassfish.jersey.server.ContainerException;
Expand Down Expand Up @@ -137,6 +138,7 @@ public boolean handle(Request request, Response response, Callback callback) thr

final ResponseWriter responseWriter = new ResponseWriter(request, response, callback, configSetStatusOverSendError);
try {
LOGGER.debugLog(LocalizationMessages.CONTAINER_STARTED());
final URI baseUri = getBaseUri(request);
final URI requestUri = getRequestUri(request, baseUri);
final ContainerRequest requestContext = new ContainerRequest(
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#

# {0} - status code; {1} - status reason message
container.started=JettyHttpContainer.handle(...) started.
exception.sending.error.response=I/O exception occurred while sending "{0}/{1}" error response.
error.when.creating.server=Exception thrown when trying to create jetty server.
unable.to.close.response=Unable to close response output.
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -25,6 +25,10 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand Down Expand Up @@ -90,6 +94,8 @@ public class ClientRequest extends OutboundMessageContext
private LazyValue<PropertiesResolver> propertiesResolver = Values.lazy(
(Value<PropertiesResolver>) () -> PropertiesResolver.create(getConfiguration(), getPropertiesDelegate())
);
// by default nothing to be cancelled.
private Future cancellable = NotCancellable.INSTANCE;

private static final Logger LOGGER = Logger.getLogger(ClientRequest.class.getName());

Expand Down Expand Up @@ -126,6 +132,7 @@ public ClientRequest(final ClientRequest original) {
this.writerInterceptors = original.writerInterceptors;
this.propertiesDelegate = new MapPropertiesDelegate(original.propertiesDelegate);
this.ignoreUserAgent = original.ignoreUserAgent;
this.cancellable = original.cancellable;
}

@Override
Expand Down Expand Up @@ -599,4 +606,66 @@ public boolean ignoreUserAgent() {
public void ignoreUserAgent(final boolean ignore) {
this.ignoreUserAgent = ignore;
}

/**
* Sets the new {@code Future} that may cancel this {@link ClientRequest}.
* @param cancellable
*/
void setCancellable(Future cancellable) {
this.cancellable = cancellable;
}

/**
* Cancels this {@link ClientRequest}. May result in {@link java.util.concurrent.CancellationException} later in this
* request processing if this {@link ClientRequest} is backed by a {@link Future} provided to
* {@link JerseyInvocation.Builder#setCancellable(Future)}.
* @param mayInterruptIfRunning may have no effect or {@code true} if the thread executing this task should be interrupted
* (if the thread is known to the implementation);
* otherwise, in-progress tasks are allowed to complete
*/
public void cancel(boolean mayInterruptIfRunning) {
cancellable.cancel(mayInterruptIfRunning);
}

/**
* Returns {@code true} if this {@link ClientRequest} was cancelled
* before it completed normally.
*
* @return {@code true} if this {@link ClientRequest} was cancelled
* before it completed normally
*/
public boolean isCancelled() {
return cancellable.isCancelled();
}

private static class NotCancellable implements Future {
public static final Future INSTANCE = new NotCancellable();
private boolean isCancelled = false;

@Override
public boolean cancel(boolean mayInterruptIfRunning) {
isCancelled = true;
return isCancelled;
}

@Override
public boolean isCancelled() {
return isCancelled;
}

@Override
public boolean isDone() {
return false;
}

@Override
public Object get() throws InterruptedException, ExecutionException {
return null;
}

@Override
public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return null;
}
}
}
Loading

0 comments on commit 41f52e6

Please sign in to comment.