From 64ba5a6ef8558c70ae053a7854891273fe4ea5bf Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Sun, 27 Sep 2015 17:03:29 +0200 Subject: [PATCH] Improved usability of PingFrame. --- .../eclipse/jetty/http2/frames/PingFrame.java | 63 ++++++++++++++++++- .../jetty/http2/generator/PingGenerator.java | 4 +- .../http2/frames/PingGenerateParseTest.java | 33 ++++++++++ 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java index e2a61b9038f..b407e5950c0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java @@ -18,15 +18,49 @@ package org.eclipse.jetty.http2.frames; +import java.util.Objects; + public class PingFrame extends Frame { + public static final int PING_LENGTH = 8; + private static final byte[] EMPTY_PAYLOAD = new byte[8]; + private final byte[] payload; private final boolean reply; + /** + * Creates a PING frame with an empty payload. + * + * @param reply whether this PING frame is a reply + */ + public PingFrame(boolean reply) + { + this(EMPTY_PAYLOAD, reply); + } + + /** + * Creates a PING frame with the given {@code long} {@code value} as payload. + * + * @param value the value to use as a payload for this PING frame + * @param reply whether this PING frame is a reply + */ + public PingFrame(long value, boolean reply) + { + this(toBytes(value), reply); + } + + /** + * Creates a PING frame with the given {@code payload}. + * + * @param payload the payload for this PING frame + * @param reply whether this PING frame is a reply + */ public PingFrame(byte[] payload, boolean reply) { super(FrameType.PING); - this.payload = payload; + this.payload = Objects.requireNonNull(payload); + if (payload.length != PING_LENGTH) + throw new IllegalArgumentException("PING payload must be 8 bytes"); this.reply = reply; } @@ -35,8 +69,35 @@ public class PingFrame extends Frame return payload; } + public long getPayloadAsLong() + { + return toLong(payload); + } + public boolean isReply() { return reply; } + + private static byte[] toBytes(long value) + { + byte[] result = new byte[8]; + for (int i = result.length - 1; i >= 0; --i) + { + result[i] = (byte)(value & 0xFF); + value >>= 8; + } + return result; + } + + private static long toLong(byte[] payload) + { + long result = 0; + for (int i = 0; i < 8; ++i) + { + result <<= 8; + result |= (payload[i] & 0xFF); + } + return result; + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java index 415fd32b907..e5ee775529d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java @@ -43,10 +43,10 @@ public class PingGenerator extends FrameGenerator public void generatePing(ByteBufferPool.Lease lease, byte[] payload, boolean reply) { - if (payload.length != 8) + if (payload.length != PingFrame.PING_LENGTH) throw new IllegalArgumentException("Invalid payload length: " + payload.length); - ByteBuffer header = generateHeader(lease, FrameType.PING, 8, reply ? Flags.ACK : Flags.NONE, 0); + ByteBuffer header = generateHeader(lease, FrameType.PING, PingFrame.PING_LENGTH, reply ? Flags.ACK : Flags.NONE, 0); header.put(payload); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java index 7591ae472ff..b3e85aeab48 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -109,4 +109,37 @@ public class PingGenerateParseTest Assert.assertArrayEquals(payload, frame.getPayload()); Assert.assertTrue(frame.isReply()); } + + @Test + public void testPayloadAsLong() throws Exception + { + PingGenerator generator = new PingGenerator(new HeaderGenerator()); + + final List frames = new ArrayList<>(); + Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + { + @Override + public void onPing(PingFrame frame) + { + frames.add(frame); + } + }, 4096, 8192); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + PingFrame ping = new PingFrame(System.nanoTime(), true); + generator.generate(lease, ping); + + for (ByteBuffer buffer : lease.getByteBuffers()) + { + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + + Assert.assertEquals(1, frames.size()); + PingFrame pong = frames.get(0); + Assert.assertEquals(ping.getPayloadAsLong(), pong.getPayloadAsLong()); + Assert.assertTrue(pong.isReply()); + } }