HTTP/2 Sonar Bugs

Motivation:
Clinker provides a Sonar tool which detects potential bugs or problems in the code.  These problems were reported here http://clinker.netty.io/sonar/drilldown/issues/io.netty:netty-parent:master?

Modifications:
Make the recommended changes as reported by Sonar

Result:
Better or more standard code.  Less Sonar problem reports for HTTP/2 codec.
This commit is contained in:
Scott Mitchell 2014-12-10 21:10:26 -05:00
parent 140a32bcb3
commit 2cf4ee9322
13 changed files with 37 additions and 46 deletions

View File

@ -513,14 +513,12 @@ public class DefaultHttp2Connection implements Http2Connection {
notifyParentChanging(child, this); notifyParentChanging(child, this);
child.parent = this; child.parent = this;
if (exclusive) { if (exclusive && !children.isEmpty()) {
// If it was requested that this child be the exclusive dependency of this node, // If it was requested that this child be the exclusive dependency of this node,
// move any previous children to the child node, becoming grand children // move any previous children to the child node, becoming grand children
// of this node. // of this node.
if (!children.isEmpty()) { for (DefaultStream grandchild : removeAllChildren().values()) {
for (DefaultStream grandchild : removeAllChildren().values()) { child.takeChild(grandchild, false, events);
child.takeChild(grandchild, false, events);
}
} }
} }
@ -676,7 +674,7 @@ public class DefaultHttp2Connection implements Http2Connection {
* Stream class representing the connection, itself. * Stream class representing the connection, itself.
*/ */
private final class ConnectionStream extends DefaultStream { private final class ConnectionStream extends DefaultStream {
private ConnectionStream() { ConnectionStream() {
super(CONNECTION_STREAM_ID); super(CONNECTION_STREAM_ID);
} }

View File

@ -403,7 +403,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
// is present in the headers frame. // is present in the headers frame.
if (flags.priorityPresent()) { if (flags.priorityPresent()) {
long word1 = payload.readUnsignedInt(); long word1 = payload.readUnsignedInt();
final boolean exclusive = (word1 & 0x80000000L) > 0; final boolean exclusive = (word1 & 0x80000000L) != 0;
final int streamDependency = (int) (word1 & 0x7FFFFFFFL); final int streamDependency = (int) (word1 & 0x7FFFFFFFL);
final short weight = (short) (payload.readUnsignedByte() + 1); final short weight = (short) (payload.readUnsignedByte() + 1);
final ByteBuf fragment = payload.readSlice(payload.readableBytes() - padding); final ByteBuf fragment = payload.readSlice(payload.readableBytes() - padding);
@ -462,7 +462,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
private void readPriorityFrame(ChannelHandlerContext ctx, ByteBuf payload, private void readPriorityFrame(ChannelHandlerContext ctx, ByteBuf payload,
Http2FrameListener listener) throws Http2Exception { Http2FrameListener listener) throws Http2Exception {
long word1 = payload.readUnsignedInt(); long word1 = payload.readUnsignedInt();
boolean exclusive = (word1 & 0x80000000L) > 0; boolean exclusive = (word1 & 0x80000000L) != 0;
int streamDependency = (int) (word1 & 0x7FFFFFFFL); int streamDependency = (int) (word1 & 0x7FFFFFFFL);
short weight = (short) (payload.readUnsignedByte() + 1); short weight = (short) (payload.readUnsignedByte() + 1);
listener.onPriorityRead(ctx, streamId, streamDependency, weight, exclusive); listener.onPriorityRead(ctx, streamId, streamDependency, weight, exclusive);

View File

@ -79,17 +79,19 @@ public class DefaultHttp2HeadersDecoder implements Http2HeadersDecoder, Http2Hea
return headers; return headers;
} catch (IOException e) { } catch (IOException e) {
throw new Http2Exception(COMPRESSION_ERROR, e.getMessage()); throw connectionError(COMPRESSION_ERROR, e, e.getMessage());
} catch (Http2Exception e) {
throw e;
} catch (Throwable e) { } catch (Throwable e) {
// Default handler for any other types of errors that may have occurred. For example, // Default handler for any other types of errors that may have occurred. For example,
// the the Header builder throws IllegalArgumentException if the key or value was invalid // the the Header builder throws IllegalArgumentException if the key or value was invalid
// for any reason (e.g. the key was an invalid pseudo-header). // for any reason (e.g. the key was an invalid pseudo-header).
throw new Http2Exception(PROTOCOL_ERROR, e.getMessage(), e); throw connectionError(PROTOCOL_ERROR, e, e.getMessage());
} finally { } finally {
try { try {
in.close(); in.close();
} catch (IOException e) { } catch (IOException e) {
throw new Http2Exception(INTERNAL_ERROR, e.getMessage(), e); throw connectionError(INTERNAL_ERROR, e, e.getMessage());
} }
} }
} }

View File

@ -87,14 +87,15 @@ public class DefaultHttp2HeadersEncoder implements Http2HeadersEncoder, Http2Hea
return true; return true;
} }
}); });
} catch (Exception e) { } catch (Http2Exception e) {
throw connectionError(COMPRESSION_ERROR, "Failed encoding headers block: %s", throw e;
e.getMessage()); } catch (Throwable t) {
throw connectionError(COMPRESSION_ERROR, t, "Failed encoding headers block: %s", t.getMessage());
} finally { } finally {
try { try {
stream.close(); stream.close();
} catch (IOException e) { } catch (IOException e) {
throw new Http2Exception(INTERNAL_ERROR, e.getMessage(), e); throw connectionError(INTERNAL_ERROR, e, e.getMessage());
} }
} }
} }

View File

@ -361,7 +361,7 @@ public class DefaultHttp2RemoteFlowController implements Http2RemoteFlowControll
private int allocated; private int allocated;
private ChannelFuture lastNewFrame; private ChannelFuture lastNewFrame;
private FlowState(Http2Stream stream) { FlowState(Http2Stream stream) {
this.stream = stream; this.stream = stream;
pendingWriteQueue = new ArrayDeque<Frame>(2); pendingWriteQueue = new ArrayDeque<Frame>(2);
} }
@ -590,9 +590,8 @@ public class DefaultHttp2RemoteFlowController implements Http2RemoteFlowControll
try { try {
connectionState().incrementStreamWindow(-bytesToWrite); connectionState().incrementStreamWindow(-bytesToWrite);
incrementStreamWindow(-bytesToWrite); incrementStreamWindow(-bytesToWrite);
} catch (Http2Exception e) { } catch (Http2Exception e) { // Should never get here since we're decrementing.
// Should never get here since we're decrementing. throw new RuntimeException("Invalid window state when writing frame: " + e.getMessage(), e);
throw new AssertionError("Invalid window state when writing frame: " + e.getMessage());
} }
frameWriter.writeData(ctx, stream.id(), data, padding, endStream, promise); frameWriter.writeData(ctx, stream.id(), data, padding, endStream, promise);
frameSent = true; frameSent = true;
@ -662,7 +661,7 @@ public class DefaultHttp2RemoteFlowController implements Http2RemoteFlowControll
/** /**
* Lightweight promise aggregator. * Lightweight promise aggregator.
*/ */
private class SimplePromiseAggregator { private static final class SimplePromiseAggregator {
final ChannelPromise promise; final ChannelPromise promise;
final AtomicInteger awaiting = new AtomicInteger(); final AtomicInteger awaiting = new AtomicInteger();
final ChannelFutureListener listener = new ChannelFutureListener() { final ChannelFutureListener listener = new ChannelFutureListener() {

View File

@ -118,9 +118,7 @@ public class DelegatingDecompressorFrameListener extends Http2FrameListenerDecor
buf = nextBuf; buf = nextBuf;
} }
} finally { } finally {
if (buf != null) { buf.release();
buf.release();
}
} }
} }
decompressor.incrementProcessedBytes(processedBytes); decompressor.incrementProcessedBytes(processedBytes);
@ -290,7 +288,7 @@ public class DelegatingDecompressorFrameListener extends Http2FrameListenerDecor
/** /**
* A decorator around the local flow controller that converts consumed bytes from uncompressed to compressed. * A decorator around the local flow controller that converts consumed bytes from uncompressed to compressed.
*/ */
private final class ConsumedBytesConverter implements Http2LocalFlowController { private static final class ConsumedBytesConverter implements Http2LocalFlowController {
private final Http2LocalFlowController flowController; private final Http2LocalFlowController flowController;
ConsumedBytesConverter(Http2LocalFlowController flowController) { ConsumedBytesConverter(Http2LocalFlowController flowController) {

View File

@ -19,8 +19,6 @@ import static io.netty.util.CharsetUtil.UTF_8;
import static io.netty.util.internal.ObjectUtil.checkNotNull; import static io.netty.util.internal.ObjectUtil.checkNotNull;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http2.Http2StreamRemovalPolicy.Action; import io.netty.handler.codec.http2.Http2StreamRemovalPolicy.Action;

View File

@ -373,7 +373,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
try { try {
// Read the remaining of the client preface string if we haven't already. // Read the remaining of the client preface string if we haven't already.
// If this is a client endpoint, always returns true. // If this is a client endpoint, always returns true.
if (!readClientPrefaceString(ctx, in)) { if (!readClientPrefaceString(in)) {
// Still processing the client preface. // Still processing the client preface.
return; return;
} }
@ -422,7 +422,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
* @return {@code true} if processing of the client preface string is complete. Since client preface strings can * @return {@code true} if processing of the client preface string is complete. Since client preface strings can
* only be received by servers, returns true immediately for client endpoints. * only be received by servers, returns true immediately for client endpoints.
*/ */
private boolean readClientPrefaceString(ChannelHandlerContext ctx, ByteBuf in) throws Http2Exception { private boolean readClientPrefaceString(ByteBuf in) throws Http2Exception {
if (clientPrefaceString == null) { if (clientPrefaceString == null) {
return true; return true;
} }

View File

@ -137,21 +137,16 @@ public class Http2Exception extends Exception {
private static final long serialVersionUID = 462766352505067095L; private static final long serialVersionUID = 462766352505067095L;
private final int streamId; private final int streamId;
private StreamException(int streamId, Http2Error error, String message) { StreamException(int streamId, Http2Error error, String message) {
super(error, message); super(error, message);
this.streamId = streamId; this.streamId = streamId;
} }
private StreamException(int streamId, Http2Error error, String message, Throwable cause) { StreamException(int streamId, Http2Error error, String message, Throwable cause) {
super(error, message, cause); super(error, message, cause);
this.streamId = streamId; this.streamId = streamId;
} }
private StreamException(int streamId, Http2Error error) {
super(error);
this.streamId = streamId;
}
public int streamId() { public int streamId() {
return streamId; return streamId;
} }

View File

@ -47,7 +47,6 @@ public class Http2ServerUpgradeCodec implements HttpServerUpgradeHandler.Upgrade
private final String handlerName; private final String handlerName;
private final Http2ConnectionHandler connectionHandler; private final Http2ConnectionHandler connectionHandler;
private final Http2FrameReader frameReader; private final Http2FrameReader frameReader;
private Http2Settings settings;
/** /**
* Creates the codec using a default name for the connection handler when adding to the * Creates the codec using a default name for the connection handler when adding to the
@ -92,7 +91,7 @@ public class Http2ServerUpgradeCodec implements HttpServerUpgradeHandler.Upgrade
throw new IllegalArgumentException("There must be 1 and only 1 " throw new IllegalArgumentException("There must be 1 and only 1 "
+ HTTP_UPGRADE_SETTINGS_HEADER + " header."); + HTTP_UPGRADE_SETTINGS_HEADER + " header.");
} }
settings = decodeSettingsHeader(ctx, upgradeHeaders.get(0)); Http2Settings settings = decodeSettingsHeader(ctx, upgradeHeaders.get(0));
connectionHandler.onHttpServerUpgrade(settings); connectionHandler.onHttpServerUpgrade(settings);
// Everything looks good, no need to modify the response. // Everything looks good, no need to modify the response.
} catch (Throwable e) { } catch (Throwable e) {

View File

@ -175,8 +175,8 @@ public final class HttpUtil {
} }
} catch (Http2Exception e) { } catch (Http2Exception e) {
throw e; throw e;
} catch (Exception ignored) { } catch (Throwable t) {
throw connectionError(PROTOCOL_ERROR, throw connectionError(PROTOCOL_ERROR, t,
"Unrecognized HTTP status code '%s' encountered in translation to HTTP/1.x", status); "Unrecognized HTTP status code '%s' encountered in translation to HTTP/1.x", status);
} }
return result; return result;

View File

@ -62,7 +62,7 @@ public final class InboundHttp2ToHttpPriorityAdapter extends InboundHttp2ToHttpA
} }
} }
private InboundHttp2ToHttpPriorityAdapter(Builder builder) { InboundHttp2ToHttpPriorityAdapter(Builder builder) {
super(builder); super(builder);
outOfMessageFlowHeaders = new IntObjectHashMap<HttpHeaders>(); outOfMessageFlowHeaders = new IntObjectHashMap<HttpHeaders>();
} }

View File

@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertSame;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyShort; import static org.mockito.Matchers.anyShort;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
@ -532,15 +533,15 @@ public class DefaultHttp2ConnectionTest {
} }
private void verifyParentChanging(List<Http2Stream> expectedArg1, List<Http2Stream> expectedArg2) { private void verifyParentChanging(List<Http2Stream> expectedArg1, List<Http2Stream> expectedArg2) {
assertTrue(expectedArg1.size() == expectedArg2.size()); assertSame(expectedArg1.size(), expectedArg2.size());
ArgumentCaptor<Http2Stream> arg1Captor = ArgumentCaptor.forClass(Http2Stream.class); ArgumentCaptor<Http2Stream> arg1Captor = ArgumentCaptor.forClass(Http2Stream.class);
ArgumentCaptor<Http2Stream> arg2Captor = ArgumentCaptor.forClass(Http2Stream.class); ArgumentCaptor<Http2Stream> arg2Captor = ArgumentCaptor.forClass(Http2Stream.class);
verify(clientListener, times(expectedArg1.size())).priorityTreeParentChanging(arg1Captor.capture(), verify(clientListener, times(expectedArg1.size())).priorityTreeParentChanging(arg1Captor.capture(),
arg2Captor.capture()); arg2Captor.capture());
List<Http2Stream> capturedArg1 = arg1Captor.getAllValues(); List<Http2Stream> capturedArg1 = arg1Captor.getAllValues();
List<Http2Stream> capturedArg2 = arg2Captor.getAllValues(); List<Http2Stream> capturedArg2 = arg2Captor.getAllValues();
assertTrue(capturedArg1.size() == capturedArg2.size()); assertSame(capturedArg1.size(), capturedArg2.size());
assertTrue(capturedArg1.size() == expectedArg1.size()); assertSame(capturedArg1.size(), expectedArg1.size());
for (int i = 0; i < capturedArg1.size(); ++i) { for (int i = 0; i < capturedArg1.size(); ++i) {
assertEquals(expectedArg1.get(i), capturedArg1.get(i)); assertEquals(expectedArg1.get(i), capturedArg1.get(i));
assertEquals(expectedArg2.get(i), capturedArg2.get(i)); assertEquals(expectedArg2.get(i), capturedArg2.get(i));
@ -548,15 +549,15 @@ public class DefaultHttp2ConnectionTest {
} }
private void verifyParentsChanged(List<Http2Stream> expectedArg1, List<Http2Stream> expectedArg2) { private void verifyParentsChanged(List<Http2Stream> expectedArg1, List<Http2Stream> expectedArg2) {
assertTrue(expectedArg1.size() == expectedArg2.size()); assertSame(expectedArg1.size(), expectedArg2.size());
ArgumentCaptor<Http2Stream> arg1Captor = ArgumentCaptor.forClass(Http2Stream.class); ArgumentCaptor<Http2Stream> arg1Captor = ArgumentCaptor.forClass(Http2Stream.class);
ArgumentCaptor<Http2Stream> arg2Captor = ArgumentCaptor.forClass(Http2Stream.class); ArgumentCaptor<Http2Stream> arg2Captor = ArgumentCaptor.forClass(Http2Stream.class);
verify(clientListener, times(expectedArg1.size())).priorityTreeParentChanged(arg1Captor.capture(), verify(clientListener, times(expectedArg1.size())).priorityTreeParentChanged(arg1Captor.capture(),
arg2Captor.capture()); arg2Captor.capture());
List<Http2Stream> capturedArg1 = arg1Captor.getAllValues(); List<Http2Stream> capturedArg1 = arg1Captor.getAllValues();
List<Http2Stream> capturedArg2 = arg2Captor.getAllValues(); List<Http2Stream> capturedArg2 = arg2Captor.getAllValues();
assertTrue(capturedArg1.size() == capturedArg2.size()); assertSame(capturedArg1.size(), capturedArg2.size());
assertTrue(capturedArg1.size() == expectedArg1.size()); assertSame(capturedArg1.size(), expectedArg1.size());
for (int i = 0; i < capturedArg1.size(); ++i) { for (int i = 0; i < capturedArg1.size(); ++i) {
assertEquals(expectedArg1.get(i), capturedArg1.get(i)); assertEquals(expectedArg1.get(i), capturedArg1.get(i));
assertEquals(expectedArg2.get(i), capturedArg2.get(i)); assertEquals(expectedArg2.get(i), capturedArg2.get(i));