Skip to content

Commit 8464d89

Browse files
rschmittok2c
authored andcommitted
Adds StaleCheckCommand
The `StaleCheckCommand`, like all `Command`s, is modeled as a write operation, and `InternalDataChannel::onIOEvent` processesreads before writes. Therefore, by the time the stale check command is processed, the client's view of the connectio is already up-to-date; any server-initiated connection closure (FIN, RST, GOAWAY) has already been read and processed.
1 parent 49ae683 commit 8464d89

File tree

4 files changed

+98
-7
lines changed

4 files changed

+98
-7
lines changed

httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import javax.net.ssl.SSLSession;
4747

4848
import org.apache.hc.core5.concurrent.CancellableDependency;
49+
import org.apache.hc.core5.concurrent.FutureCallback;
4950
import org.apache.hc.core5.http.ConnectionClosedException;
5051
import org.apache.hc.core5.http.EndpointDetails;
5152
import org.apache.hc.core5.http.Header;
@@ -65,6 +66,7 @@
6566
import org.apache.hc.core5.http.nio.HandlerFactory;
6667
import org.apache.hc.core5.http.nio.command.ExecutableCommand;
6768
import org.apache.hc.core5.http.nio.command.ShutdownCommand;
69+
import org.apache.hc.core5.http.nio.command.StaleCheckCommand;
6870
import org.apache.hc.core5.http.protocol.HttpCoreContext;
6971
import org.apache.hc.core5.http.protocol.HttpProcessor;
7072
import org.apache.hc.core5.http2.H2ConnectionException;
@@ -410,6 +412,11 @@ private int generateStreamId() {
410412
}
411413
}
412414

415+
void doStalecheck(final FutureCallback<Boolean> callback) throws IOException {
416+
callback.completed(
417+
ioSession.isOpen() && connState.compareTo(ConnectionHandshake.ACTIVE) == 0);
418+
}
419+
413420
public final void onConnect() throws HttpException, IOException {
414421
connState = ConnectionHandshake.ACTIVE;
415422
final RawFrame settingsFrame = frameFactory.createSettings(
@@ -647,6 +654,8 @@ private void processPendingCommands() throws IOException, HttpException {
647654
if (!outputQueue.isEmpty()) {
648655
return;
649656
}
657+
} else if (command instanceof StaleCheckCommand) {
658+
doStalecheck(((StaleCheckCommand) command).getCallback());
650659
}
651660
}
652661
}

httpcore5-h2/src/main/java/org/apache/hc/core5/http2/nio/pool/H2ConnPool.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@
3939
import org.apache.hc.core5.http.URIScheme;
4040
import org.apache.hc.core5.http.impl.DefaultAddressResolver;
4141
import org.apache.hc.core5.http.nio.command.ShutdownCommand;
42+
import org.apache.hc.core5.http.nio.command.StaleCheckCommand;
4243
import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
43-
import org.apache.hc.core5.http2.nio.command.PingCommand;
44-
import org.apache.hc.core5.http2.nio.support.BasicPingHandler;
4544
import org.apache.hc.core5.io.CloseMode;
4645
import org.apache.hc.core5.reactor.AbstractIOSessionPool;
4746
import org.apache.hc.core5.reactor.Command;
@@ -146,11 +145,24 @@ protected void validateSession(
146145
final long lastAccessTime = Math.min(ioSession.getLastReadTime(), ioSession.getLastWriteTime());
147146
final long deadline = lastAccessTime + timeValue.toMilliseconds();
148147
if (deadline <= System.currentTimeMillis()) {
149-
final Timeout socketTimeoutMillis = ioSession.getSocketTimeout();
150-
ioSession.enqueue(new PingCommand(new BasicPingHandler(result -> {
151-
ioSession.setSocketTimeout(socketTimeoutMillis);
152-
callback.execute(result);
153-
})), Command.Priority.NORMAL);
148+
ioSession.enqueue(new StaleCheckCommand(new FutureCallback<Boolean>() {
149+
150+
@Override
151+
public void completed(final Boolean result) {
152+
callback.execute(result);
153+
}
154+
155+
@Override
156+
public void failed(final Exception ex) {
157+
callback.execute(false);
158+
}
159+
160+
@Override
161+
public void cancelled() {
162+
callback.execute(false);
163+
}
164+
165+
}), Command.Priority.NORMAL);
154166
return;
155167
}
156168
}

httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import javax.net.ssl.SSLHandshakeException;
4141
import javax.net.ssl.SSLSession;
4242

43+
import org.apache.hc.core5.concurrent.FutureCallback;
4344
import org.apache.hc.core5.http.ConnectionClosedException;
4445
import org.apache.hc.core5.http.ContentLengthStrategy;
4546
import org.apache.hc.core5.http.EndpointDetails;
@@ -68,6 +69,7 @@
6869
import org.apache.hc.core5.http.nio.command.CommandSupport;
6970
import org.apache.hc.core5.http.nio.command.RequestExecutionCommand;
7071
import org.apache.hc.core5.http.nio.command.ShutdownCommand;
72+
import org.apache.hc.core5.http.nio.command.StaleCheckCommand;
7173
import org.apache.hc.core5.io.CloseMode;
7274
import org.apache.hc.core5.io.SocketTimeoutExceptionFactory;
7375
import org.apache.hc.core5.reactor.Command;
@@ -244,6 +246,8 @@ private void processCommands() throws HttpException, IOException {
244246
execute((RequestExecutionCommand) command);
245247
return;
246248
}
249+
} else if (command instanceof StaleCheckCommand) {
250+
doStalecheck(((StaleCheckCommand) command).getCallback());
247251
} else {
248252
throw new HttpException("Unexpected command: " + command.getClass());
249253
}
@@ -429,6 +433,11 @@ void requestShutdown(final CloseMode closeMode) {
429433
ioSession.setEvent(SelectionKey.OP_WRITE);
430434
}
431435

436+
void doStalecheck(final FutureCallback<Boolean> callback) throws IOException {
437+
callback.completed(
438+
ioSession.isOpen() && connState.compareTo(ConnectionState.ACTIVE) == 0);
439+
}
440+
432441
void commitMessageHead(
433442
final OutgoingMessage messageHead,
434443
final boolean endStream,
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* ====================================================================
3+
* Licensed to the Apache Software Foundation (ASF) under one
4+
* or more contributor license agreements. See the NOTICE file
5+
* distributed with this work for additional information
6+
* regarding copyright ownership. The ASF licenses this file
7+
* to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance
9+
* with the License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing,
14+
* software distributed under the License is distributed on an
15+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
* KIND, either express or implied. See the License for the
17+
* specific language governing permissions and limitations
18+
* under the License.
19+
* ====================================================================
20+
*
21+
* This software consists of voluntary contributions made by many
22+
* individuals on behalf of the Apache Software Foundation. For more
23+
* information on the Apache Software Foundation, please see
24+
* <http://www.apache.org/>.
25+
*
26+
*/
27+
28+
package org.apache.hc.core5.http.nio.command;
29+
30+
import org.apache.hc.core5.annotation.Internal;
31+
import org.apache.hc.core5.concurrent.FutureCallback;
32+
import org.apache.hc.core5.reactor.Command;
33+
import org.apache.hc.core5.util.Args;
34+
35+
/**
36+
* Stale check command. The {@code callback} will be invoked after the client's event loop has finished processing
37+
* all pending reads on the connection. If the connection is still active at that point, the callback will be completed
38+
* with {@code true}. In any other event, the callback will be cancelled, failed, or completed with {@code false}.
39+
*
40+
* @since 5.4
41+
*/
42+
@Internal
43+
public final class StaleCheckCommand implements Command {
44+
45+
private final FutureCallback<Boolean> callback;
46+
47+
public StaleCheckCommand(final FutureCallback<Boolean> callback) {
48+
this.callback = Args.notNull(callback, "Callback");
49+
}
50+
51+
public FutureCallback<Boolean> getCallback() {
52+
return callback;
53+
}
54+
55+
@Override
56+
public boolean cancel() {
57+
callback.cancelled();
58+
return true;
59+
}
60+
61+
}

0 commit comments

Comments
 (0)