-
Notifications
You must be signed in to change notification settings - Fork 912
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix delayed notification of session creation failure and log GOAWAY f…
…rames Motivation: When a connection is closed before session protocol negotiation succeeds or fails, the Promise of session creation is not notified immediately but only after the session creation timeout occurs. As a result, the notification of session creation due to an unexpected disconnection can take up to as long as connection timeout (3.2 seconds by default) Also, we need to log more: - the information about GOAWAY frames we sent and received - the current session protocol when an unexpected exception occurred Modifications: - Try to reject the session creation promise when a connection has been closed. - Add Http2GoAwayListener and add it to both client and server connections so that we have more information about GOAWAY frames we send and receive. - Log the current session protocol when logging an unexpected exception - Log the pre-upgrade request and the removal of the upgrade stream to see if there's a case where the upgrade stream is removed before sending the first response - Miscellaneous: - Do not propagate IdleStateEvent in Http*IdleTimeoutHandler. Result: - Session creation failure is notified much sooner in the situation described above. - We will have more information about GOAWAY frames and unexpected behaviors related with session protocol negotiation
- Loading branch information
Showing
8 changed files
with
172 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
src/main/java/com/linecorp/armeria/common/http/Http2GoAwayListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* Copyright 2016 LINE Corporation | ||
* | ||
* LINE Corporation licenses this file to you under the Apache License, | ||
* version 2.0 (the "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at: | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
package com.linecorp.armeria.common.http; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import io.netty.buffer.ByteBuf; | ||
import io.netty.buffer.ByteBufUtil; | ||
import io.netty.channel.Channel; | ||
import io.netty.handler.codec.http2.Http2Connection; | ||
import io.netty.handler.codec.http2.Http2ConnectionAdapter; | ||
import io.netty.handler.codec.http2.Http2Error; | ||
import io.netty.handler.codec.http2.Http2Stream; | ||
|
||
/** | ||
* A {@link Http2Connection.Listener} that logs the received GOAWAY frames and makes sure disconnection. | ||
*/ | ||
public class Http2GoAwayListener extends Http2ConnectionAdapter { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(Http2GoAwayListener.class); | ||
|
||
private final Channel ch; | ||
private boolean goAwaySent; | ||
|
||
public Http2GoAwayListener(Channel ch) { | ||
this.ch = ch; | ||
} | ||
|
||
@Override | ||
public void onGoAwaySent(int lastStreamId, long errorCode, ByteBuf debugData) { | ||
goAwaySent = true; | ||
onGoAway("Sent", lastStreamId, errorCode, debugData); | ||
} | ||
|
||
@Override | ||
public void onGoAwayReceived(int lastStreamId, long errorCode, ByteBuf debugData) { | ||
onGoAway("Received", lastStreamId, errorCode, debugData); | ||
|
||
// Send a GOAWAY back to the peer and close the connection gracefully if we did not send GOAWAY yet. | ||
// This will make sure that the connection is always closed after receiving GOAWAY, | ||
// because otherwise we have to wait until the peer who sent GOAWAY to us closes the connection. | ||
if (!goAwaySent) { | ||
ch.close(); | ||
} | ||
} | ||
|
||
private void onGoAway(String sentOrReceived, int lastStreamId, long errorCode, ByteBuf debugData) { | ||
if (errorCode != Http2Error.NO_ERROR.code()) { | ||
if (logger.isWarnEnabled()) { | ||
logger.warn("{} {} a GOAWAY frame: lastStreamId={}, errorCode={}, debugData=\"{}\" (Hex: {})", | ||
ch, sentOrReceived, lastStreamId, errorStr(errorCode), | ||
debugData.toString(StandardCharsets.UTF_8), | ||
ByteBufUtil.hexDump(debugData)); | ||
} | ||
} else { | ||
if (logger.isInfoEnabled()) { | ||
logger.debug("{} {} a GOAWAY frame: lastStreamId={}, errorCode=NO_ERROR", | ||
ch, sentOrReceived, lastStreamId); | ||
} | ||
} | ||
} | ||
|
||
private static String errorStr(long errorCode) { | ||
final Http2Error error = Http2Error.valueOf(errorCode); | ||
return error != null ? error.toString() + '(' + errorCode + ')' | ||
: "UNKNOWN(" + errorCode + ')'; | ||
} | ||
|
||
@Override | ||
public void onStreamRemoved(Http2Stream stream) { | ||
if (stream.id() == 1) { | ||
logger.debug("{} HTTP/2 upgrade stream removed: {}", ch, stream.state()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.